mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (90 commits) mfd: Push byte swaps out of wm8994 bulk read path mfd: Rename ab8500 gpadc header mfd: Constify WM8994 write path mfd: Push byte swap out of WM8994 bulk I/O mfd: Avoid copying data in WM8994 I2C write mfd: Remove copy from WM831x I2C write function mfd: Staticise WM8994 PM ops regulator: Add a subdriver for TI TPS6105x regulator portions v2 mfd: Add a core driver for TI TPS61050/TPS61052 chips v2 gpio: Add Tunnel Creek support to sch_gpio mfd: Add Tunnel Creek support to lpc_sch pci_ids: Add Intel Tunnel Creek LPC Bridge device ID. regulator: MAX8997/8966 support mfd: Add WM8994 bulk register write operation mfd: Append additional read write on 88pm860x mfd: Adopt mfd_data in 88pm860x input driver mfd: Adopt mfd_data in 88pm860x regulator mfd: Adopt mfd_data in 88pm860x led mfd: Adopt mfd_data in 88pm860x backlight mfd: Fix MAX8997 Kconfig entry typos ...
This commit is contained in:
commit
a6a1d6485e
45
Documentation/hwmon/twl4030-madc-hwmon
Normal file
45
Documentation/hwmon/twl4030-madc-hwmon
Normal file
@ -0,0 +1,45 @@
|
||||
Kernel driver twl4030-madc
|
||||
=========================
|
||||
|
||||
Supported chips:
|
||||
* Texas Instruments TWL4030
|
||||
Prefix: 'twl4030-madc'
|
||||
|
||||
|
||||
Authors:
|
||||
J Keerthy <j-keerthy@ti.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The Texas Instruments TWL4030 is a Power Management and Audio Circuit. Among
|
||||
other things it contains a 10-bit A/D converter MADC. The converter has 16
|
||||
channels which can be used in different modes.
|
||||
|
||||
|
||||
See this table for the meaning of the different channels
|
||||
|
||||
Channel Signal
|
||||
------------------------------------------
|
||||
0 Battery type(BTYPE)
|
||||
1 BCI: Battery temperature (BTEMP)
|
||||
2 GP analog input
|
||||
3 GP analog input
|
||||
4 GP analog input
|
||||
5 GP analog input
|
||||
6 GP analog input
|
||||
7 GP analog input
|
||||
8 BCI: VBUS voltage(VBUS)
|
||||
9 Backup Battery voltage (VBKP)
|
||||
10 BCI: Battery charger current (ICHG)
|
||||
11 BCI: Battery charger voltage (VCHG)
|
||||
12 BCI: Main battery voltage (VBAT)
|
||||
13 Reserved
|
||||
14 Reserved
|
||||
15 VRUSB Supply/Speaker left/Speaker right polarization level
|
||||
|
||||
|
||||
The Sysfs nodes will represent the voltage in the units of mV,
|
||||
the temperature channel shows the converted temperature in
|
||||
degree celcius. The Battery charging current channel represents
|
||||
battery charging current in mA.
|
@ -232,10 +232,13 @@ static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = {
|
||||
};
|
||||
|
||||
/* MC13783 */
|
||||
static struct mc13xxx_platform_data mc13783_pdata __initdata = {
|
||||
.regulators = mx27_3ds_regulators,
|
||||
.num_regulators = ARRAY_SIZE(mx27_3ds_regulators),
|
||||
.flags = MC13XXX_USE_REGULATOR,
|
||||
static struct mc13xxx_platform_data mc13783_pdata = {
|
||||
.regulators = {
|
||||
.regulators = mx27_3ds_regulators,
|
||||
.num_regulators = ARRAY_SIZE(mx27_3ds_regulators),
|
||||
|
||||
},
|
||||
.flags = MC13783_USE_REGULATOR,
|
||||
};
|
||||
|
||||
/* SPI */
|
||||
|
@ -263,10 +263,12 @@ static struct mc13xxx_regulator_init_data pcm038_regulators[] = {
|
||||
};
|
||||
|
||||
static struct mc13xxx_platform_data pcm038_pmic = {
|
||||
.regulators = pcm038_regulators,
|
||||
.num_regulators = ARRAY_SIZE(pcm038_regulators),
|
||||
.flags = MC13XXX_USE_ADC | MC13XXX_USE_REGULATOR |
|
||||
MC13XXX_USE_TOUCHSCREEN,
|
||||
.regulators = {
|
||||
.regulators = pcm038_regulators,
|
||||
.num_regulators = ARRAY_SIZE(pcm038_regulators),
|
||||
},
|
||||
.flags = MC13783_USE_ADC | MC13783_USE_REGULATOR |
|
||||
MC13783_USE_TOUCHSCREEN,
|
||||
};
|
||||
|
||||
static struct spi_board_info pcm038_spi_board_info[] __initdata = {
|
||||
|
@ -488,10 +488,12 @@ static struct mc13xxx_regulator_init_data mx31_3ds_regulators[] = {
|
||||
};
|
||||
|
||||
/* MC13783 */
|
||||
static struct mc13xxx_platform_data mc13783_pdata __initdata = {
|
||||
.regulators = mx31_3ds_regulators,
|
||||
.num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
|
||||
.flags = MC13XXX_USE_REGULATOR | MC13XXX_USE_TOUCHSCREEN
|
||||
static struct mc13xxx_platform_data mc13783_pdata = {
|
||||
.regulators = {
|
||||
.regulators = mx31_3ds_regulators,
|
||||
.num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
|
||||
},
|
||||
.flags = MC13783_USE_REGULATOR | MC13783_USE_TOUCHSCREEN,
|
||||
};
|
||||
|
||||
/* SPI */
|
||||
|
@ -268,8 +268,10 @@ static struct mc13783_leds_platform_data moboard_leds = {
|
||||
};
|
||||
|
||||
static struct mc13xxx_platform_data moboard_pmic = {
|
||||
.regulators = moboard_regulators,
|
||||
.num_regulators = ARRAY_SIZE(moboard_regulators),
|
||||
.regulators = {
|
||||
.regulators = moboard_regulators,
|
||||
.num_regulators = ARRAY_SIZE(moboard_regulators),
|
||||
},
|
||||
.leds = &moboard_leds,
|
||||
.flags = MC13XXX_USE_REGULATOR | MC13XXX_USE_RTC |
|
||||
MC13XXX_USE_ADC | MC13XXX_USE_LED,
|
||||
|
@ -550,6 +550,12 @@ static struct regulator_init_data sdp4430_vusb = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct regulator_init_data sdp4430_clk32kg = {
|
||||
.constraints = {
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
};
|
||||
|
||||
static struct twl4030_platform_data sdp4430_twldata = {
|
||||
.irq_base = TWL6030_IRQ_BASE,
|
||||
.irq_end = TWL6030_IRQ_END,
|
||||
@ -565,6 +571,7 @@ static struct twl4030_platform_data sdp4430_twldata = {
|
||||
.vaux1 = &sdp4430_vaux1,
|
||||
.vaux2 = &sdp4430_vaux2,
|
||||
.vaux3 = &sdp4430_vaux3,
|
||||
.clk32kg = &sdp4430_clk32kg,
|
||||
.usb = &omap4_usbphy_data
|
||||
};
|
||||
|
||||
|
@ -411,6 +411,12 @@ static struct regulator_init_data omap4_panda_vusb = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct regulator_init_data omap4_panda_clk32kg = {
|
||||
.constraints = {
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
};
|
||||
|
||||
static struct twl4030_platform_data omap4_panda_twldata = {
|
||||
.irq_base = TWL6030_IRQ_BASE,
|
||||
.irq_end = TWL6030_IRQ_END,
|
||||
@ -426,6 +432,7 @@ static struct twl4030_platform_data omap4_panda_twldata = {
|
||||
.vaux1 = &omap4_panda_vaux1,
|
||||
.vaux2 = &omap4_panda_vaux2,
|
||||
.vaux3 = &omap4_panda_vaux3,
|
||||
.clk32kg = &omap4_panda_clk32kg,
|
||||
.usb = &omap4_usbphy_data,
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/olpc.h>
|
||||
@ -56,25 +57,24 @@ static void xo1_power_off(void)
|
||||
static int __devinit olpc_xo1_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
int err;
|
||||
|
||||
/* don't run on non-XOs */
|
||||
if (!machine_is_olpc())
|
||||
return -ENODEV;
|
||||
|
||||
err = mfd_cell_enable(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "can't fetch device resource info\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!request_region(res->start, resource_size(res), DRV_NAME)) {
|
||||
dev_err(&pdev->dev, "can't request region\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (strcmp(pdev->name, "cs5535-pms") == 0)
|
||||
if (strcmp(pdev->name, "olpc-xo1-pms") == 0)
|
||||
pms_base = res->start;
|
||||
else if (strcmp(pdev->name, "cs5535-acpi") == 0)
|
||||
else if (strcmp(pdev->name, "olpc-xo1-ac-acpi") == 0)
|
||||
acpi_base = res->start;
|
||||
|
||||
/* If we have both addresses, we can override the poweroff hook */
|
||||
@ -88,14 +88,11 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev)
|
||||
|
||||
static int __devexit olpc_xo1_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
mfd_cell_disable(pdev);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
release_region(r->start, resource_size(r));
|
||||
|
||||
if (strcmp(pdev->name, "cs5535-pms") == 0)
|
||||
if (strcmp(pdev->name, "olpc-xo1-pms") == 0)
|
||||
pms_base = 0;
|
||||
else if (strcmp(pdev->name, "cs5535-acpi") == 0)
|
||||
else if (strcmp(pdev->name, "olpc-xo1-acpi") == 0)
|
||||
acpi_base = 0;
|
||||
|
||||
pm_power_off = NULL;
|
||||
@ -104,7 +101,7 @@ static int __devexit olpc_xo1_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver cs5535_pms_drv = {
|
||||
.driver = {
|
||||
.name = "cs5535-pms",
|
||||
.name = "olpc-xo1-pms",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = olpc_xo1_probe,
|
||||
@ -113,7 +110,7 @@ static struct platform_driver cs5535_pms_drv = {
|
||||
|
||||
static struct platform_driver cs5535_acpi_drv = {
|
||||
.driver = {
|
||||
.name = "cs5535-acpi",
|
||||
.name = "olpc-xo1-acpi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = olpc_xo1_probe,
|
||||
@ -124,26 +121,27 @@ static int __init olpc_xo1_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = platform_driver_register(&cs5535_pms_drv);
|
||||
r = mfd_shared_platform_driver_register(&cs5535_pms_drv, "cs5535-pms");
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = platform_driver_register(&cs5535_acpi_drv);
|
||||
r = mfd_shared_platform_driver_register(&cs5535_acpi_drv,
|
||||
"cs5535-acpi");
|
||||
if (r)
|
||||
platform_driver_unregister(&cs5535_pms_drv);
|
||||
mfd_shared_platform_driver_unregister(&cs5535_pms_drv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit olpc_xo1_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&cs5535_acpi_drv);
|
||||
platform_driver_unregister(&cs5535_pms_drv);
|
||||
mfd_shared_platform_driver_unregister(&cs5535_acpi_drv);
|
||||
mfd_shared_platform_driver_unregister(&cs5535_pms_drv);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:olpc-xo1");
|
||||
MODULE_ALIAS("platform:cs5535-pms");
|
||||
|
||||
module_init(olpc_xo1_init);
|
||||
module_exit(olpc_xo1_exit);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/timb_dma.h>
|
||||
@ -684,7 +685,7 @@ static irqreturn_t td_irq(int irq, void *devid)
|
||||
|
||||
static int __devinit td_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timb_dma_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct timb_dma *td;
|
||||
struct resource *iomem;
|
||||
int irq;
|
||||
|
@ -100,18 +100,21 @@ config GPIO_VR41XX
|
||||
Say yes here to support the NEC VR4100 series General-purpose I/O Uint
|
||||
|
||||
config GPIO_SCH
|
||||
tristate "Intel SCH GPIO"
|
||||
tristate "Intel SCH/TunnelCreek GPIO"
|
||||
depends on GPIOLIB && PCI && X86
|
||||
select MFD_CORE
|
||||
select LPC_SCH
|
||||
help
|
||||
Say yes here to support GPIO interface on Intel Poulsbo SCH.
|
||||
Say yes here to support GPIO interface on Intel Poulsbo SCH
|
||||
or Intel Tunnel Creek processor.
|
||||
The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
|
||||
powered by the core power rail and are turned off during sleep
|
||||
modes (S3 and higher). The remaining four GPIOs are powered by
|
||||
the Intel SCH suspend power supply. These GPIOs remain
|
||||
active during S3. The suspend powered GPIOs can be used to wake the
|
||||
system from the Suspend-to-RAM state.
|
||||
The Intel Tunnel Creek processor has 5 GPIOs powered by the
|
||||
core power rail and 9 from suspend power supply.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sch-gpio.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
@ -149,7 +150,7 @@ static int __devinit ttl_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
pdata = mfd_get_data(pdev);
|
||||
if (!pdata) {
|
||||
dev_err(dev, "no platform data\n");
|
||||
ret = -ENXIO;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mfd/rdc321x.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct rdc321x_gpio {
|
||||
@ -135,7 +136,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
|
||||
struct rdc321x_gpio *rdc321x_gpio_dev;
|
||||
struct rdc321x_gpio_pdata *pdata;
|
||||
|
||||
pdata = platform_get_drvdata(pdev);
|
||||
pdata = mfd_get_data(pdev);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data supplied\n");
|
||||
return -ENODEV;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci_ids.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
|
||||
@ -187,7 +188,11 @@ static struct gpio_chip sch_gpio_resume = {
|
||||
static int __devinit sch_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
int err;
|
||||
int err, id;
|
||||
|
||||
id = pdev->id;
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res)
|
||||
@ -198,12 +203,40 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
gpio_ba = res->start;
|
||||
|
||||
sch_gpio_core.base = 0;
|
||||
sch_gpio_core.ngpio = 10;
|
||||
sch_gpio_core.dev = &pdev->dev;
|
||||
switch (id) {
|
||||
case PCI_DEVICE_ID_INTEL_SCH_LPC:
|
||||
sch_gpio_core.base = 0;
|
||||
sch_gpio_core.ngpio = 10;
|
||||
|
||||
sch_gpio_resume.base = 10;
|
||||
sch_gpio_resume.ngpio = 4;
|
||||
sch_gpio_resume.base = 10;
|
||||
sch_gpio_resume.ngpio = 4;
|
||||
|
||||
/*
|
||||
* GPIO[6:0] enabled by default
|
||||
* GPIO7 is configured by the CMC as SLPIOVR
|
||||
* Enable GPIO[9:8] core powered gpios explicitly
|
||||
*/
|
||||
outb(0x3, gpio_ba + CGEN + 1);
|
||||
/*
|
||||
* SUS_GPIO[2:0] enabled by default
|
||||
* Enable SUS_GPIO3 resume powered gpio explicitly
|
||||
*/
|
||||
outb(0x8, gpio_ba + RGEN);
|
||||
break;
|
||||
|
||||
case PCI_DEVICE_ID_INTEL_ITC_LPC:
|
||||
sch_gpio_core.base = 0;
|
||||
sch_gpio_core.ngpio = 5;
|
||||
|
||||
sch_gpio_resume.base = 5;
|
||||
sch_gpio_resume.ngpio = 9;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
sch_gpio_core.dev = &pdev->dev;
|
||||
sch_gpio_resume.dev = &pdev->dev;
|
||||
|
||||
err = gpiochip_add(&sch_gpio_core);
|
||||
@ -214,18 +247,6 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
|
||||
if (err < 0)
|
||||
goto err_sch_gpio_resume;
|
||||
|
||||
/*
|
||||
* GPIO[6:0] enabled by default
|
||||
* GPIO7 is configured by the CMC as SLPIOVR
|
||||
* Enable GPIO[9:8] core powered gpios explicitly
|
||||
*/
|
||||
outb(0x3, gpio_ba + CGEN + 1);
|
||||
/*
|
||||
* SUS_GPIO[2:0] enabled by default
|
||||
* Enable SUS_GPIO3 resume powered gpio explicitly
|
||||
*/
|
||||
outb(0x8, gpio_ba + RGEN);
|
||||
|
||||
return 0;
|
||||
|
||||
err_sch_gpio_resume:
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/timb_gpio.h>
|
||||
@ -228,7 +229,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
|
||||
struct gpio_chip *gc;
|
||||
struct timbgpio *tgpio;
|
||||
struct resource *iomem;
|
||||
struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timbgpio_platform_data *pdata = mfd_get_data(pdev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (!pdata || pdata->nr_pins > 32) {
|
||||
@ -319,14 +320,13 @@ err_mem:
|
||||
static int __devexit timbgpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timbgpio *tgpio = platform_get_drvdata(pdev);
|
||||
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (irq >= 0 && tgpio->irq_base > 0) {
|
||||
int i;
|
||||
for (i = 0; i < pdata->nr_pins; i++) {
|
||||
for (i = 0; i < tgpio->gpio.ngpio; i++) {
|
||||
set_irq_chip(tgpio->irq_base + i, NULL);
|
||||
set_irq_chip_data(tgpio->irq_base + i, NULL);
|
||||
}
|
||||
|
@ -1047,6 +1047,16 @@ config SENSORS_TMP421
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tmp421.
|
||||
|
||||
config SENSORS_TWL4030_MADC
|
||||
tristate "Texas Instruments TWL4030 MADC Hwmon"
|
||||
depends on TWL4030_MADC
|
||||
help
|
||||
If you say yes here you get hwmon support for triton
|
||||
TWL4030-MADC.
|
||||
|
||||
This driver can also be built as a module. If so it will be called
|
||||
twl4030-madc-hwmon.
|
||||
|
||||
config SENSORS_VIA_CPUTEMP
|
||||
tristate "VIA CPU temperature sensor"
|
||||
depends on X86
|
||||
|
@ -104,6 +104,7 @@ obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
|
||||
obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
|
||||
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
|
||||
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
|
||||
obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
|
||||
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
|
||||
obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
|
||||
|
@ -32,7 +32,7 @@ struct jz4740_hwmon {
|
||||
|
||||
int irq;
|
||||
|
||||
struct mfd_cell *cell;
|
||||
const struct mfd_cell *cell;
|
||||
struct device *hwmon;
|
||||
|
||||
struct completion read_completion;
|
||||
@ -112,7 +112,7 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hwmon->cell = pdev->dev.platform_data;
|
||||
hwmon->cell = mfd_get_cell(pdev);
|
||||
|
||||
hwmon->irq = platform_get_irq(pdev, 0);
|
||||
if (hwmon->irq < 0) {
|
||||
|
157
drivers/hwmon/twl4030-madc-hwmon.c
Normal file
157
drivers/hwmon/twl4030-madc-hwmon.c
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
*
|
||||
* TWL4030 MADC Hwmon driver-This driver monitors the real time
|
||||
* conversion of analog signals like battery temperature,
|
||||
* battery type, battery level etc. User can ask for the conversion on a
|
||||
* particular channel using the sysfs nodes.
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* J Keerthy <j-keerthy@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c/twl4030-madc.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* sysfs hook function
|
||||
*/
|
||||
static ssize_t madc_read(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct twl4030_madc_request req;
|
||||
long val;
|
||||
|
||||
req.channels = (1 << attr->index);
|
||||
req.method = TWL4030_MADC_SW2;
|
||||
req.func_cb = NULL;
|
||||
val = twl4030_madc_conversion(&req);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
return sprintf(buf, "%d\n", req.rbuf[attr->index]);
|
||||
}
|
||||
|
||||
/* sysfs nodes to read individual channels from user side */
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, madc_read, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, madc_read, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, madc_read, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, madc_read, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, madc_read, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, madc_read, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, madc_read, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, madc_read, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, madc_read, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, madc_read, NULL, 9);
|
||||
static SENSOR_DEVICE_ATTR(curr10_input, S_IRUGO, madc_read, NULL, 10);
|
||||
static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, madc_read, NULL, 11);
|
||||
static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, madc_read, NULL, 12);
|
||||
static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, madc_read, NULL, 15);
|
||||
|
||||
static struct attribute *twl4030_madc_attributes[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in9_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr10_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in15_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group twl4030_madc_group = {
|
||||
.attrs = twl4030_madc_attributes,
|
||||
};
|
||||
|
||||
static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
int status;
|
||||
struct device *hwmon;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group);
|
||||
if (ret)
|
||||
goto err_sysfs;
|
||||
hwmon = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(hwmon)) {
|
||||
dev_err(&pdev->dev, "hwmon_device_register failed.\n");
|
||||
status = PTR_ERR(hwmon);
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group);
|
||||
err_sysfs:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit twl4030_madc_hwmon_remove(struct platform_device *pdev)
|
||||
{
|
||||
hwmon_device_unregister(&pdev->dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl4030_madc_hwmon_driver = {
|
||||
.probe = twl4030_madc_hwmon_probe,
|
||||
.remove = __exit_p(twl4030_madc_hwmon_remove),
|
||||
.driver = {
|
||||
.name = "twl4030_madc_hwmon",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init twl4030_madc_hwmon_init(void)
|
||||
{
|
||||
return platform_driver_register(&twl4030_madc_hwmon_driver);
|
||||
}
|
||||
|
||||
module_init(twl4030_madc_hwmon_init);
|
||||
|
||||
static void __exit twl4030_madc_hwmon_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&twl4030_madc_hwmon_driver);
|
||||
}
|
||||
|
||||
module_exit(twl4030_madc_hwmon_exit);
|
||||
|
||||
MODULE_DESCRIPTION("TWL4030 ADC Hwmon driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("J Keerthy");
|
||||
MODULE_ALIAS("twl4030_madc_hwmon");
|
@ -49,6 +49,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
@ -305,7 +306,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
pdata = mfd_get_data(pdev);
|
||||
if (pdata) {
|
||||
i2c->regstep = pdata->regstep;
|
||||
i2c->clock_khz = pdata->clock_khz;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
@ -704,7 +705,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
goto resource_missing;
|
||||
|
||||
pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
|
||||
pdata = mfd_get_data(pdev);
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -74,7 +74,7 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
|
||||
info->chip = chip;
|
||||
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
|
||||
info->dev = &pdev->dev;
|
||||
info->irq = irq + chip->irq_base;
|
||||
info->irq = irq;
|
||||
|
||||
info->idev = input_allocate_device();
|
||||
if (!info->idev) {
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/mfd/twl4030-codec.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -196,7 +197,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
|
||||
|
||||
static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
|
||||
struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev);
|
||||
struct vibra_info *info;
|
||||
int ret;
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
#define LED_PWM_SHIFT (3)
|
||||
@ -118,7 +119,8 @@ static void pm860x_led_work(struct work_struct *work)
|
||||
|
||||
struct pm860x_led *led;
|
||||
struct pm860x_chip *chip;
|
||||
int mask;
|
||||
unsigned char buf[3];
|
||||
int mask, ret;
|
||||
|
||||
led = container_of(work, struct pm860x_led, work);
|
||||
chip = led->chip;
|
||||
@ -128,16 +130,27 @@ static void pm860x_led_work(struct work_struct *work)
|
||||
pm860x_set_bits(led->i2c, __led_off(led->port),
|
||||
LED_CURRENT_MASK, led->iset);
|
||||
}
|
||||
pm860x_set_bits(led->i2c, __blink_off(led->port),
|
||||
LED_BLINK_MASK, LED_ON_CONTINUOUS);
|
||||
mask = __blink_ctl_mask(led->port);
|
||||
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask);
|
||||
} else if (led->brightness == 0) {
|
||||
pm860x_set_bits(led->i2c, __led_off(led->port),
|
||||
LED_CURRENT_MASK, 0);
|
||||
mask = __blink_ctl_mask(led->port);
|
||||
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
|
||||
}
|
||||
pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK,
|
||||
led->brightness);
|
||||
|
||||
if (led->brightness == 0) {
|
||||
pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf);
|
||||
ret = buf[0] & LED_PWM_MASK;
|
||||
ret |= buf[1] & LED_PWM_MASK;
|
||||
ret |= buf[2] & LED_PWM_MASK;
|
||||
if (ret == 0) {
|
||||
/* unset current since no led is lighting */
|
||||
pm860x_set_bits(led->i2c, __led_off(led->port),
|
||||
LED_CURRENT_MASK, 0);
|
||||
mask = __blink_ctl_mask(led->port);
|
||||
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
|
||||
}
|
||||
}
|
||||
led->current_brightness = led->brightness;
|
||||
dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
|
||||
__led_off(led->port), led->brightness);
|
||||
@ -153,31 +166,12 @@ static void pm860x_led_set(struct led_classdev *cdev,
|
||||
schedule_work(&data->work);
|
||||
}
|
||||
|
||||
static int __check_device(struct pm860x_led_pdata *pdata, char *name)
|
||||
{
|
||||
struct pm860x_led_pdata *p = pdata;
|
||||
int ret = -EINVAL;
|
||||
|
||||
while (p && p->id) {
|
||||
if ((p->id != PM8606_ID_LED) || (p->flags < 0))
|
||||
break;
|
||||
|
||||
if (!strncmp(name, pm860x_led_name[p->flags],
|
||||
MFD_NAME_SIZE)) {
|
||||
ret = (int)p->flags;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pm860x_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_platform_data *pm860x_pdata;
|
||||
struct pm860x_led_pdata *pdata;
|
||||
struct pm860x_led *data;
|
||||
struct mfd_cell *cell;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
@ -187,10 +181,11 @@ static int pm860x_led_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdev->dev.parent->platform_data) {
|
||||
pm860x_pdata = pdev->dev.parent->platform_data;
|
||||
pdata = pm860x_pdata->led;
|
||||
} else {
|
||||
cell = pdev->dev.platform_data;
|
||||
if (cell == NULL)
|
||||
return -ENODEV;
|
||||
pdata = cell->mfd_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "No platform data!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -198,12 +193,12 @@ static int pm860x_led_probe(struct platform_device *pdev)
|
||||
data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
strncpy(data->name, res->name, MFD_NAME_SIZE);
|
||||
strncpy(data->name, res->name, MFD_NAME_SIZE - 1);
|
||||
dev_set_drvdata(&pdev->dev, data);
|
||||
data->chip = chip;
|
||||
data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
|
||||
data->iset = pdata->iset;
|
||||
data->port = __check_device(pdata, data->name);
|
||||
data->port = pdata->flags;
|
||||
if (data->port < 0) {
|
||||
dev_err(&pdev->dev, "check device failed\n");
|
||||
kfree(data);
|
||||
@ -221,6 +216,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
pm860x_led_set(&data->cdev, 0);
|
||||
return 0;
|
||||
out:
|
||||
kfree(data);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mfd/mc13783.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct mc13783_led {
|
||||
@ -183,7 +184,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
|
||||
|
||||
static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
|
||||
int ret = 0;
|
||||
int reg = 0;
|
||||
@ -264,7 +265,7 @@ out:
|
||||
|
||||
static int __devinit mc13783_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_led_platform_data *led_cur;
|
||||
struct mc13783_led *led, *led_dat;
|
||||
int ret, i;
|
||||
@ -351,7 +352,7 @@ err_free:
|
||||
|
||||
static int __devexit mc13783_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_led *led = platform_get_drvdata(pdev);
|
||||
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
|
||||
int i;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
@ -148,7 +149,7 @@ static const struct v4l2_file_operations timbradio_fops = {
|
||||
|
||||
static int __devinit timbradio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timb_radio_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct timbradio *tr;
|
||||
int err;
|
||||
|
||||
|
@ -2138,7 +2138,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
|
||||
|
||||
static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wl1273_core **core = pdev->dev.platform_data;
|
||||
struct wl1273_core **core = mfd_get_data(pdev);
|
||||
struct wl1273_device *radio;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
int r = 0;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
@ -790,7 +791,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct timblogiw *lw = NULL;
|
||||
struct timb_video_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timb_video_platform_data *pdata = mfd_get_data(pdev);
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data\n");
|
||||
|
@ -17,229 +17,137 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
#define INT_STATUS_NUM 3
|
||||
|
||||
char pm860x_backlight_name[][MFD_NAME_SIZE] = {
|
||||
"backlight-0",
|
||||
"backlight-1",
|
||||
"backlight-2",
|
||||
};
|
||||
EXPORT_SYMBOL(pm860x_backlight_name);
|
||||
|
||||
char pm860x_led_name[][MFD_NAME_SIZE] = {
|
||||
"led0-red",
|
||||
"led0-green",
|
||||
"led0-blue",
|
||||
"led1-red",
|
||||
"led1-green",
|
||||
"led1-blue",
|
||||
};
|
||||
EXPORT_SYMBOL(pm860x_led_name);
|
||||
|
||||
#define PM8606_BACKLIGHT_RESOURCE(_i, _x) \
|
||||
{ \
|
||||
.name = pm860x_backlight_name[_i], \
|
||||
.start = PM8606_##_x, \
|
||||
.end = PM8606_##_x, \
|
||||
.flags = IORESOURCE_IO, \
|
||||
}
|
||||
|
||||
static struct resource backlight_resources[] = {
|
||||
PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A),
|
||||
PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A),
|
||||
PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A),
|
||||
static struct resource bk_resources[] __initdata = {
|
||||
{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
|
||||
{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
|
||||
{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
|
||||
};
|
||||
|
||||
#define PM8606_BACKLIGHT_DEVS(_i) \
|
||||
{ \
|
||||
.name = "88pm860x-backlight", \
|
||||
.num_resources = 1, \
|
||||
.resources = &backlight_resources[_i], \
|
||||
.id = _i, \
|
||||
}
|
||||
|
||||
static struct mfd_cell backlight_devs[] = {
|
||||
PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1),
|
||||
PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2),
|
||||
PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3),
|
||||
static struct resource led_resources[] __initdata = {
|
||||
{PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,},
|
||||
{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
|
||||
{PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,},
|
||||
{PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,},
|
||||
{PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,},
|
||||
{PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,},
|
||||
};
|
||||
|
||||
#define PM8606_LED_RESOURCE(_i, _x) \
|
||||
{ \
|
||||
.name = pm860x_led_name[_i], \
|
||||
.start = PM8606_##_x, \
|
||||
.end = PM8606_##_x, \
|
||||
.flags = IORESOURCE_IO, \
|
||||
}
|
||||
|
||||
static struct resource led_resources[] = {
|
||||
PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B),
|
||||
PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C),
|
||||
PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D),
|
||||
PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B),
|
||||
PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C),
|
||||
PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D),
|
||||
static struct resource regulator_resources[] __initdata = {
|
||||
{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
|
||||
{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
|
||||
{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,},
|
||||
{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
|
||||
};
|
||||
|
||||
#define PM8606_LED_DEVS(_i) \
|
||||
{ \
|
||||
.name = "88pm860x-led", \
|
||||
.num_resources = 1, \
|
||||
.resources = &led_resources[_i], \
|
||||
.id = _i, \
|
||||
}
|
||||
|
||||
static struct mfd_cell led_devs[] = {
|
||||
PM8606_LED_DEVS(PM8606_LED1_RED),
|
||||
PM8606_LED_DEVS(PM8606_LED1_GREEN),
|
||||
PM8606_LED_DEVS(PM8606_LED1_BLUE),
|
||||
PM8606_LED_DEVS(PM8606_LED2_RED),
|
||||
PM8606_LED_DEVS(PM8606_LED2_GREEN),
|
||||
PM8606_LED_DEVS(PM8606_LED2_BLUE),
|
||||
static struct resource touch_resources[] __initdata = {
|
||||
{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct resource touch_resources[] = {
|
||||
{
|
||||
.start = PM8607_IRQ_PEN,
|
||||
.end = PM8607_IRQ_PEN,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
static struct resource onkey_resources[] __initdata = {
|
||||
{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct mfd_cell touch_devs[] = {
|
||||
{
|
||||
.name = "88pm860x-touch",
|
||||
.num_resources = 1,
|
||||
.resources = &touch_resources[0],
|
||||
},
|
||||
static struct resource codec_resources[] __initdata = {
|
||||
/* Headset microphone insertion or removal */
|
||||
{PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,},
|
||||
/* Hook-switch press or release */
|
||||
{PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,},
|
||||
/* Headset insertion or removal */
|
||||
{PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
|
||||
/* Audio short */
|
||||
{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
#define PM8607_REG_RESOURCE(_start, _end) \
|
||||
{ \
|
||||
.start = PM8607_##_start, \
|
||||
.end = PM8607_##_end, \
|
||||
.flags = IORESOURCE_IO, \
|
||||
}
|
||||
static struct resource battery_resources[] __initdata = {
|
||||
{PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct resource power_supply_resources[] = {
|
||||
{
|
||||
.name = "88pm860x-power",
|
||||
.start = PM8607_IRQ_CHG,
|
||||
.end = PM8607_IRQ_CHG,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
static struct resource charger_resources[] __initdata = {
|
||||
{PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct mfd_cell bk_devs[] __initdata = {
|
||||
{"88pm860x-backlight", 0,},
|
||||
{"88pm860x-backlight", 1,},
|
||||
{"88pm860x-backlight", 2,},
|
||||
};
|
||||
|
||||
static struct mfd_cell led_devs[] __initdata = {
|
||||
{"88pm860x-led", 0,},
|
||||
{"88pm860x-led", 1,},
|
||||
{"88pm860x-led", 2,},
|
||||
{"88pm860x-led", 3,},
|
||||
{"88pm860x-led", 4,},
|
||||
{"88pm860x-led", 5,},
|
||||
};
|
||||
|
||||
static struct mfd_cell regulator_devs[] __initdata = {
|
||||
{"88pm860x-regulator", 0,},
|
||||
{"88pm860x-regulator", 1,},
|
||||
{"88pm860x-regulator", 2,},
|
||||
{"88pm860x-regulator", 3,},
|
||||
{"88pm860x-regulator", 4,},
|
||||
{"88pm860x-regulator", 5,},
|
||||
{"88pm860x-regulator", 6,},
|
||||
{"88pm860x-regulator", 7,},
|
||||
{"88pm860x-regulator", 8,},
|
||||
{"88pm860x-regulator", 9,},
|
||||
{"88pm860x-regulator", 10,},
|
||||
{"88pm860x-regulator", 11,},
|
||||
{"88pm860x-regulator", 12,},
|
||||
{"88pm860x-regulator", 13,},
|
||||
{"88pm860x-regulator", 14,},
|
||||
{"88pm860x-regulator", 15,},
|
||||
{"88pm860x-regulator", 16,},
|
||||
{"88pm860x-regulator", 17,},
|
||||
};
|
||||
|
||||
static struct mfd_cell touch_devs[] __initdata = {
|
||||
{"88pm860x-touch", -1,},
|
||||
};
|
||||
|
||||
static struct mfd_cell onkey_devs[] __initdata = {
|
||||
{"88pm860x-onkey", -1,},
|
||||
};
|
||||
|
||||
static struct mfd_cell codec_devs[] __initdata = {
|
||||
{"88pm860x-codec", -1,},
|
||||
};
|
||||
|
||||
static struct mfd_cell power_devs[] = {
|
||||
{
|
||||
.name = "88pm860x-power",
|
||||
.num_resources = 1,
|
||||
.resources = &power_supply_resources[0],
|
||||
.id = -1,
|
||||
},
|
||||
{"88pm860x-battery", -1,},
|
||||
{"88pm860x-charger", -1,},
|
||||
};
|
||||
|
||||
static struct resource onkey_resources[] = {
|
||||
{
|
||||
.name = "88pm860x-onkey",
|
||||
.start = PM8607_IRQ_ONKEY,
|
||||
.end = PM8607_IRQ_ONKEY,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell onkey_devs[] = {
|
||||
{
|
||||
.name = "88pm860x-onkey",
|
||||
.num_resources = 1,
|
||||
.resources = &onkey_resources[0],
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource codec_resources[] = {
|
||||
{
|
||||
/* Headset microphone insertion or removal */
|
||||
.name = "micin",
|
||||
.start = PM8607_IRQ_MICIN,
|
||||
.end = PM8607_IRQ_MICIN,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
/* Hook-switch press or release */
|
||||
.name = "hook",
|
||||
.start = PM8607_IRQ_HOOK,
|
||||
.end = PM8607_IRQ_HOOK,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
/* Headset insertion or removal */
|
||||
.name = "headset",
|
||||
.start = PM8607_IRQ_HEADSET,
|
||||
.end = PM8607_IRQ_HEADSET,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
/* Audio short */
|
||||
.name = "audio-short",
|
||||
.start = PM8607_IRQ_AUDIO_SHORT,
|
||||
.end = PM8607_IRQ_AUDIO_SHORT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell codec_devs[] = {
|
||||
{
|
||||
.name = "88pm860x-codec",
|
||||
.num_resources = ARRAY_SIZE(codec_resources),
|
||||
.resources = &codec_resources[0],
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource regulator_resources[] = {
|
||||
PM8607_REG_RESOURCE(BUCK1, BUCK1),
|
||||
PM8607_REG_RESOURCE(BUCK2, BUCK2),
|
||||
PM8607_REG_RESOURCE(BUCK3, BUCK3),
|
||||
PM8607_REG_RESOURCE(LDO1, LDO1),
|
||||
PM8607_REG_RESOURCE(LDO2, LDO2),
|
||||
PM8607_REG_RESOURCE(LDO3, LDO3),
|
||||
PM8607_REG_RESOURCE(LDO4, LDO4),
|
||||
PM8607_REG_RESOURCE(LDO5, LDO5),
|
||||
PM8607_REG_RESOURCE(LDO6, LDO6),
|
||||
PM8607_REG_RESOURCE(LDO7, LDO7),
|
||||
PM8607_REG_RESOURCE(LDO8, LDO8),
|
||||
PM8607_REG_RESOURCE(LDO9, LDO9),
|
||||
PM8607_REG_RESOURCE(LDO10, LDO10),
|
||||
PM8607_REG_RESOURCE(LDO12, LDO12),
|
||||
PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET),
|
||||
PM8607_REG_RESOURCE(LDO14, LDO14),
|
||||
};
|
||||
|
||||
#define PM8607_REG_DEVS(_id) \
|
||||
{ \
|
||||
.name = "88pm860x-regulator", \
|
||||
.num_resources = 1, \
|
||||
.resources = ®ulator_resources[PM8607_ID_##_id], \
|
||||
.id = PM8607_ID_##_id, \
|
||||
}
|
||||
|
||||
static struct mfd_cell regulator_devs[] = {
|
||||
PM8607_REG_DEVS(BUCK1),
|
||||
PM8607_REG_DEVS(BUCK2),
|
||||
PM8607_REG_DEVS(BUCK3),
|
||||
PM8607_REG_DEVS(LDO1),
|
||||
PM8607_REG_DEVS(LDO2),
|
||||
PM8607_REG_DEVS(LDO3),
|
||||
PM8607_REG_DEVS(LDO4),
|
||||
PM8607_REG_DEVS(LDO5),
|
||||
PM8607_REG_DEVS(LDO6),
|
||||
PM8607_REG_DEVS(LDO7),
|
||||
PM8607_REG_DEVS(LDO8),
|
||||
PM8607_REG_DEVS(LDO9),
|
||||
PM8607_REG_DEVS(LDO10),
|
||||
PM8607_REG_DEVS(LDO12),
|
||||
PM8607_REG_DEVS(LDO13),
|
||||
PM8607_REG_DEVS(LDO14),
|
||||
};
|
||||
static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
|
||||
static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
|
||||
static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
|
||||
static struct pm860x_touch_pdata touch_pdata;
|
||||
static struct pm860x_power_pdata power_pdata;
|
||||
|
||||
struct pm860x_irq_data {
|
||||
int reg;
|
||||
@ -595,37 +503,212 @@ static void device_irq_exit(struct pm860x_chip *chip)
|
||||
free_irq(chip->core_irq, chip);
|
||||
}
|
||||
|
||||
static void __devinit device_8606_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
static void __devinit device_bk_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
int i, j, id;
|
||||
|
||||
if ((pdata == NULL) || (pdata->backlight == NULL))
|
||||
return;
|
||||
|
||||
if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
|
||||
pdata->num_backlights = ARRAY_SIZE(bk_devs);
|
||||
|
||||
for (i = 0; i < pdata->num_backlights; i++) {
|
||||
memcpy(&bk_pdata[i], &pdata->backlight[i],
|
||||
sizeof(struct pm860x_backlight_pdata));
|
||||
bk_devs[i].mfd_data = &bk_pdata[i];
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
|
||||
id = bk_resources[j].start;
|
||||
if (bk_pdata[i].flags != id)
|
||||
continue;
|
||||
|
||||
bk_devs[i].num_resources = 1;
|
||||
bk_devs[i].resources = &bk_resources[j];
|
||||
ret = mfd_add_devices(chip->dev, 0,
|
||||
&bk_devs[i], 1,
|
||||
&bk_resources[j], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add "
|
||||
"backlight subdev\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __devinit device_led_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
int i, j, id;
|
||||
|
||||
if ((pdata == NULL) || (pdata->led == NULL))
|
||||
return;
|
||||
|
||||
if (pdata->num_leds > ARRAY_SIZE(led_devs))
|
||||
pdata->num_leds = ARRAY_SIZE(led_devs);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
memcpy(&led_pdata[i], &pdata->led[i],
|
||||
sizeof(struct pm860x_led_pdata));
|
||||
led_devs[i].mfd_data = &led_pdata[i];
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
|
||||
id = led_resources[j].start;
|
||||
if (led_pdata[i].flags != id)
|
||||
continue;
|
||||
|
||||
led_devs[i].num_resources = 1;
|
||||
led_devs[i].resources = &led_resources[j],
|
||||
ret = mfd_add_devices(chip->dev, 0,
|
||||
&led_devs[i], 1,
|
||||
&led_resources[j], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add "
|
||||
"led subdev\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __devinit device_regulator_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
struct regulator_init_data *initdata;
|
||||
int ret;
|
||||
int i, j;
|
||||
|
||||
if ((pdata == NULL) || (pdata->regulator == NULL))
|
||||
return;
|
||||
|
||||
if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
|
||||
pdata->num_regulators = ARRAY_SIZE(regulator_devs);
|
||||
|
||||
for (i = 0, j = -1; i < pdata->num_regulators; i++) {
|
||||
initdata = &pdata->regulator[i];
|
||||
if (strstr(initdata->constraints.name, "BUCK")) {
|
||||
sscanf(initdata->constraints.name, "BUCK%d", &j);
|
||||
/* BUCK1 ~ BUCK3 */
|
||||
if ((j < 1) || (j > 3)) {
|
||||
dev_err(chip->dev, "Failed to add constraint "
|
||||
"(%s)\n", initdata->constraints.name);
|
||||
goto out;
|
||||
}
|
||||
j = (j - 1) + PM8607_ID_BUCK1;
|
||||
}
|
||||
if (strstr(initdata->constraints.name, "LDO")) {
|
||||
sscanf(initdata->constraints.name, "LDO%d", &j);
|
||||
/* LDO1 ~ LDO15 */
|
||||
if ((j < 1) || (j > 15)) {
|
||||
dev_err(chip->dev, "Failed to add constraint "
|
||||
"(%s)\n", initdata->constraints.name);
|
||||
goto out;
|
||||
}
|
||||
j = (j - 1) + PM8607_ID_LDO1;
|
||||
}
|
||||
if (j == -1) {
|
||||
dev_err(chip->dev, "Failed to add constraint (%s)\n",
|
||||
initdata->constraints.name);
|
||||
goto out;
|
||||
}
|
||||
memcpy(®ulator_pdata[i], &pdata->regulator[i],
|
||||
sizeof(struct regulator_init_data));
|
||||
regulator_devs[i].mfd_data = ®ulator_pdata[i];
|
||||
regulator_devs[i].num_resources = 1;
|
||||
regulator_devs[i].resources = ®ulator_resources[j];
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1,
|
||||
®ulator_resources[j], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add regulator subdev\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void __devinit device_touch_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pdata && pdata->backlight) {
|
||||
ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0],
|
||||
ARRAY_SIZE(backlight_devs),
|
||||
&backlight_resources[0], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add backlight "
|
||||
"subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
}
|
||||
if ((pdata == NULL) || (pdata->touch == NULL))
|
||||
return;
|
||||
|
||||
if (pdata && pdata->led) {
|
||||
ret = mfd_add_devices(chip->dev, 0, &led_devs[0],
|
||||
ARRAY_SIZE(led_devs),
|
||||
&led_resources[0], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add led "
|
||||
"subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
}
|
||||
return;
|
||||
out_dev:
|
||||
mfd_remove_devices(chip->dev);
|
||||
device_irq_exit(chip);
|
||||
memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata));
|
||||
touch_devs[0].mfd_data = &touch_pdata;
|
||||
touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
|
||||
touch_devs[0].resources = &touch_resources[0];
|
||||
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
|
||||
ARRAY_SIZE(touch_devs), &touch_resources[0],
|
||||
chip->irq_base);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add touch subdev\n");
|
||||
}
|
||||
|
||||
static void __devinit device_power_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((pdata == NULL) || (pdata->power == NULL))
|
||||
return;
|
||||
|
||||
memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata));
|
||||
power_devs[0].mfd_data = &power_pdata;
|
||||
power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
|
||||
power_devs[0].resources = &battery_resources[0],
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
|
||||
&battery_resources[0], chip->irq_base);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add battery subdev\n");
|
||||
|
||||
power_devs[1].mfd_data = &power_pdata;
|
||||
power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
|
||||
power_devs[1].resources = &charger_resources[0],
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
|
||||
&charger_resources[0], chip->irq_base);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add charger subdev\n");
|
||||
}
|
||||
|
||||
static void __devinit device_onkey_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
|
||||
onkey_devs[0].resources = &onkey_resources[0],
|
||||
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
|
||||
ARRAY_SIZE(onkey_devs), &onkey_resources[0],
|
||||
chip->irq_base);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add onkey subdev\n");
|
||||
}
|
||||
|
||||
static void __devinit device_codec_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
|
||||
codec_devs[0].resources = &codec_resources[0],
|
||||
ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
|
||||
ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add codec subdev\n");
|
||||
}
|
||||
|
||||
static void __devinit device_8607_init(struct pm860x_chip *chip,
|
||||
@ -683,55 +766,11 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0],
|
||||
ARRAY_SIZE(regulator_devs),
|
||||
®ulator_resources[0], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add regulator subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
if (pdata && pdata->touch) {
|
||||
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
|
||||
ARRAY_SIZE(touch_devs),
|
||||
&touch_resources[0], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add touch "
|
||||
"subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata && pdata->power) {
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
|
||||
ARRAY_SIZE(power_devs),
|
||||
&power_supply_resources[0], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add power supply "
|
||||
"subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
|
||||
ARRAY_SIZE(onkey_devs),
|
||||
&onkey_resources[0], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add onkey subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
|
||||
ARRAY_SIZE(codec_devs),
|
||||
&codec_resources[0], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add codec subdev\n");
|
||||
goto out_dev;
|
||||
}
|
||||
return;
|
||||
out_dev:
|
||||
mfd_remove_devices(chip->dev);
|
||||
device_irq_exit(chip);
|
||||
device_regulator_init(chip, i2c, pdata);
|
||||
device_onkey_init(chip, i2c, pdata);
|
||||
device_touch_init(chip, i2c, pdata);
|
||||
device_power_init(chip, i2c, pdata);
|
||||
device_codec_init(chip, i2c, pdata);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
@ -743,7 +782,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
|
||||
|
||||
switch (chip->id) {
|
||||
case CHIP_PM8606:
|
||||
device_8606_init(chip, chip->client, pdata);
|
||||
device_bk_init(chip, chip->client, pdata);
|
||||
device_led_init(chip, chip->client, pdata);
|
||||
break;
|
||||
case CHIP_PM8607:
|
||||
device_8607_init(chip, chip->client, pdata);
|
||||
@ -753,7 +793,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
|
||||
if (chip->companion) {
|
||||
switch (chip->id) {
|
||||
case CHIP_PM8607:
|
||||
device_8606_init(chip, chip->companion, pdata);
|
||||
device_bk_init(chip, chip->companion, pdata);
|
||||
device_led_init(chip, chip->companion, pdata);
|
||||
break;
|
||||
case CHIP_PM8606:
|
||||
device_8607_init(chip, chip->companion, pdata);
|
||||
|
@ -126,6 +126,109 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(pm860x_set_bits);
|
||||
|
||||
int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
|
||||
{
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
|
||||
unsigned char zero = 0;
|
||||
unsigned char data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->io_lock);
|
||||
pm860x_write_device(i2c, 0xFA, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFB, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFF, 0, &zero);
|
||||
ret = pm860x_read_device(i2c, reg, 1, &data);
|
||||
if (ret >= 0)
|
||||
ret = (int)data;
|
||||
pm860x_write_device(i2c, 0xFE, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFC, 0, &zero);
|
||||
mutex_unlock(&chip->io_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pm860x_page_reg_read);
|
||||
|
||||
int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
|
||||
unsigned char data)
|
||||
{
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
|
||||
unsigned char zero;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->io_lock);
|
||||
pm860x_write_device(i2c, 0xFA, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFB, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFF, 0, &zero);
|
||||
ret = pm860x_write_device(i2c, reg, 1, &data);
|
||||
pm860x_write_device(i2c, 0xFE, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFC, 0, &zero);
|
||||
mutex_unlock(&chip->io_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pm860x_page_reg_write);
|
||||
|
||||
int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
|
||||
int count, unsigned char *buf)
|
||||
{
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
|
||||
unsigned char zero = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->io_lock);
|
||||
pm860x_write_device(i2c, 0xFA, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFB, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFF, 0, &zero);
|
||||
ret = pm860x_read_device(i2c, reg, count, buf);
|
||||
pm860x_write_device(i2c, 0xFE, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFC, 0, &zero);
|
||||
mutex_unlock(&chip->io_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pm860x_page_bulk_read);
|
||||
|
||||
int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
|
||||
int count, unsigned char *buf)
|
||||
{
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
|
||||
unsigned char zero = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->io_lock);
|
||||
pm860x_write_device(i2c, 0xFA, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFB, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFF, 0, &zero);
|
||||
ret = pm860x_write_device(i2c, reg, count, buf);
|
||||
pm860x_write_device(i2c, 0xFE, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFC, 0, &zero);
|
||||
mutex_unlock(&chip->io_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pm860x_page_bulk_write);
|
||||
|
||||
int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
|
||||
unsigned char mask, unsigned char data)
|
||||
{
|
||||
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
|
||||
unsigned char zero;
|
||||
unsigned char value;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->io_lock);
|
||||
pm860x_write_device(i2c, 0xFA, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFB, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFF, 0, &zero);
|
||||
ret = pm860x_read_device(i2c, reg, 1, &value);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
value &= ~mask;
|
||||
value |= data;
|
||||
ret = pm860x_write_device(i2c, reg, 1, &value);
|
||||
out:
|
||||
pm860x_write_device(i2c, 0xFE, 0, &zero);
|
||||
pm860x_write_device(i2c, 0xFC, 0, &zero);
|
||||
mutex_unlock(&chip->io_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pm860x_page_set_bits);
|
||||
|
||||
static const struct i2c_device_id pm860x_id_table[] = {
|
||||
{ "88PM860x", 0 },
|
||||
|
@ -129,6 +129,17 @@ config UCB1400_CORE
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ucb1400_core.
|
||||
|
||||
config TPS6105X
|
||||
tristate "TPS61050/61052 Boost Converters"
|
||||
depends on I2C
|
||||
select REGULATOR
|
||||
select REGULATOR_FIXED_VOLTAGE
|
||||
help
|
||||
This option enables a driver for the TP61050/TPS61052
|
||||
high-power "white LED driver". This boost converter is
|
||||
sometimes used for other things than white LEDs, and
|
||||
also contains a GPIO pin.
|
||||
|
||||
config TPS65010
|
||||
tristate "TPS6501x Power Management chips"
|
||||
depends on I2C && GPIOLIB
|
||||
@ -178,6 +189,16 @@ config TWL4030_CORE
|
||||
high speed USB OTG transceiver, an audio codec (on most
|
||||
versions) and many other features.
|
||||
|
||||
config TWL4030_MADC
|
||||
tristate "Texas Instruments TWL4030 MADC"
|
||||
depends on TWL4030_CORE
|
||||
help
|
||||
This driver provides support for triton TWL4030-MADC. The
|
||||
driver supports both RT and SW conversion methods.
|
||||
|
||||
This driver can be built as a module. If so it will be
|
||||
named twl4030-madc
|
||||
|
||||
config TWL4030_POWER
|
||||
bool "Support power resources on TWL4030 family chips"
|
||||
depends on TWL4030_CORE && ARM
|
||||
@ -304,6 +325,18 @@ config MFD_MAX8925
|
||||
accessing the device, additional drivers must be enabled in order
|
||||
to use the functionality of the device.
|
||||
|
||||
config MFD_MAX8997
|
||||
bool "Maxim Semiconductor MAX8997/8966 PMIC Support"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
Say yes here to support for Maxim Semiconductor MAX8998/8966.
|
||||
This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
|
||||
MUIC controls on chip.
|
||||
This driver provides common support for accessing the device;
|
||||
additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
config MFD_MAX8998
|
||||
bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
@ -534,6 +567,13 @@ config AB8500_DEBUG
|
||||
Select this option if you want debug information using the debug
|
||||
filesystem, debugfs.
|
||||
|
||||
config AB8500_GPADC
|
||||
bool "AB8500 GPADC driver"
|
||||
depends on AB8500_CORE && REGULATOR_AB8500
|
||||
default y
|
||||
help
|
||||
AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage
|
||||
|
||||
config AB3550_CORE
|
||||
bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions"
|
||||
select MFD_CORE
|
||||
|
@ -33,11 +33,13 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o
|
||||
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
|
||||
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
|
||||
|
||||
obj-$(CONFIG_TPS6105X) += tps6105x.o
|
||||
obj-$(CONFIG_TPS65010) += tps65010.o
|
||||
obj-$(CONFIG_TPS6507X) += tps6507x.o
|
||||
obj-$(CONFIG_MENELAUS) += menelaus.o
|
||||
|
||||
obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
|
||||
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
|
||||
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
|
||||
obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
|
||||
obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
|
||||
@ -61,6 +63,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
|
||||
obj-$(CONFIG_PMIC_DA903X) += da903x.o
|
||||
max8925-objs := max8925-core.o max8925-i2c.o
|
||||
obj-$(CONFIG_MFD_MAX8925) += max8925.o
|
||||
obj-$(CONFIG_MFD_MAX8997) += max8997.o
|
||||
obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o
|
||||
|
||||
pcf50633-objs := pcf50633-core.o pcf50633-irq.o
|
||||
@ -71,9 +74,10 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
|
||||
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
|
||||
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
|
||||
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
|
||||
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o
|
||||
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
|
||||
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
|
||||
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
|
||||
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
|
||||
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
|
||||
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
|
||||
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
|
||||
|
@ -613,7 +613,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100)
|
||||
ab3100_get_priv.ab3100 = ab3100;
|
||||
ab3100_get_priv.mode = false;
|
||||
ab3100_get_reg_file = debugfs_create_file("get_reg",
|
||||
S_IWUGO, ab3100_dir, &ab3100_get_priv,
|
||||
S_IWUSR, ab3100_dir, &ab3100_get_priv,
|
||||
&ab3100_get_set_reg_fops);
|
||||
if (!ab3100_get_reg_file) {
|
||||
err = -ENOMEM;
|
||||
@ -623,7 +623,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100)
|
||||
ab3100_set_priv.ab3100 = ab3100;
|
||||
ab3100_set_priv.mode = true;
|
||||
ab3100_set_reg_file = debugfs_create_file("set_reg",
|
||||
S_IWUGO, ab3100_dir, &ab3100_set_priv,
|
||||
S_IWUSR, ab3100_dir, &ab3100_set_priv,
|
||||
&ab3100_get_set_reg_fops);
|
||||
if (!ab3100_set_reg_file) {
|
||||
err = -ENOMEM;
|
||||
@ -949,10 +949,8 @@ static int __devinit ab3100_probe(struct i2c_client *client,
|
||||
goto exit_no_ops;
|
||||
|
||||
/* Set up and register the platform devices. */
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
|
||||
ab3100_devs[i].platform_data = ab3100_plf_data;
|
||||
ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++)
|
||||
ab3100_devs[i].mfd_data = ab3100_plf_data;
|
||||
|
||||
err = mfd_add_devices(&client->dev, 0, ab3100_devs,
|
||||
ARRAY_SIZE(ab3100_devs), NULL, 0);
|
||||
|
@ -1053,17 +1053,17 @@ static inline void ab3550_setup_debugfs(struct ab3550 *ab)
|
||||
goto exit_destroy_dir;
|
||||
|
||||
ab3550_bank_file = debugfs_create_file("register-bank",
|
||||
(S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_bank_fops);
|
||||
(S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_bank_fops);
|
||||
if (!ab3550_bank_file)
|
||||
goto exit_destroy_reg;
|
||||
|
||||
ab3550_address_file = debugfs_create_file("register-address",
|
||||
(S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_address_fops);
|
||||
(S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_address_fops);
|
||||
if (!ab3550_address_file)
|
||||
goto exit_destroy_bank;
|
||||
|
||||
ab3550_val_file = debugfs_create_file("register-value",
|
||||
(S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_val_fops);
|
||||
(S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_val_fops);
|
||||
if (!ab3550_val_file)
|
||||
goto exit_destroy_address;
|
||||
|
||||
@ -1320,10 +1320,8 @@ static int __init ab3550_probe(struct i2c_client *client,
|
||||
goto exit_no_ops;
|
||||
|
||||
/* Set up and register the platform devices. */
|
||||
for (i = 0; i < AB3550_NUM_DEVICES; i++) {
|
||||
ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i];
|
||||
ab3550_devs[i].data_size = ab3550_plf_data->dev_data_sz[i];
|
||||
}
|
||||
for (i = 0; i < AB3550_NUM_DEVICES; i++)
|
||||
ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i];
|
||||
|
||||
err = mfd_add_devices(&client->dev, 0, ab3550_devs,
|
||||
ARRAY_SIZE(ab3550_devs), NULL,
|
||||
|
@ -4,7 +4,7 @@
|
||||
* License Terms: GNU General Public License v2
|
||||
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
|
||||
* Author: Rabin Vincent <rabin.vincent@stericsson.com>
|
||||
* Changes: Mattias Wallin <mattias.wallin@stericsson.com>
|
||||
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -90,6 +90,7 @@
|
||||
#define AB8500_IT_MASK24_REG 0x57
|
||||
|
||||
#define AB8500_REV_REG 0x80
|
||||
#define AB8500_SWITCH_OFF_STATUS 0x00
|
||||
|
||||
/*
|
||||
* Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
|
||||
@ -652,10 +653,38 @@ static ssize_t show_chip_id(struct device *dev,
|
||||
return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* ab8500 has switched off due to (SWITCH_OFF_STATUS):
|
||||
* 0x01 Swoff bit programming
|
||||
* 0x02 Thermal protection activation
|
||||
* 0x04 Vbat lower then BattOk falling threshold
|
||||
* 0x08 Watchdog expired
|
||||
* 0x10 Non presence of 32kHz clock
|
||||
* 0x20 Battery level lower than power on reset threshold
|
||||
* 0x40 Power on key 1 pressed longer than 10 seconds
|
||||
* 0x80 DB8500 thermal shutdown
|
||||
*/
|
||||
static ssize_t show_switch_off_status(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret;
|
||||
u8 value;
|
||||
struct ab8500 *ab8500;
|
||||
|
||||
ab8500 = dev_get_drvdata(dev);
|
||||
ret = get_register_interruptible(ab8500, AB8500_RTC,
|
||||
AB8500_SWITCH_OFF_STATUS, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%#x\n", value);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
|
||||
static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
|
||||
|
||||
static struct attribute *ab8500_sysfs_entries[] = {
|
||||
&dev_attr_chip_id.attr,
|
||||
&dev_attr_switch_off_status.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -686,9 +715,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
* 0x10 - Cut 1.0
|
||||
* 0x11 - Cut 1.1
|
||||
* 0x20 - Cut 2.0
|
||||
* 0x30 - Cut 3.0
|
||||
*/
|
||||
if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
|
||||
ab8500->revision = value;
|
||||
if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 ||
|
||||
value == 0x30) {
|
||||
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
|
||||
} else {
|
||||
dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
|
||||
@ -696,6 +726,24 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
}
|
||||
ab8500->chip_id = value;
|
||||
|
||||
/*
|
||||
* ab8500 has switched off due to (SWITCH_OFF_STATUS):
|
||||
* 0x01 Swoff bit programming
|
||||
* 0x02 Thermal protection activation
|
||||
* 0x04 Vbat lower then BattOk falling threshold
|
||||
* 0x08 Watchdog expired
|
||||
* 0x10 Non presence of 32kHz clock
|
||||
* 0x20 Battery level lower than power on reset threshold
|
||||
* 0x40 Power on key 1 pressed longer than 10 seconds
|
||||
* 0x80 DB8500 thermal shutdown
|
||||
*/
|
||||
|
||||
ret = get_register_interruptible(ab8500, AB8500_RTC,
|
||||
AB8500_SWITCH_OFF_STATUS, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
dev_info(ab8500->dev, "switch off status: %#x", value);
|
||||
|
||||
if (plat && plat->init)
|
||||
plat->init(ab8500);
|
||||
|
||||
@ -764,6 +812,6 @@ int __devexit ab8500_exit(struct ab8500 *ab8500)
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent");
|
||||
MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
|
||||
MODULE_DESCRIPTION("AB8500 MFD core");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -585,18 +585,18 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf)
|
||||
goto exit_destroy_dir;
|
||||
|
||||
ab8500_bank_file = debugfs_create_file("register-bank",
|
||||
(S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
|
||||
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops);
|
||||
if (!ab8500_bank_file)
|
||||
goto exit_destroy_reg;
|
||||
|
||||
ab8500_address_file = debugfs_create_file("register-address",
|
||||
(S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
|
||||
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
|
||||
&ab8500_address_fops);
|
||||
if (!ab8500_address_file)
|
||||
goto exit_destroy_bank;
|
||||
|
||||
ab8500_val_file = debugfs_create_file("register-value",
|
||||
(S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
|
||||
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops);
|
||||
if (!ab8500_val_file)
|
||||
goto exit_destroy_address;
|
||||
|
||||
|
614
drivers/mfd/ab8500-gpadc.c
Normal file
614
drivers/mfd/ab8500-gpadc.c
Normal file
@ -0,0 +1,614 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2010
|
||||
*
|
||||
* License Terms: GNU General Public License v2
|
||||
* Author: Arun R Murthy <arun.murthy@stericsson.com>
|
||||
* Author: Daniel Willerud <daniel.willerud@stericsson.com>
|
||||
* Author: Johan Palsson <johan.palsson@stericsson.com>
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mfd/ab8500.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/ab8500/gpadc.h>
|
||||
|
||||
/*
|
||||
* GPADC register offsets
|
||||
* Bank : 0x0A
|
||||
*/
|
||||
#define AB8500_GPADC_CTRL1_REG 0x00
|
||||
#define AB8500_GPADC_CTRL2_REG 0x01
|
||||
#define AB8500_GPADC_CTRL3_REG 0x02
|
||||
#define AB8500_GPADC_AUTO_TIMER_REG 0x03
|
||||
#define AB8500_GPADC_STAT_REG 0x04
|
||||
#define AB8500_GPADC_MANDATAL_REG 0x05
|
||||
#define AB8500_GPADC_MANDATAH_REG 0x06
|
||||
#define AB8500_GPADC_AUTODATAL_REG 0x07
|
||||
#define AB8500_GPADC_AUTODATAH_REG 0x08
|
||||
#define AB8500_GPADC_MUX_CTRL_REG 0x09
|
||||
|
||||
/*
|
||||
* OTP register offsets
|
||||
* Bank : 0x15
|
||||
*/
|
||||
#define AB8500_GPADC_CAL_1 0x0F
|
||||
#define AB8500_GPADC_CAL_2 0x10
|
||||
#define AB8500_GPADC_CAL_3 0x11
|
||||
#define AB8500_GPADC_CAL_4 0x12
|
||||
#define AB8500_GPADC_CAL_5 0x13
|
||||
#define AB8500_GPADC_CAL_6 0x14
|
||||
#define AB8500_GPADC_CAL_7 0x15
|
||||
|
||||
/* gpadc constants */
|
||||
#define EN_VINTCORE12 0x04
|
||||
#define EN_VTVOUT 0x02
|
||||
#define EN_GPADC 0x01
|
||||
#define DIS_GPADC 0x00
|
||||
#define SW_AVG_16 0x60
|
||||
#define ADC_SW_CONV 0x04
|
||||
#define EN_ICHAR 0x80
|
||||
#define EN_BUF 0x40
|
||||
#define DIS_ZERO 0x00
|
||||
#define GPADC_BUSY 0x01
|
||||
|
||||
/* GPADC constants from AB8500 spec, UM0836 */
|
||||
#define ADC_RESOLUTION 1024
|
||||
#define ADC_CH_BTEMP_MIN 0
|
||||
#define ADC_CH_BTEMP_MAX 1350
|
||||
#define ADC_CH_DIETEMP_MIN 0
|
||||
#define ADC_CH_DIETEMP_MAX 1350
|
||||
#define ADC_CH_CHG_V_MIN 0
|
||||
#define ADC_CH_CHG_V_MAX 20030
|
||||
#define ADC_CH_ACCDET2_MIN 0
|
||||
#define ADC_CH_ACCDET2_MAX 2500
|
||||
#define ADC_CH_VBAT_MIN 2300
|
||||
#define ADC_CH_VBAT_MAX 4800
|
||||
#define ADC_CH_CHG_I_MIN 0
|
||||
#define ADC_CH_CHG_I_MAX 1500
|
||||
#define ADC_CH_BKBAT_MIN 0
|
||||
#define ADC_CH_BKBAT_MAX 3200
|
||||
|
||||
/* This is used to not lose precision when dividing to get gain and offset */
|
||||
#define CALIB_SCALE 1000
|
||||
|
||||
enum cal_channels {
|
||||
ADC_INPUT_VMAIN = 0,
|
||||
ADC_INPUT_BTEMP,
|
||||
ADC_INPUT_VBAT,
|
||||
NBR_CAL_INPUTS,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adc_cal_data - Table for storing gain and offset for the calibrated
|
||||
* ADC channels
|
||||
* @gain: Gain of the ADC channel
|
||||
* @offset: Offset of the ADC channel
|
||||
*/
|
||||
struct adc_cal_data {
|
||||
u64 gain;
|
||||
u64 offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab8500_gpadc - AB8500 GPADC device information
|
||||
* @dev: pointer to the struct device
|
||||
* @node: a list of AB8500 GPADCs, hence prepared for
|
||||
reentrance
|
||||
* @ab8500_gpadc_complete: pointer to the struct completion, to indicate
|
||||
* the completion of gpadc conversion
|
||||
* @ab8500_gpadc_lock: structure of type mutex
|
||||
* @regu: pointer to the struct regulator
|
||||
* @irq: interrupt number that is used by gpadc
|
||||
* @cal_data array of ADC calibration data structs
|
||||
*/
|
||||
struct ab8500_gpadc {
|
||||
struct device *dev;
|
||||
struct list_head node;
|
||||
struct completion ab8500_gpadc_complete;
|
||||
struct mutex ab8500_gpadc_lock;
|
||||
struct regulator *regu;
|
||||
int irq;
|
||||
struct adc_cal_data cal_data[NBR_CAL_INPUTS];
|
||||
};
|
||||
|
||||
static LIST_HEAD(ab8500_gpadc_list);
|
||||
|
||||
/**
|
||||
* ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC
|
||||
* (i.e. the first GPADC in the instance list)
|
||||
*/
|
||||
struct ab8500_gpadc *ab8500_gpadc_get(char *name)
|
||||
{
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
list_for_each_entry(gpadc, &ab8500_gpadc_list, node) {
|
||||
if (!strcmp(name, dev_name(gpadc->dev)))
|
||||
return gpadc;
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
EXPORT_SYMBOL(ab8500_gpadc_get);
|
||||
|
||||
static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 input,
|
||||
int ad_value)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (input) {
|
||||
case MAIN_CHARGER_V:
|
||||
/* For some reason we don't have calibrated data */
|
||||
if (!gpadc->cal_data[ADC_INPUT_VMAIN].gain) {
|
||||
res = ADC_CH_CHG_V_MIN + (ADC_CH_CHG_V_MAX -
|
||||
ADC_CH_CHG_V_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
}
|
||||
/* Here we can use the calibrated data */
|
||||
res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VMAIN].gain +
|
||||
gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE;
|
||||
break;
|
||||
|
||||
case BAT_CTRL:
|
||||
case BTEMP_BALL:
|
||||
case ACC_DETECT1:
|
||||
case ADC_AUX1:
|
||||
case ADC_AUX2:
|
||||
/* For some reason we don't have calibrated data */
|
||||
if (!gpadc->cal_data[ADC_INPUT_BTEMP].gain) {
|
||||
res = ADC_CH_BTEMP_MIN + (ADC_CH_BTEMP_MAX -
|
||||
ADC_CH_BTEMP_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
}
|
||||
/* Here we can use the calibrated data */
|
||||
res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_BTEMP].gain +
|
||||
gpadc->cal_data[ADC_INPUT_BTEMP].offset) / CALIB_SCALE;
|
||||
break;
|
||||
|
||||
case MAIN_BAT_V:
|
||||
/* For some reason we don't have calibrated data */
|
||||
if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) {
|
||||
res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX -
|
||||
ADC_CH_VBAT_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
}
|
||||
/* Here we can use the calibrated data */
|
||||
res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VBAT].gain +
|
||||
gpadc->cal_data[ADC_INPUT_VBAT].offset) / CALIB_SCALE;
|
||||
break;
|
||||
|
||||
case DIE_TEMP:
|
||||
res = ADC_CH_DIETEMP_MIN +
|
||||
(ADC_CH_DIETEMP_MAX - ADC_CH_DIETEMP_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
|
||||
case ACC_DETECT2:
|
||||
res = ADC_CH_ACCDET2_MIN +
|
||||
(ADC_CH_ACCDET2_MAX - ADC_CH_ACCDET2_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
|
||||
case VBUS_V:
|
||||
res = ADC_CH_CHG_V_MIN +
|
||||
(ADC_CH_CHG_V_MAX - ADC_CH_CHG_V_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
|
||||
case MAIN_CHARGER_C:
|
||||
case USB_CHARGER_C:
|
||||
res = ADC_CH_CHG_I_MIN +
|
||||
(ADC_CH_CHG_I_MAX - ADC_CH_CHG_I_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
|
||||
case BK_BAT_V:
|
||||
res = ADC_CH_BKBAT_MIN +
|
||||
(ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * ad_value /
|
||||
ADC_RESOLUTION;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(gpadc->dev,
|
||||
"unknown channel, not possible to convert\n");
|
||||
res = -EINVAL;
|
||||
break;
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* ab8500_gpadc_convert() - gpadc conversion
|
||||
* @input: analog input to be converted to digital data
|
||||
*
|
||||
* This function converts the selected analog i/p to digital
|
||||
* data.
|
||||
*/
|
||||
int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
|
||||
{
|
||||
int ret;
|
||||
u16 data = 0;
|
||||
int looplimit = 0;
|
||||
u8 val, low_data, high_data;
|
||||
|
||||
if (!gpadc)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&gpadc->ab8500_gpadc_lock);
|
||||
/* Enable VTVout LDO this is required for GPADC */
|
||||
regulator_enable(gpadc->regu);
|
||||
|
||||
/* Check if ADC is not busy, lock and proceed */
|
||||
do {
|
||||
ret = abx500_get_register_interruptible(gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_STAT_REG, &val);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (!(val & GPADC_BUSY))
|
||||
break;
|
||||
msleep(10);
|
||||
} while (++looplimit < 10);
|
||||
if (looplimit >= 10 && (val & GPADC_BUSY)) {
|
||||
dev_err(gpadc->dev, "gpadc_conversion: GPADC busy");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Enable GPADC */
|
||||
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
|
||||
goto out;
|
||||
}
|
||||
/* Select the input source and set average samples to 16 */
|
||||
ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
|
||||
AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev,
|
||||
"gpadc_conversion: set avg samples failed\n");
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* Enable ADC, buffering, select rising edge and enable ADC path
|
||||
* charging current sense if it needed
|
||||
*/
|
||||
switch (input) {
|
||||
case MAIN_CHARGER_C:
|
||||
case USB_CHARGER_C:
|
||||
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
|
||||
EN_BUF | EN_ICHAR,
|
||||
EN_BUF | EN_ICHAR);
|
||||
break;
|
||||
default:
|
||||
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev,
|
||||
"gpadc_conversion: select falling edge failed\n");
|
||||
goto out;
|
||||
}
|
||||
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev,
|
||||
"gpadc_conversion: start s/w conversion failed\n");
|
||||
goto out;
|
||||
}
|
||||
/* wait for completion of conversion */
|
||||
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
|
||||
dev_err(gpadc->dev,
|
||||
"timeout: didnt recieve GPADC conversion interrupt\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read the converted RAW data */
|
||||
ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
|
||||
AB8500_GPADC_MANDATAL_REG, &low_data);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
|
||||
AB8500_GPADC_MANDATAH_REG, &high_data);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev,
|
||||
"gpadc_conversion: read high data failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = (high_data << 8) | low_data;
|
||||
/* Disable GPADC */
|
||||
ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
|
||||
AB8500_GPADC_CTRL1_REG, DIS_GPADC);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
|
||||
goto out;
|
||||
}
|
||||
/* Disable VTVout LDO this is required for GPADC */
|
||||
regulator_disable(gpadc->regu);
|
||||
mutex_unlock(&gpadc->ab8500_gpadc_lock);
|
||||
ret = ab8500_gpadc_ad_to_voltage(gpadc, input, data);
|
||||
return ret;
|
||||
|
||||
out:
|
||||
/*
|
||||
* It has shown to be needed to turn off the GPADC if an error occurs,
|
||||
* otherwise we might have problem when waiting for the busy bit in the
|
||||
* GPADC status register to go low. In V1.1 there wait_for_completion
|
||||
* seems to timeout when waiting for an interrupt.. Not seen in V2.0
|
||||
*/
|
||||
(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
|
||||
AB8500_GPADC_CTRL1_REG, DIS_GPADC);
|
||||
regulator_disable(gpadc->regu);
|
||||
mutex_unlock(&gpadc->ab8500_gpadc_lock);
|
||||
dev_err(gpadc->dev,
|
||||
"gpadc_conversion: Failed to AD convert channel %d\n", input);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ab8500_gpadc_convert);
|
||||
|
||||
/**
|
||||
* ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion
|
||||
* @irq: irq number
|
||||
* @data: pointer to the data passed during request irq
|
||||
*
|
||||
* This is a interrupt service routine for s/w gpadc conversion completion.
|
||||
* Notifies the gpadc completion is completed and the converted raw value
|
||||
* can be read from the registers.
|
||||
* Returns IRQ status(IRQ_HANDLED)
|
||||
*/
|
||||
static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc)
|
||||
{
|
||||
struct ab8500_gpadc *gpadc = _gpadc;
|
||||
|
||||
complete(&gpadc->ab8500_gpadc_complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int otp_cal_regs[] = {
|
||||
AB8500_GPADC_CAL_1,
|
||||
AB8500_GPADC_CAL_2,
|
||||
AB8500_GPADC_CAL_3,
|
||||
AB8500_GPADC_CAL_4,
|
||||
AB8500_GPADC_CAL_5,
|
||||
AB8500_GPADC_CAL_6,
|
||||
AB8500_GPADC_CAL_7,
|
||||
};
|
||||
|
||||
static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
|
||||
{
|
||||
int i;
|
||||
int ret[ARRAY_SIZE(otp_cal_regs)];
|
||||
u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)];
|
||||
|
||||
int vmain_high, vmain_low;
|
||||
int btemp_high, btemp_low;
|
||||
int vbat_high, vbat_low;
|
||||
|
||||
/* First we read all OTP registers and store the error code */
|
||||
for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) {
|
||||
ret[i] = abx500_get_register_interruptible(gpadc->dev,
|
||||
AB8500_OTP_EMUL, otp_cal_regs[i], &gpadc_cal[i]);
|
||||
if (ret[i] < 0)
|
||||
dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n",
|
||||
__func__, otp_cal_regs[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* The ADC calibration data is stored in OTP registers.
|
||||
* The layout of the calibration data is outlined below and a more
|
||||
* detailed description can be found in UM0836
|
||||
*
|
||||
* vm_h/l = vmain_high/low
|
||||
* bt_h/l = btemp_high/low
|
||||
* vb_h/l = vbat_high/low
|
||||
*
|
||||
* Data bits:
|
||||
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
* | | vm_h9 | vm_h8
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
* | | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
* | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
* | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
* | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
* | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
* | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 |
|
||||
* |.......|.......|.......|.......|.......|.......|.......|.......
|
||||
*
|
||||
*
|
||||
* Ideal output ADC codes corresponding to injected input voltages
|
||||
* during manufacturing is:
|
||||
*
|
||||
* vmain_high: Vin = 19500mV / ADC ideal code = 997
|
||||
* vmain_low: Vin = 315mV / ADC ideal code = 16
|
||||
* btemp_high: Vin = 1300mV / ADC ideal code = 985
|
||||
* btemp_low: Vin = 21mV / ADC ideal code = 16
|
||||
* vbat_high: Vin = 4700mV / ADC ideal code = 982
|
||||
* vbat_low: Vin = 2380mV / ADC ideal code = 33
|
||||
*/
|
||||
|
||||
/* Calculate gain and offset for VMAIN if all reads succeeded */
|
||||
if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) {
|
||||
vmain_high = (((gpadc_cal[0] & 0x03) << 8) |
|
||||
((gpadc_cal[1] & 0x3F) << 2) |
|
||||
((gpadc_cal[2] & 0xC0) >> 6));
|
||||
|
||||
vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
|
||||
|
||||
gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
|
||||
(19500 - 315) / (vmain_high - vmain_low);
|
||||
|
||||
gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 -
|
||||
(CALIB_SCALE * (19500 - 315) /
|
||||
(vmain_high - vmain_low)) * vmain_high;
|
||||
} else {
|
||||
gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
|
||||
}
|
||||
|
||||
/* Calculate gain and offset for BTEMP if all reads succeeded */
|
||||
if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) {
|
||||
btemp_high = (((gpadc_cal[2] & 0x01) << 9) |
|
||||
(gpadc_cal[3] << 1) |
|
||||
((gpadc_cal[4] & 0x80) >> 7));
|
||||
|
||||
btemp_low = ((gpadc_cal[4] & 0x7C) >> 2);
|
||||
|
||||
gpadc->cal_data[ADC_INPUT_BTEMP].gain =
|
||||
CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low);
|
||||
|
||||
gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 -
|
||||
(CALIB_SCALE * (1300 - 21) /
|
||||
(btemp_high - btemp_low)) * btemp_high;
|
||||
} else {
|
||||
gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0;
|
||||
}
|
||||
|
||||
/* Calculate gain and offset for VBAT if all reads succeeded */
|
||||
if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) {
|
||||
vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]);
|
||||
vbat_low = ((gpadc_cal[6] & 0xFC) >> 2);
|
||||
|
||||
gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE *
|
||||
(4700 - 2380) / (vbat_high - vbat_low);
|
||||
|
||||
gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 -
|
||||
(CALIB_SCALE * (4700 - 2380) /
|
||||
(vbat_high - vbat_low)) * vbat_high;
|
||||
} else {
|
||||
gpadc->cal_data[ADC_INPUT_VBAT].gain = 0;
|
||||
}
|
||||
|
||||
dev_dbg(gpadc->dev, "VMAIN gain %llu offset %llu\n",
|
||||
gpadc->cal_data[ADC_INPUT_VMAIN].gain,
|
||||
gpadc->cal_data[ADC_INPUT_VMAIN].offset);
|
||||
|
||||
dev_dbg(gpadc->dev, "BTEMP gain %llu offset %llu\n",
|
||||
gpadc->cal_data[ADC_INPUT_BTEMP].gain,
|
||||
gpadc->cal_data[ADC_INPUT_BTEMP].offset);
|
||||
|
||||
dev_dbg(gpadc->dev, "VBAT gain %llu offset %llu\n",
|
||||
gpadc->cal_data[ADC_INPUT_VBAT].gain,
|
||||
gpadc->cal_data[ADC_INPUT_VBAT].offset);
|
||||
}
|
||||
|
||||
static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL);
|
||||
if (!gpadc) {
|
||||
dev_err(&pdev->dev, "Error: No memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
|
||||
if (gpadc->irq < 0) {
|
||||
dev_err(gpadc->dev, "failed to get platform irq-%d\n",
|
||||
gpadc->irq);
|
||||
ret = gpadc->irq;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gpadc->dev = &pdev->dev;
|
||||
mutex_init(&gpadc->ab8500_gpadc_lock);
|
||||
|
||||
/* Initialize completion used to notify completion of conversion */
|
||||
init_completion(&gpadc->ab8500_gpadc_complete);
|
||||
|
||||
/* Register interrupt - SwAdcComplete */
|
||||
ret = request_threaded_irq(gpadc->irq, NULL,
|
||||
ab8500_bm_gpswadcconvend_handler,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
|
||||
gpadc->irq);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* VTVout LDO used to power up ab8500-GPADC */
|
||||
gpadc->regu = regulator_get(&pdev->dev, "vddadc");
|
||||
if (IS_ERR(gpadc->regu)) {
|
||||
ret = PTR_ERR(gpadc->regu);
|
||||
dev_err(gpadc->dev, "failed to get vtvout LDO\n");
|
||||
goto fail_irq;
|
||||
}
|
||||
ab8500_gpadc_read_calibration_data(gpadc);
|
||||
list_add_tail(&gpadc->node, &ab8500_gpadc_list);
|
||||
dev_dbg(gpadc->dev, "probe success\n");
|
||||
return 0;
|
||||
fail_irq:
|
||||
free_irq(gpadc->irq, gpadc);
|
||||
fail:
|
||||
kfree(gpadc);
|
||||
gpadc = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ab8500_gpadc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev);
|
||||
|
||||
/* remove this gpadc entry from the list */
|
||||
list_del(&gpadc->node);
|
||||
/* remove interrupt - completion of Sw ADC conversion */
|
||||
free_irq(gpadc->irq, gpadc);
|
||||
/* disable VTVout LDO that is being used by GPADC */
|
||||
regulator_put(gpadc->regu);
|
||||
kfree(gpadc);
|
||||
gpadc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ab8500_gpadc_driver = {
|
||||
.probe = ab8500_gpadc_probe,
|
||||
.remove = __devexit_p(ab8500_gpadc_remove),
|
||||
.driver = {
|
||||
.name = "ab8500-gpadc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ab8500_gpadc_init(void)
|
||||
{
|
||||
return platform_driver_register(&ab8500_gpadc_driver);
|
||||
}
|
||||
|
||||
static void __exit ab8500_gpadc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ab8500_gpadc_driver);
|
||||
}
|
||||
|
||||
subsys_initcall_sync(ab8500_gpadc_init);
|
||||
module_exit(ab8500_gpadc_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson");
|
||||
MODULE_ALIAS("platform:ab8500_gpadc");
|
||||
MODULE_DESCRIPTION("AB8500 GPADC driver");
|
80
drivers/mfd/ab8500-sysctrl.c
Normal file
80
drivers/mfd/ab8500-sysctrl.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2010
|
||||
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/ab8500.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/ab8500/sysctrl.h>
|
||||
|
||||
static struct device *sysctrl_dev;
|
||||
|
||||
static inline bool valid_bank(u8 bank)
|
||||
{
|
||||
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
|
||||
(bank == AB8500_SYS_CTRL2_BLOCK));
|
||||
}
|
||||
|
||||
int ab8500_sysctrl_read(u16 reg, u8 *value)
|
||||
{
|
||||
u8 bank;
|
||||
|
||||
if (sysctrl_dev == NULL)
|
||||
return -EAGAIN;
|
||||
|
||||
bank = (reg >> 8);
|
||||
if (!valid_bank(bank))
|
||||
return -EINVAL;
|
||||
|
||||
return abx500_get_register_interruptible(sysctrl_dev, bank,
|
||||
(u8)(reg & 0xFF), value);
|
||||
}
|
||||
|
||||
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
|
||||
{
|
||||
u8 bank;
|
||||
|
||||
if (sysctrl_dev == NULL)
|
||||
return -EAGAIN;
|
||||
|
||||
bank = (reg >> 8);
|
||||
if (!valid_bank(bank))
|
||||
return -EINVAL;
|
||||
|
||||
return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
|
||||
(u8)(reg & 0xFF), mask, value);
|
||||
}
|
||||
|
||||
static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
sysctrl_dev = &pdev->dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
sysctrl_dev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ab8500_sysctrl_driver = {
|
||||
.driver = {
|
||||
.name = "ab8500-sysctrl",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ab8500_sysctrl_probe,
|
||||
.remove = __devexit_p(ab8500_sysctrl_remove),
|
||||
};
|
||||
|
||||
static int __init ab8500_sysctrl_init(void)
|
||||
{
|
||||
return platform_driver_register(&ab8500_sysctrl_driver);
|
||||
}
|
||||
subsys_initcall(ab8500_sysctrl_init);
|
||||
|
||||
MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com");
|
||||
MODULE_DESCRIPTION("AB8500 system control driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -321,27 +321,27 @@ static int __devexit adp5520_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int adp5520_suspend(struct i2c_client *client,
|
||||
pm_message_t state)
|
||||
static int adp5520_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
|
||||
|
||||
adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adp5520_resume(struct i2c_client *client)
|
||||
static int adp5520_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
|
||||
|
||||
adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define adp5520_suspend NULL
|
||||
#define adp5520_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume);
|
||||
|
||||
static const struct i2c_device_id adp5520_id[] = {
|
||||
{ "pmic-adp5520", ID_ADP5520 },
|
||||
{ "pmic-adp5501", ID_ADP5501 },
|
||||
@ -353,11 +353,10 @@ static struct i2c_driver adp5520_driver = {
|
||||
.driver = {
|
||||
.name = "adp5520",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &adp5520_pm,
|
||||
},
|
||||
.probe = adp5520_probe,
|
||||
.remove = __devexit_p(adp5520_remove),
|
||||
.suspend = adp5520_suspend,
|
||||
.resume = adp5520_resume,
|
||||
.id_table = adp5520_id,
|
||||
};
|
||||
|
||||
|
@ -682,7 +682,7 @@ static struct mfd_cell asic3_cell_ds1wm = {
|
||||
.name = "ds1wm",
|
||||
.enable = ds1wm_enable,
|
||||
.disable = ds1wm_disable,
|
||||
.driver_data = &ds1wm_pdata,
|
||||
.mfd_data = &ds1wm_pdata,
|
||||
.num_resources = ARRAY_SIZE(ds1wm_resources),
|
||||
.resources = ds1wm_resources,
|
||||
};
|
||||
@ -783,7 +783,7 @@ static struct mfd_cell asic3_cell_mmc = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = asic3_mmc_enable,
|
||||
.disable = asic3_mmc_disable,
|
||||
.driver_data = &asic3_mmc_data,
|
||||
.mfd_data = &asic3_mmc_data,
|
||||
.num_resources = ARRAY_SIZE(asic3_mmc_resources),
|
||||
.resources = asic3_mmc_resources,
|
||||
};
|
||||
@ -810,9 +810,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
|
||||
ds1wm_resources[0].start >>= asic->bus_shift;
|
||||
ds1wm_resources[0].end >>= asic->bus_shift;
|
||||
|
||||
asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm;
|
||||
asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
|
||||
|
||||
/* MMC */
|
||||
asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
|
||||
mem_sdio->start, 0x400 >> asic->bus_shift);
|
||||
@ -824,9 +821,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
|
||||
asic3_mmc_resources[0].start >>= asic->bus_shift;
|
||||
asic3_mmc_resources[0].end >>= asic->bus_shift;
|
||||
|
||||
asic3_cell_mmc.platform_data = &asic3_cell_mmc;
|
||||
asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id,
|
||||
&asic3_cell_ds1wm, 1, mem, asic->irq_base);
|
||||
if (ret < 0)
|
||||
|
@ -39,6 +39,37 @@ enum cs5535_mfd_bars {
|
||||
NR_BARS,
|
||||
};
|
||||
|
||||
static int cs5535_mfd_res_enable(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "can't fetch device resource info\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!request_region(res->start, resource_size(res), DRV_NAME)) {
|
||||
dev_err(&pdev->dev, "can't request region\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs5535_mfd_res_disable(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "can't fetch device resource info\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
release_region(res->start, resource_size(res));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __devinitdata struct resource cs5535_mfd_resources[NR_BARS];
|
||||
|
||||
static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
|
||||
@ -65,12 +96,18 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
|
||||
.name = "cs5535-pms",
|
||||
.num_resources = 1,
|
||||
.resources = &cs5535_mfd_resources[PMS_BAR],
|
||||
|
||||
.enable = cs5535_mfd_res_enable,
|
||||
.disable = cs5535_mfd_res_disable,
|
||||
},
|
||||
{
|
||||
.id = ACPI_BAR,
|
||||
.name = "cs5535-acpi",
|
||||
.num_resources = 1,
|
||||
.resources = &cs5535_mfd_resources[ACPI_BAR],
|
||||
|
||||
.enable = cs5535_mfd_res_enable,
|
||||
.disable = cs5535_mfd_res_disable,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -119,12 +119,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
|
||||
/* Voice codec interface client */
|
||||
cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
|
||||
cell->name = "davinci-vcif";
|
||||
cell->driver_data = davinci_vc;
|
||||
cell->mfd_data = davinci_vc;
|
||||
|
||||
/* Voice codec CQ93VC client */
|
||||
cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
|
||||
cell->name = "cq93vc-codec";
|
||||
cell->driver_data = davinci_vc;
|
||||
cell->mfd_data = davinci_vc;
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
|
||||
DAVINCI_VC_CELLS, NULL, 0);
|
||||
|
@ -117,7 +117,7 @@ static struct mfd_cell ds1wm_cell __initdata = {
|
||||
.name = "ds1wm",
|
||||
.enable = ds1wm_enable,
|
||||
.disable = ds1wm_disable,
|
||||
.driver_data = &ds1wm_pdata,
|
||||
.mfd_data = &ds1wm_pdata,
|
||||
.num_resources = 2,
|
||||
.resources = ds1wm_resources,
|
||||
};
|
||||
@ -165,8 +165,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
|
||||
ds1wm_pdata.clock_rate = pdata->clock_rate;
|
||||
/* the first 5 PASIC3 registers control the DS1WM */
|
||||
ds1wm_resources[0].end = (5 << asic->bus_shift) - 1;
|
||||
ds1wm_cell.platform_data = &ds1wm_cell;
|
||||
ds1wm_cell.data_size = sizeof(ds1wm_cell);
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id,
|
||||
&ds1wm_cell, 1, r, irq);
|
||||
if (ret < 0)
|
||||
@ -174,9 +172,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (pdata && pdata->led_pdata) {
|
||||
led_cell.driver_data = pdata->led_pdata;
|
||||
led_cell.platform_data = &led_cell;
|
||||
led_cell.data_size = sizeof(ds1wm_cell);
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "failed to register LED device\n");
|
||||
|
@ -86,8 +86,7 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv,
|
||||
|
||||
/* Add platform data */
|
||||
pdata->modno = modno;
|
||||
cell->platform_data = pdata;
|
||||
cell->data_size = sizeof(*pdata);
|
||||
cell->mfd_data = pdata;
|
||||
|
||||
/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
|
||||
res->flags = IORESOURCE_MEM;
|
||||
|
@ -232,8 +232,6 @@ const struct mfd_cell jz4740_adc_cells[] = {
|
||||
.name = "jz4740-hwmon",
|
||||
.num_resources = ARRAY_SIZE(jz4740_hwmon_resources),
|
||||
.resources = jz4740_hwmon_resources,
|
||||
.platform_data = (void *)&jz4740_adc_cells[0],
|
||||
.data_size = sizeof(struct mfd_cell),
|
||||
|
||||
.enable = jz4740_adc_cell_enable,
|
||||
.disable = jz4740_adc_cell_disable,
|
||||
@ -243,8 +241,6 @@ const struct mfd_cell jz4740_adc_cells[] = {
|
||||
.name = "jz4740-battery",
|
||||
.num_resources = ARRAY_SIZE(jz4740_battery_resources),
|
||||
.resources = jz4740_battery_resources,
|
||||
.platform_data = (void *)&jz4740_adc_cells[1],
|
||||
.data_size = sizeof(struct mfd_cell),
|
||||
|
||||
.enable = jz4740_adc_cell_enable,
|
||||
.disable = jz4740_adc_cell_disable,
|
||||
|
@ -61,6 +61,7 @@ static struct mfd_cell lpc_sch_cells[] = {
|
||||
|
||||
static struct pci_device_id lpc_sch_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
|
||||
@ -70,6 +71,7 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
|
||||
{
|
||||
unsigned int base_addr_cfg;
|
||||
unsigned short base_addr;
|
||||
int i;
|
||||
|
||||
pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
|
||||
if (!(base_addr_cfg & (1 << 31))) {
|
||||
@ -99,7 +101,10 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
|
||||
gpio_sch_resource.start = base_addr;
|
||||
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
|
||||
|
||||
return mfd_add_devices(&dev->dev, -1,
|
||||
for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
|
||||
lpc_sch_cells[i].id = id->device;
|
||||
|
||||
return mfd_add_devices(&dev->dev, 0,
|
||||
lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
|
||||
}
|
||||
|
||||
|
427
drivers/mfd/max8997.c
Normal file
427
drivers/mfd/max8997.c
Normal file
@ -0,0 +1,427 @@
|
||||
/*
|
||||
* max8997.c - mfd core driver for the Maxim 8966 and 8997
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
* MyungJoo Ham <myungjoo.ham@smasung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* This driver is based on max8998.c
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/max8997.h>
|
||||
#include <linux/mfd/max8997-private.h>
|
||||
|
||||
#define I2C_ADDR_PMIC (0xCC >> 1)
|
||||
#define I2C_ADDR_MUIC (0x4A >> 1)
|
||||
#define I2C_ADDR_BATTERY (0x6C >> 1)
|
||||
#define I2C_ADDR_RTC (0x0C >> 1)
|
||||
#define I2C_ADDR_HAPTIC (0x90 >> 1)
|
||||
|
||||
static struct mfd_cell max8997_devs[] = {
|
||||
{ .name = "max8997-pmic", },
|
||||
{ .name = "max8997-rtc", },
|
||||
{ .name = "max8997-battery", },
|
||||
{ .name = "max8997-haptic", },
|
||||
{ .name = "max8997-muic", },
|
||||
{ .name = "max8997-flash", },
|
||||
};
|
||||
|
||||
int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
|
||||
{
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&max8997->iolock);
|
||||
ret = i2c_smbus_read_byte_data(i2c, reg);
|
||||
mutex_unlock(&max8997->iolock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret &= 0xff;
|
||||
*dest = ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max8997_read_reg);
|
||||
|
||||
int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
|
||||
{
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&max8997->iolock);
|
||||
ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
|
||||
mutex_unlock(&max8997->iolock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max8997_bulk_read);
|
||||
|
||||
int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value)
|
||||
{
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&max8997->iolock);
|
||||
ret = i2c_smbus_write_byte_data(i2c, reg, value);
|
||||
mutex_unlock(&max8997->iolock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max8997_write_reg);
|
||||
|
||||
int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
|
||||
{
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&max8997->iolock);
|
||||
ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
|
||||
mutex_unlock(&max8997->iolock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max8997_bulk_write);
|
||||
|
||||
int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
|
||||
{
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&max8997->iolock);
|
||||
ret = i2c_smbus_read_byte_data(i2c, reg);
|
||||
if (ret >= 0) {
|
||||
u8 old_val = ret & 0xff;
|
||||
u8 new_val = (val & mask) | (old_val & (~mask));
|
||||
ret = i2c_smbus_write_byte_data(i2c, reg, new_val);
|
||||
}
|
||||
mutex_unlock(&max8997->iolock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(max8997_update_reg);
|
||||
|
||||
static int max8997_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct max8997_dev *max8997;
|
||||
struct max8997_platform_data *pdata = i2c->dev.platform_data;
|
||||
int ret = 0;
|
||||
|
||||
max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL);
|
||||
if (max8997 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, max8997);
|
||||
max8997->dev = &i2c->dev;
|
||||
max8997->i2c = i2c;
|
||||
max8997->type = id->driver_data;
|
||||
|
||||
if (!pdata)
|
||||
goto err;
|
||||
|
||||
max8997->wakeup = pdata->wakeup;
|
||||
|
||||
mutex_init(&max8997->iolock);
|
||||
|
||||
max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
|
||||
i2c_set_clientdata(max8997->rtc, max8997);
|
||||
max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
|
||||
i2c_set_clientdata(max8997->haptic, max8997);
|
||||
max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
|
||||
i2c_set_clientdata(max8997->muic, max8997);
|
||||
|
||||
pm_runtime_set_active(max8997->dev);
|
||||
|
||||
mfd_add_devices(max8997->dev, -1, max8997_devs,
|
||||
ARRAY_SIZE(max8997_devs),
|
||||
NULL, 0);
|
||||
|
||||
/*
|
||||
* TODO: enable others (flash, muic, rtc, battery, ...) and
|
||||
* check the return value
|
||||
*/
|
||||
|
||||
if (ret < 0)
|
||||
goto err_mfd;
|
||||
|
||||
return ret;
|
||||
|
||||
err_mfd:
|
||||
mfd_remove_devices(max8997->dev);
|
||||
i2c_unregister_device(max8997->muic);
|
||||
i2c_unregister_device(max8997->haptic);
|
||||
i2c_unregister_device(max8997->rtc);
|
||||
err:
|
||||
kfree(max8997);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
|
||||
mfd_remove_devices(max8997->dev);
|
||||
i2c_unregister_device(max8997->muic);
|
||||
i2c_unregister_device(max8997->haptic);
|
||||
i2c_unregister_device(max8997->rtc);
|
||||
kfree(max8997);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max8997_i2c_id[] = {
|
||||
{ "max8997", TYPE_MAX8997 },
|
||||
{ "max8966", TYPE_MAX8966 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
|
||||
|
||||
u8 max8997_dumpaddr_pmic[] = {
|
||||
MAX8997_REG_INT1MSK,
|
||||
MAX8997_REG_INT2MSK,
|
||||
MAX8997_REG_INT3MSK,
|
||||
MAX8997_REG_INT4MSK,
|
||||
MAX8997_REG_MAINCON1,
|
||||
MAX8997_REG_MAINCON2,
|
||||
MAX8997_REG_BUCKRAMP,
|
||||
MAX8997_REG_BUCK1CTRL,
|
||||
MAX8997_REG_BUCK1DVS1,
|
||||
MAX8997_REG_BUCK1DVS2,
|
||||
MAX8997_REG_BUCK1DVS3,
|
||||
MAX8997_REG_BUCK1DVS4,
|
||||
MAX8997_REG_BUCK1DVS5,
|
||||
MAX8997_REG_BUCK1DVS6,
|
||||
MAX8997_REG_BUCK1DVS7,
|
||||
MAX8997_REG_BUCK1DVS8,
|
||||
MAX8997_REG_BUCK2CTRL,
|
||||
MAX8997_REG_BUCK2DVS1,
|
||||
MAX8997_REG_BUCK2DVS2,
|
||||
MAX8997_REG_BUCK2DVS3,
|
||||
MAX8997_REG_BUCK2DVS4,
|
||||
MAX8997_REG_BUCK2DVS5,
|
||||
MAX8997_REG_BUCK2DVS6,
|
||||
MAX8997_REG_BUCK2DVS7,
|
||||
MAX8997_REG_BUCK2DVS8,
|
||||
MAX8997_REG_BUCK3CTRL,
|
||||
MAX8997_REG_BUCK3DVS,
|
||||
MAX8997_REG_BUCK4CTRL,
|
||||
MAX8997_REG_BUCK4DVS,
|
||||
MAX8997_REG_BUCK5CTRL,
|
||||
MAX8997_REG_BUCK5DVS1,
|
||||
MAX8997_REG_BUCK5DVS2,
|
||||
MAX8997_REG_BUCK5DVS3,
|
||||
MAX8997_REG_BUCK5DVS4,
|
||||
MAX8997_REG_BUCK5DVS5,
|
||||
MAX8997_REG_BUCK5DVS6,
|
||||
MAX8997_REG_BUCK5DVS7,
|
||||
MAX8997_REG_BUCK5DVS8,
|
||||
MAX8997_REG_BUCK6CTRL,
|
||||
MAX8997_REG_BUCK6BPSKIPCTRL,
|
||||
MAX8997_REG_BUCK7CTRL,
|
||||
MAX8997_REG_BUCK7DVS,
|
||||
MAX8997_REG_LDO1CTRL,
|
||||
MAX8997_REG_LDO2CTRL,
|
||||
MAX8997_REG_LDO3CTRL,
|
||||
MAX8997_REG_LDO4CTRL,
|
||||
MAX8997_REG_LDO5CTRL,
|
||||
MAX8997_REG_LDO6CTRL,
|
||||
MAX8997_REG_LDO7CTRL,
|
||||
MAX8997_REG_LDO8CTRL,
|
||||
MAX8997_REG_LDO9CTRL,
|
||||
MAX8997_REG_LDO10CTRL,
|
||||
MAX8997_REG_LDO11CTRL,
|
||||
MAX8997_REG_LDO12CTRL,
|
||||
MAX8997_REG_LDO13CTRL,
|
||||
MAX8997_REG_LDO14CTRL,
|
||||
MAX8997_REG_LDO15CTRL,
|
||||
MAX8997_REG_LDO16CTRL,
|
||||
MAX8997_REG_LDO17CTRL,
|
||||
MAX8997_REG_LDO18CTRL,
|
||||
MAX8997_REG_LDO21CTRL,
|
||||
MAX8997_REG_MBCCTRL1,
|
||||
MAX8997_REG_MBCCTRL2,
|
||||
MAX8997_REG_MBCCTRL3,
|
||||
MAX8997_REG_MBCCTRL4,
|
||||
MAX8997_REG_MBCCTRL5,
|
||||
MAX8997_REG_MBCCTRL6,
|
||||
MAX8997_REG_OTPCGHCVS,
|
||||
MAX8997_REG_SAFEOUTCTRL,
|
||||
MAX8997_REG_LBCNFG1,
|
||||
MAX8997_REG_LBCNFG2,
|
||||
MAX8997_REG_BBCCTRL,
|
||||
|
||||
MAX8997_REG_FLASH1_CUR,
|
||||
MAX8997_REG_FLASH2_CUR,
|
||||
MAX8997_REG_MOVIE_CUR,
|
||||
MAX8997_REG_GSMB_CUR,
|
||||
MAX8997_REG_BOOST_CNTL,
|
||||
MAX8997_REG_LEN_CNTL,
|
||||
MAX8997_REG_FLASH_CNTL,
|
||||
MAX8997_REG_WDT_CNTL,
|
||||
MAX8997_REG_MAXFLASH1,
|
||||
MAX8997_REG_MAXFLASH2,
|
||||
MAX8997_REG_FLASHSTATUSMASK,
|
||||
|
||||
MAX8997_REG_GPIOCNTL1,
|
||||
MAX8997_REG_GPIOCNTL2,
|
||||
MAX8997_REG_GPIOCNTL3,
|
||||
MAX8997_REG_GPIOCNTL4,
|
||||
MAX8997_REG_GPIOCNTL5,
|
||||
MAX8997_REG_GPIOCNTL6,
|
||||
MAX8997_REG_GPIOCNTL7,
|
||||
MAX8997_REG_GPIOCNTL8,
|
||||
MAX8997_REG_GPIOCNTL9,
|
||||
MAX8997_REG_GPIOCNTL10,
|
||||
MAX8997_REG_GPIOCNTL11,
|
||||
MAX8997_REG_GPIOCNTL12,
|
||||
|
||||
MAX8997_REG_LDO1CONFIG,
|
||||
MAX8997_REG_LDO2CONFIG,
|
||||
MAX8997_REG_LDO3CONFIG,
|
||||
MAX8997_REG_LDO4CONFIG,
|
||||
MAX8997_REG_LDO5CONFIG,
|
||||
MAX8997_REG_LDO6CONFIG,
|
||||
MAX8997_REG_LDO7CONFIG,
|
||||
MAX8997_REG_LDO8CONFIG,
|
||||
MAX8997_REG_LDO9CONFIG,
|
||||
MAX8997_REG_LDO10CONFIG,
|
||||
MAX8997_REG_LDO11CONFIG,
|
||||
MAX8997_REG_LDO12CONFIG,
|
||||
MAX8997_REG_LDO13CONFIG,
|
||||
MAX8997_REG_LDO14CONFIG,
|
||||
MAX8997_REG_LDO15CONFIG,
|
||||
MAX8997_REG_LDO16CONFIG,
|
||||
MAX8997_REG_LDO17CONFIG,
|
||||
MAX8997_REG_LDO18CONFIG,
|
||||
MAX8997_REG_LDO21CONFIG,
|
||||
|
||||
MAX8997_REG_DVSOKTIMER1,
|
||||
MAX8997_REG_DVSOKTIMER2,
|
||||
MAX8997_REG_DVSOKTIMER4,
|
||||
MAX8997_REG_DVSOKTIMER5,
|
||||
};
|
||||
|
||||
u8 max8997_dumpaddr_muic[] = {
|
||||
MAX8997_MUIC_REG_INTMASK1,
|
||||
MAX8997_MUIC_REG_INTMASK2,
|
||||
MAX8997_MUIC_REG_INTMASK3,
|
||||
MAX8997_MUIC_REG_CDETCTRL,
|
||||
MAX8997_MUIC_REG_CONTROL1,
|
||||
MAX8997_MUIC_REG_CONTROL2,
|
||||
MAX8997_MUIC_REG_CONTROL3,
|
||||
};
|
||||
|
||||
u8 max8997_dumpaddr_haptic[] = {
|
||||
MAX8997_HAPTIC_REG_CONF1,
|
||||
MAX8997_HAPTIC_REG_CONF2,
|
||||
MAX8997_HAPTIC_REG_DRVCONF,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF1,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF2,
|
||||
MAX8997_HAPTIC_REG_SIGCONF1,
|
||||
MAX8997_HAPTIC_REG_SIGCONF2,
|
||||
MAX8997_HAPTIC_REG_SIGCONF3,
|
||||
MAX8997_HAPTIC_REG_SIGCONF4,
|
||||
MAX8997_HAPTIC_REG_SIGDC1,
|
||||
MAX8997_HAPTIC_REG_SIGDC2,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC1,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC2,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC3,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC4,
|
||||
};
|
||||
|
||||
static int max8997_freeze(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)
|
||||
max8997_read_reg(i2c, max8997_dumpaddr_pmic[i],
|
||||
&max8997->reg_dump[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
|
||||
max8997_read_reg(i2c, max8997_dumpaddr_muic[i],
|
||||
&max8997->reg_dump[i + MAX8997_REG_PMIC_END]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)
|
||||
max8997_read_reg(i2c, max8997_dumpaddr_haptic[i],
|
||||
&max8997->reg_dump[i + MAX8997_REG_PMIC_END +
|
||||
MAX8997_MUIC_REG_END]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max8997_restore(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)
|
||||
max8997_write_reg(i2c, max8997_dumpaddr_pmic[i],
|
||||
max8997->reg_dump[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
|
||||
max8997_write_reg(i2c, max8997_dumpaddr_muic[i],
|
||||
max8997->reg_dump[i + MAX8997_REG_PMIC_END]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)
|
||||
max8997_write_reg(i2c, max8997_dumpaddr_haptic[i],
|
||||
max8997->reg_dump[i + MAX8997_REG_PMIC_END +
|
||||
MAX8997_MUIC_REG_END]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops max8997_pm = {
|
||||
.freeze = max8997_freeze,
|
||||
.restore = max8997_restore,
|
||||
};
|
||||
|
||||
static struct i2c_driver max8997_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max8997",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &max8997_pm,
|
||||
},
|
||||
.probe = max8997_i2c_probe,
|
||||
.remove = max8997_i2c_remove,
|
||||
.id_table = max8997_i2c_id,
|
||||
};
|
||||
|
||||
static int __init max8997_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max8997_i2c_driver);
|
||||
}
|
||||
/* init early so consumer devices can complete system boot */
|
||||
subsys_initcall(max8997_i2c_init);
|
||||
|
||||
static void __exit max8997_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max8997_i2c_driver);
|
||||
}
|
||||
module_exit(max8997_i2c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 8997 multi-function core driver");
|
||||
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -233,7 +233,7 @@ struct max8998_reg_dump {
|
||||
u8 val;
|
||||
};
|
||||
#define SAVE_ITEM(x) { .addr = (x), .val = 0x0, }
|
||||
struct max8998_reg_dump max8998_dump[] = {
|
||||
static struct max8998_reg_dump max8998_dump[] = {
|
||||
SAVE_ITEM(MAX8998_REG_IRQM1),
|
||||
SAVE_ITEM(MAX8998_REG_IRQM2),
|
||||
SAVE_ITEM(MAX8998_REG_IRQM3),
|
||||
@ -298,7 +298,7 @@ static int max8998_restore(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops max8998_pm = {
|
||||
static const struct dev_pm_ops max8998_pm = {
|
||||
.suspend = max8998_suspend,
|
||||
.resume = max8998_resume,
|
||||
.freeze = max8998_freeze,
|
||||
|
@ -683,14 +683,13 @@ out:
|
||||
EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
|
||||
|
||||
static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
|
||||
const char *format, void *pdata, size_t pdata_size)
|
||||
const char *format, void *pdata)
|
||||
{
|
||||
char buf[30];
|
||||
const char *name = mc13xxx_get_chipname(mc13xxx);
|
||||
|
||||
struct mfd_cell cell = {
|
||||
.platform_data = pdata,
|
||||
.data_size = pdata_size,
|
||||
.mfd_data = pdata,
|
||||
};
|
||||
|
||||
/* there is no asnprintf in the kernel :-( */
|
||||
@ -706,7 +705,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
|
||||
|
||||
static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
|
||||
{
|
||||
return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
|
||||
return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL);
|
||||
}
|
||||
|
||||
static int mc13xxx_probe(struct spi_device *spi)
|
||||
@ -764,13 +763,8 @@ err_revision:
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
|
||||
|
||||
if (pdata->flags & MC13XXX_USE_REGULATOR) {
|
||||
struct mc13xxx_regulator_platform_data regulator_pdata = {
|
||||
.num_regulators = pdata->num_regulators,
|
||||
.regulators = pdata->regulators,
|
||||
};
|
||||
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
|
||||
®ulator_pdata, sizeof(regulator_pdata));
|
||||
&pdata->regulators);
|
||||
}
|
||||
|
||||
if (pdata->flags & MC13XXX_USE_RTC)
|
||||
@ -779,10 +773,8 @@ err_revision:
|
||||
if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-ts");
|
||||
|
||||
if (pdata->flags & MC13XXX_USE_LED) {
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
|
||||
pdata->leds, sizeof(*pdata->leds));
|
||||
}
|
||||
if (pdata->flags & MC13XXX_USE_LED)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -811,6 +803,7 @@ static const struct spi_device_id mc13xxx_device_id[] = {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
|
||||
|
||||
static struct spi_driver mc13xxx_driver = {
|
||||
.id_table = mc13xxx_device_id,
|
||||
|
@ -18,6 +18,43 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
int mfd_cell_enable(struct platform_device *pdev)
|
||||
{
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
int err = 0;
|
||||
|
||||
/* only call enable hook if the cell wasn't previously enabled */
|
||||
if (atomic_inc_return(cell->usage_count) == 1)
|
||||
err = cell->enable(pdev);
|
||||
|
||||
/* if the enable hook failed, decrement counter to allow retries */
|
||||
if (err)
|
||||
atomic_dec(cell->usage_count);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mfd_cell_enable);
|
||||
|
||||
int mfd_cell_disable(struct platform_device *pdev)
|
||||
{
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
int err = 0;
|
||||
|
||||
/* only disable if no other clients are using it */
|
||||
if (atomic_dec_return(cell->usage_count) == 0)
|
||||
err = cell->disable(pdev);
|
||||
|
||||
/* if the disable hook failed, increment to allow retries */
|
||||
if (err)
|
||||
atomic_inc(cell->usage_count);
|
||||
|
||||
/* sanity check; did someone call disable too many times? */
|
||||
WARN_ON(atomic_read(cell->usage_count) < 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mfd_cell_disable);
|
||||
|
||||
static int mfd_add_device(struct device *parent, int id,
|
||||
const struct mfd_cell *cell,
|
||||
struct resource *mem_base,
|
||||
@ -37,14 +74,10 @@ static int mfd_add_device(struct device *parent, int id,
|
||||
goto fail_device;
|
||||
|
||||
pdev->dev.parent = parent;
|
||||
platform_set_drvdata(pdev, cell->driver_data);
|
||||
|
||||
if (cell->data_size) {
|
||||
ret = platform_device_add_data(pdev,
|
||||
cell->platform_data, cell->data_size);
|
||||
if (ret)
|
||||
goto fail_res;
|
||||
}
|
||||
ret = platform_device_add_data(pdev, cell, sizeof(*cell));
|
||||
if (ret)
|
||||
goto fail_res;
|
||||
|
||||
for (r = 0; r < cell->num_resources; r++) {
|
||||
res[r].name = cell->resources[r].name;
|
||||
@ -100,14 +133,22 @@ fail_alloc:
|
||||
}
|
||||
|
||||
int mfd_add_devices(struct device *parent, int id,
|
||||
const struct mfd_cell *cells, int n_devs,
|
||||
struct mfd_cell *cells, int n_devs,
|
||||
struct resource *mem_base,
|
||||
int irq_base)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
atomic_t *cnts;
|
||||
|
||||
/* initialize reference counting for all cells */
|
||||
cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
|
||||
if (!cnts)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < n_devs; i++) {
|
||||
atomic_set(&cnts[i], 0);
|
||||
cells[i].usage_count = &cnts[i];
|
||||
ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base);
|
||||
if (ret)
|
||||
break;
|
||||
@ -120,17 +161,89 @@ int mfd_add_devices(struct device *parent, int id,
|
||||
}
|
||||
EXPORT_SYMBOL(mfd_add_devices);
|
||||
|
||||
static int mfd_remove_devices_fn(struct device *dev, void *unused)
|
||||
static int mfd_remove_devices_fn(struct device *dev, void *c)
|
||||
{
|
||||
platform_device_unregister(to_platform_device(dev));
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
atomic_t **usage_count = c;
|
||||
|
||||
/* find the base address of usage_count pointers (for freeing) */
|
||||
if (!*usage_count || (cell->usage_count < *usage_count))
|
||||
*usage_count = cell->usage_count;
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mfd_remove_devices(struct device *parent)
|
||||
{
|
||||
device_for_each_child(parent, NULL, mfd_remove_devices_fn);
|
||||
atomic_t *cnts = NULL;
|
||||
|
||||
device_for_each_child(parent, &cnts, mfd_remove_devices_fn);
|
||||
kfree(cnts);
|
||||
}
|
||||
EXPORT_SYMBOL(mfd_remove_devices);
|
||||
|
||||
static int add_shared_platform_device(const char *cell, const char *name)
|
||||
{
|
||||
struct mfd_cell cell_entry;
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
int err;
|
||||
|
||||
/* check if we've already registered a device (don't fail if we have) */
|
||||
if (bus_find_device_by_name(&platform_bus_type, NULL, name))
|
||||
return 0;
|
||||
|
||||
/* fetch the parent cell's device (should already be registered!) */
|
||||
dev = bus_find_device_by_name(&platform_bus_type, NULL, cell);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR "failed to find device for cell %s\n", cell);
|
||||
return -ENODEV;
|
||||
}
|
||||
pdev = to_platform_device(dev);
|
||||
memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry));
|
||||
|
||||
WARN_ON(!cell_entry.enable);
|
||||
|
||||
cell_entry.name = name;
|
||||
err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0);
|
||||
if (err)
|
||||
dev_err(dev, "MFD add devices failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int mfd_shared_platform_driver_register(struct platform_driver *drv,
|
||||
const char *cellname)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = add_shared_platform_device(cellname, drv->driver.name);
|
||||
if (err)
|
||||
printk(KERN_ERR "failed to add platform device %s\n",
|
||||
drv->driver.name);
|
||||
|
||||
err = platform_driver_register(drv);
|
||||
if (err)
|
||||
printk(KERN_ERR "failed to add platform driver %s\n",
|
||||
drv->driver.name);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mfd_shared_platform_driver_register);
|
||||
|
||||
void mfd_shared_platform_driver_unregister(struct platform_driver *drv)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = bus_find_device_by_name(&platform_bus_type, NULL,
|
||||
drv->driver.name);
|
||||
if (dev)
|
||||
platform_device_unregister(to_platform_device(dev));
|
||||
|
||||
platform_driver_unregister(drv);
|
||||
}
|
||||
EXPORT_SYMBOL(mfd_shared_platform_driver_unregister);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mfd/pcf50633/core.h>
|
||||
@ -230,27 +231,26 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pcf50633_suspend(struct device *dev)
|
||||
{
|
||||
struct pcf50633 *pcf;
|
||||
pcf = i2c_get_clientdata(client);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf50633 *pcf = i2c_get_clientdata(client);
|
||||
|
||||
return pcf50633_irq_suspend(pcf);
|
||||
}
|
||||
|
||||
static int pcf50633_resume(struct i2c_client *client)
|
||||
static int pcf50633_resume(struct device *dev)
|
||||
{
|
||||
struct pcf50633 *pcf;
|
||||
pcf = i2c_get_clientdata(client);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf50633 *pcf = i2c_get_clientdata(client);
|
||||
|
||||
return pcf50633_irq_resume(pcf);
|
||||
}
|
||||
#else
|
||||
#define pcf50633_suspend NULL
|
||||
#define pcf50633_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume);
|
||||
|
||||
static int __devinit pcf50633_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *ids)
|
||||
{
|
||||
@ -360,16 +360,16 @@ static struct i2c_device_id pcf50633_id_table[] = {
|
||||
{"pcf50633", 0x73},
|
||||
{/* end of list */}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf50633_id_table);
|
||||
|
||||
static struct i2c_driver pcf50633_driver = {
|
||||
.driver = {
|
||||
.name = "pcf50633",
|
||||
.pm = &pcf50633_pm,
|
||||
},
|
||||
.id_table = pcf50633_id_table,
|
||||
.probe = pcf50633_probe,
|
||||
.remove = __devexit_p(pcf50633_remove),
|
||||
.suspend = pcf50633_suspend,
|
||||
.resume = pcf50633_resume,
|
||||
};
|
||||
|
||||
static int __init pcf50633_init(void)
|
||||
|
@ -61,12 +61,12 @@ static struct mfd_cell rdc321x_sb_cells[] = {
|
||||
.name = "rdc321x-wdt",
|
||||
.resources = rdc321x_wdt_resource,
|
||||
.num_resources = ARRAY_SIZE(rdc321x_wdt_resource),
|
||||
.driver_data = &rdc321x_wdt_pdata,
|
||||
.mfd_data = &rdc321x_wdt_pdata,
|
||||
}, {
|
||||
.name = "rdc321x-gpio",
|
||||
.resources = rdc321x_gpio_resources,
|
||||
.num_resources = ARRAY_SIZE(rdc321x_gpio_resources),
|
||||
.driver_data = &rdc321x_gpio_pdata,
|
||||
.mfd_data = &rdc321x_gpio_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -146,9 +146,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
|
||||
priv->cell_mmc.driver_data = mmc_data;
|
||||
priv->cell_mmc.platform_data = &priv->cell_mmc;
|
||||
priv->cell_mmc.data_size = sizeof(priv->cell_mmc);
|
||||
priv->cell_mmc.mfd_data = mmc_data;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
|
@ -170,7 +170,7 @@ static struct mfd_cell t7l66xb_cells[] = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = t7l66xb_mmc_enable,
|
||||
.disable = t7l66xb_mmc_disable,
|
||||
.driver_data = &t7166xb_mmc_data,
|
||||
.mfd_data = &t7166xb_mmc_data,
|
||||
.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
|
||||
.resources = t7l66xb_mmc_resources,
|
||||
},
|
||||
@ -383,16 +383,7 @@ static int t7l66xb_probe(struct platform_device *dev)
|
||||
|
||||
t7l66xb_attach_irq(dev);
|
||||
|
||||
t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data;
|
||||
t7l66xb_cells[T7L66XB_CELL_NAND].platform_data =
|
||||
&t7l66xb_cells[T7L66XB_CELL_NAND];
|
||||
t7l66xb_cells[T7L66XB_CELL_NAND].data_size =
|
||||
sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]);
|
||||
|
||||
t7l66xb_cells[T7L66XB_CELL_MMC].platform_data =
|
||||
&t7l66xb_cells[T7L66XB_CELL_MMC];
|
||||
t7l66xb_cells[T7L66XB_CELL_MMC].data_size =
|
||||
sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]);
|
||||
t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data;
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, dev->id,
|
||||
t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
|
||||
|
@ -131,7 +131,7 @@ static struct mfd_cell tc6387xb_cells[] = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = tc6387xb_mmc_enable,
|
||||
.disable = tc6387xb_mmc_disable,
|
||||
.driver_data = &tc6387xb_mmc_data,
|
||||
.mfd_data = &tc6387xb_mmc_data,
|
||||
.num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
|
||||
.resources = tc6387xb_mmc_resources,
|
||||
},
|
||||
@ -190,11 +190,6 @@ static int __devinit tc6387xb_probe(struct platform_device *dev)
|
||||
|
||||
printk(KERN_INFO "Toshiba tc6387xb initialised\n");
|
||||
|
||||
tc6387xb_cells[TC6387XB_CELL_MMC].platform_data =
|
||||
&tc6387xb_cells[TC6387XB_CELL_MMC];
|
||||
tc6387xb_cells[TC6387XB_CELL_MMC].data_size =
|
||||
sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]);
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells,
|
||||
ARRAY_SIZE(tc6387xb_cells), iomem, irq);
|
||||
|
||||
|
@ -393,7 +393,7 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = tc6393xb_mmc_enable,
|
||||
.resume = tc6393xb_mmc_resume,
|
||||
.driver_data = &tc6393xb_mmc_data,
|
||||
.mfd_data = &tc6393xb_mmc_data,
|
||||
.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
|
||||
.resources = tc6393xb_mmc_resources,
|
||||
},
|
||||
@ -693,27 +693,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
|
||||
goto err_setup;
|
||||
}
|
||||
|
||||
tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data;
|
||||
tc6393xb_cells[TC6393XB_CELL_NAND].platform_data =
|
||||
&tc6393xb_cells[TC6393XB_CELL_NAND];
|
||||
tc6393xb_cells[TC6393XB_CELL_NAND].data_size =
|
||||
sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]);
|
||||
|
||||
tc6393xb_cells[TC6393XB_CELL_MMC].platform_data =
|
||||
&tc6393xb_cells[TC6393XB_CELL_MMC];
|
||||
tc6393xb_cells[TC6393XB_CELL_MMC].data_size =
|
||||
sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]);
|
||||
|
||||
tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data =
|
||||
&tc6393xb_cells[TC6393XB_CELL_OHCI];
|
||||
tc6393xb_cells[TC6393XB_CELL_OHCI].data_size =
|
||||
sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]);
|
||||
|
||||
tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data;
|
||||
tc6393xb_cells[TC6393XB_CELL_FB].platform_data =
|
||||
&tc6393xb_cells[TC6393XB_CELL_FB];
|
||||
tc6393xb_cells[TC6393XB_CELL_FB].data_size =
|
||||
sizeof(tc6393xb_cells[TC6393XB_CELL_FB]);
|
||||
tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data;
|
||||
tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data;
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, dev->id,
|
||||
tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
|
||||
|
@ -384,8 +384,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.data_size = sizeof(timb_dma_platform_data),
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -396,43 +395,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
|
||||
.name = "xiic-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
|
||||
.resources = timberdale_xiic_resources,
|
||||
.platform_data = &timberdale_xiic_platform_data,
|
||||
.data_size = sizeof(timberdale_xiic_platform_data),
|
||||
.mfd_data = &timberdale_xiic_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.data_size = sizeof(timberdale_gpio_platform_data),
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.data_size = sizeof(timberdale_video_platform_data),
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.data_size = sizeof(timberdale_radio_platform_data),
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.data_size = sizeof(timberdale_xspi_platform_data),
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "ks8842",
|
||||
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
|
||||
.resources = timberdale_eth_resources,
|
||||
.platform_data = &timberdale_ks8842_platform_data,
|
||||
.data_size = sizeof(timberdale_ks8842_platform_data)
|
||||
.mfd_data = &timberdale_ks8842_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
@ -441,8 +434,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.data_size = sizeof(timb_dma_platform_data),
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -458,15 +450,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
|
||||
.name = "xiic-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
|
||||
.resources = timberdale_xiic_resources,
|
||||
.platform_data = &timberdale_xiic_platform_data,
|
||||
.data_size = sizeof(timberdale_xiic_platform_data),
|
||||
.mfd_data = &timberdale_xiic_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.data_size = sizeof(timberdale_gpio_platform_data),
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-mlogicore",
|
||||
@ -477,29 +467,25 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.data_size = sizeof(timberdale_video_platform_data),
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.data_size = sizeof(timberdale_radio_platform_data),
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.data_size = sizeof(timberdale_xspi_platform_data),
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "ks8842",
|
||||
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
|
||||
.resources = timberdale_eth_resources,
|
||||
.platform_data = &timberdale_ks8842_platform_data,
|
||||
.data_size = sizeof(timberdale_ks8842_platform_data)
|
||||
.mfd_data = &timberdale_ks8842_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
@ -508,8 +494,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.data_size = sizeof(timb_dma_platform_data),
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -520,36 +505,31 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
|
||||
.name = "xiic-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
|
||||
.resources = timberdale_xiic_resources,
|
||||
.platform_data = &timberdale_xiic_platform_data,
|
||||
.data_size = sizeof(timberdale_xiic_platform_data),
|
||||
.mfd_data = &timberdale_xiic_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.data_size = sizeof(timberdale_gpio_platform_data),
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.data_size = sizeof(timberdale_video_platform_data),
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.data_size = sizeof(timberdale_radio_platform_data),
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.data_size = sizeof(timberdale_xspi_platform_data),
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
@ -558,8 +538,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.data_size = sizeof(timb_dma_platform_data),
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -570,43 +549,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
|
||||
.name = "ocores-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_ocores_resources),
|
||||
.resources = timberdale_ocores_resources,
|
||||
.platform_data = &timberdale_ocores_platform_data,
|
||||
.data_size = sizeof(timberdale_ocores_platform_data),
|
||||
.mfd_data = &timberdale_ocores_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.data_size = sizeof(timberdale_gpio_platform_data),
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.data_size = sizeof(timberdale_video_platform_data),
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.data_size = sizeof(timberdale_radio_platform_data),
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.data_size = sizeof(timberdale_xspi_platform_data),
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
},
|
||||
{
|
||||
.name = "ks8842",
|
||||
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
|
||||
.resources = timberdale_eth_resources,
|
||||
.platform_data = &timberdale_ks8842_platform_data,
|
||||
.data_size = sizeof(timberdale_ks8842_platform_data)
|
||||
.mfd_data = &timberdale_ks8842_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
|
246
drivers/mfd/tps6105x.c
Normal file
246
drivers/mfd/tps6105x.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Core driver for TPS61050/61052 boost converters, used for while LED
|
||||
* driving, audio power amplification, white LED flash, and generic
|
||||
* boost conversion. Additionally it provides a 1-bit GPIO pin (out or in)
|
||||
* and a flash synchronization pin to synchronize flash events when used as
|
||||
* flashgun.
|
||||
*
|
||||
* Copyright (C) 2011 ST-Ericsson SA
|
||||
* Written on behalf of Linaro for ST-Ericsson
|
||||
*
|
||||
* Author: Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps6105x.h>
|
||||
|
||||
int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&tps6105x->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value);
|
||||
mutex_unlock(&tps6105x->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tps6105x_set);
|
||||
|
||||
int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&tps6105x->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
|
||||
mutex_unlock(&tps6105x->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*buf = ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tps6105x_get);
|
||||
|
||||
/*
|
||||
* Masks off the bits in the mask and sets the bits in the bitvalues
|
||||
* parameter in one atomic operation
|
||||
*/
|
||||
int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
|
||||
u8 bitmask, u8 bitvalues)
|
||||
{
|
||||
int ret;
|
||||
u8 regval;
|
||||
|
||||
ret = mutex_lock_interruptible(&tps6105x->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
regval = ret;
|
||||
regval = (~bitmask & regval) | (bitmask & bitvalues);
|
||||
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval);
|
||||
fail:
|
||||
mutex_unlock(&tps6105x->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tps6105x_mask_and_set);
|
||||
|
||||
static int __devinit tps6105x_startup(struct tps6105x *tps6105x)
|
||||
{
|
||||
int ret;
|
||||
u8 regval;
|
||||
|
||||
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
|
||||
case TPS6105X_REG0_MODE_SHUTDOWN:
|
||||
dev_info(&tps6105x->client->dev,
|
||||
"TPS6105x found in SHUTDOWN mode\n");
|
||||
break;
|
||||
case TPS6105X_REG0_MODE_TORCH:
|
||||
dev_info(&tps6105x->client->dev,
|
||||
"TPS6105x found in TORCH mode\n");
|
||||
break;
|
||||
case TPS6105X_REG0_MODE_TORCH_FLASH:
|
||||
dev_info(&tps6105x->client->dev,
|
||||
"TPS6105x found in FLASH mode\n");
|
||||
break;
|
||||
case TPS6105X_REG0_MODE_VOLTAGE:
|
||||
dev_info(&tps6105x->client->dev,
|
||||
"TPS6105x found in VOLTAGE mode\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* MFD cells - we have one cell which is selected operation
|
||||
* mode, and we always have a GPIO cell.
|
||||
*/
|
||||
static struct mfd_cell tps6105x_cells[] = {
|
||||
{
|
||||
/* name will be runtime assigned */
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "tps6105x-gpio",
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
||||
static int __devinit tps6105x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tps6105x *tps6105x;
|
||||
struct tps6105x_platform_data *pdata;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
tps6105x = kmalloc(sizeof(*tps6105x), GFP_KERNEL);
|
||||
if (!tps6105x)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, tps6105x);
|
||||
tps6105x->client = client;
|
||||
pdata = client->dev.platform_data;
|
||||
tps6105x->pdata = pdata;
|
||||
mutex_init(&tps6105x->lock);
|
||||
|
||||
ret = tps6105x_startup(tps6105x);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "chip initialization failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Remove warning texts when you implement new cell drivers */
|
||||
switch (pdata->mode) {
|
||||
case TPS6105X_MODE_SHUTDOWN:
|
||||
dev_info(&client->dev,
|
||||
"present, not used for anything, only GPIO\n");
|
||||
break;
|
||||
case TPS6105X_MODE_TORCH:
|
||||
tps6105x_cells[0].name = "tps6105x-leds";
|
||||
dev_warn(&client->dev,
|
||||
"torch mode is unsupported\n");
|
||||
break;
|
||||
case TPS6105X_MODE_TORCH_FLASH:
|
||||
tps6105x_cells[0].name = "tps6105x-flash";
|
||||
dev_warn(&client->dev,
|
||||
"flash mode is unsupported\n");
|
||||
break;
|
||||
case TPS6105X_MODE_VOLTAGE:
|
||||
tps6105x_cells[0].name ="tps6105x-regulator";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set up and register the platform devices. */
|
||||
for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
|
||||
/* One state holder for all drivers, this is simple */
|
||||
tps6105x_cells[i].mfd_data = tps6105x;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
|
||||
ARRAY_SIZE(tps6105x_cells), NULL, 0);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
kfree(tps6105x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tps6105x_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tps6105x *tps6105x = i2c_get_clientdata(client);
|
||||
|
||||
mfd_remove_devices(&client->dev);
|
||||
|
||||
/* Put chip in shutdown mode */
|
||||
tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
|
||||
|
||||
kfree(tps6105x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tps6105x_id[] = {
|
||||
{ "tps61050", 0 },
|
||||
{ "tps61052", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tps6105x_id);
|
||||
|
||||
static struct i2c_driver tps6105x_driver = {
|
||||
.driver = {
|
||||
.name = "tps6105x",
|
||||
},
|
||||
.probe = tps6105x_probe,
|
||||
.remove = __devexit_p(tps6105x_remove),
|
||||
.id_table = tps6105x_id,
|
||||
};
|
||||
|
||||
static int __init tps6105x_init(void)
|
||||
{
|
||||
return i2c_add_driver(&tps6105x_driver);
|
||||
}
|
||||
subsys_initcall(tps6105x_init);
|
||||
|
||||
static void __exit tps6105x_exit(void)
|
||||
{
|
||||
i2c_del_driver(&tps6105x_driver);
|
||||
}
|
||||
module_exit(tps6105x_exit);
|
||||
|
||||
MODULE_AUTHOR("Linus Walleij");
|
||||
MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -288,12 +288,10 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
|
||||
return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask);
|
||||
}
|
||||
|
||||
static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
|
||||
static int tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!gpio_base)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
tps6586x->gpio.owner = THIS_MODULE;
|
||||
tps6586x->gpio.label = tps6586x->client->name;
|
||||
@ -307,9 +305,7 @@ static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
|
||||
tps6586x->gpio.set = tps6586x_gpio_set;
|
||||
tps6586x->gpio.get = tps6586x_gpio_get;
|
||||
|
||||
ret = gpiochip_add(&tps6586x->gpio);
|
||||
if (ret)
|
||||
dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret);
|
||||
return gpiochip_add(&tps6586x->gpio);
|
||||
}
|
||||
|
||||
static int __remove_subdev(struct device *dev, void *unused)
|
||||
@ -517,17 +513,28 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
ret = tps6586x_gpio_init(tps6586x, pdata->gpio_base);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "GPIO registration failed: %d\n", ret);
|
||||
goto err_gpio_init;
|
||||
}
|
||||
|
||||
ret = tps6586x_add_subdevs(tps6586x, pdata);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "add devices failed: %d\n", ret);
|
||||
goto err_add_devs;
|
||||
}
|
||||
|
||||
tps6586x_gpio_init(tps6586x, pdata->gpio_base);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_devs:
|
||||
if (pdata->gpio_base) {
|
||||
ret = gpiochip_remove(&tps6586x->gpio);
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Can't remove gpio chip: %d\n",
|
||||
ret);
|
||||
}
|
||||
err_gpio_init:
|
||||
if (client->irq)
|
||||
free_irq(client->irq, tps6586x);
|
||||
err_irq_init:
|
||||
@ -587,4 +594,3 @@ module_exit(tps6586x_exit);
|
||||
MODULE_DESCRIPTION("TPS6586X core driver");
|
||||
MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
@ -721,13 +721,13 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
|
||||
}
|
||||
|
||||
if (twl_has_watchdog()) {
|
||||
if (twl_has_watchdog() && twl_class_is_4030()) {
|
||||
child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_pwrbutton()) {
|
||||
if (twl_has_pwrbutton() && twl_class_is_4030()) {
|
||||
child = add_child(1, "twl4030_pwrbutton",
|
||||
NULL, 0, true, pdata->irq_base + 8 + 0, 0);
|
||||
if (IS_ERR(child))
|
||||
@ -864,6 +864,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_bci() && pdata->bci &&
|
||||
|
@ -208,15 +208,13 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
||||
if (pdata->audio) {
|
||||
cell = &codec->cells[childs];
|
||||
cell->name = "twl4030-codec";
|
||||
cell->platform_data = pdata->audio;
|
||||
cell->data_size = sizeof(*pdata->audio);
|
||||
cell->mfd_data = pdata->audio;
|
||||
childs++;
|
||||
}
|
||||
if (pdata->vibra) {
|
||||
cell = &codec->cells[childs];
|
||||
cell->name = "twl4030-vibra";
|
||||
cell->platform_data = pdata->vibra;
|
||||
cell->data_size = sizeof(*pdata->vibra);
|
||||
cell->mfd_data = pdata->vibra;
|
||||
childs++;
|
||||
}
|
||||
|
||||
|
802
drivers/mfd/twl4030-madc.c
Normal file
802
drivers/mfd/twl4030-madc.c
Normal file
@ -0,0 +1,802 @@
|
||||
/*
|
||||
*
|
||||
* TWL4030 MADC module driver-This driver monitors the real time
|
||||
* conversion of analog signals like battery temperature,
|
||||
* battery type, battery level etc.
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* J Keerthy <j-keerthy@ti.com>
|
||||
*
|
||||
* Based on twl4030-madc.c
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Mikko Ylinen <mikko.k.ylinen@nokia.com>
|
||||
*
|
||||
* Amit Kucheria <amit.kucheria@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/i2c/twl4030-madc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
/*
|
||||
* struct twl4030_madc_data - a container for madc info
|
||||
* @dev - pointer to device structure for madc
|
||||
* @lock - mutex protecting this data structure
|
||||
* @requests - Array of request struct corresponding to SW1, SW2 and RT
|
||||
* @imr - Interrupt mask register of MADC
|
||||
* @isr - Interrupt status register of MADC
|
||||
*/
|
||||
struct twl4030_madc_data {
|
||||
struct device *dev;
|
||||
struct mutex lock; /* mutex protecting this data structure */
|
||||
struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
|
||||
int imr;
|
||||
int isr;
|
||||
};
|
||||
|
||||
static struct twl4030_madc_data *twl4030_madc;
|
||||
|
||||
struct twl4030_prescale_divider_ratios {
|
||||
s16 numerator;
|
||||
s16 denominator;
|
||||
};
|
||||
|
||||
static const struct twl4030_prescale_divider_ratios
|
||||
twl4030_divider_ratios[16] = {
|
||||
{1, 1}, /* CHANNEL 0 No Prescaler */
|
||||
{1, 1}, /* CHANNEL 1 No Prescaler */
|
||||
{6, 10}, /* CHANNEL 2 */
|
||||
{6, 10}, /* CHANNEL 3 */
|
||||
{6, 10}, /* CHANNEL 4 */
|
||||
{6, 10}, /* CHANNEL 5 */
|
||||
{6, 10}, /* CHANNEL 6 */
|
||||
{6, 10}, /* CHANNEL 7 */
|
||||
{3, 14}, /* CHANNEL 8 */
|
||||
{1, 3}, /* CHANNEL 9 */
|
||||
{1, 1}, /* CHANNEL 10 No Prescaler */
|
||||
{15, 100}, /* CHANNEL 11 */
|
||||
{1, 4}, /* CHANNEL 12 */
|
||||
{1, 1}, /* CHANNEL 13 Reserved channels */
|
||||
{1, 1}, /* CHANNEL 14 Reseved channels */
|
||||
{5, 11}, /* CHANNEL 15 */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Conversion table from -3 to 55 degree Celcius
|
||||
*/
|
||||
static int therm_tbl[] = {
|
||||
30800, 29500, 28300, 27100,
|
||||
26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
|
||||
17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
|
||||
11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
|
||||
8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
|
||||
5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
|
||||
4040, 3910, 3790, 3670, 3550
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure containing the registers
|
||||
* of different conversion methods supported by MADC.
|
||||
* Hardware or RT real time conversion request initiated by external host
|
||||
* processor for RT Signal conversions.
|
||||
* External host processors can also request for non RT conversions
|
||||
* SW1 and SW2 software conversions also called asynchronous or GPC request.
|
||||
*/
|
||||
static
|
||||
const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
|
||||
[TWL4030_MADC_RT] = {
|
||||
.sel = TWL4030_MADC_RTSELECT_LSB,
|
||||
.avg = TWL4030_MADC_RTAVERAGE_LSB,
|
||||
.rbase = TWL4030_MADC_RTCH0_LSB,
|
||||
},
|
||||
[TWL4030_MADC_SW1] = {
|
||||
.sel = TWL4030_MADC_SW1SELECT_LSB,
|
||||
.avg = TWL4030_MADC_SW1AVERAGE_LSB,
|
||||
.rbase = TWL4030_MADC_GPCH0_LSB,
|
||||
.ctrl = TWL4030_MADC_CTRL_SW1,
|
||||
},
|
||||
[TWL4030_MADC_SW2] = {
|
||||
.sel = TWL4030_MADC_SW2SELECT_LSB,
|
||||
.avg = TWL4030_MADC_SW2AVERAGE_LSB,
|
||||
.rbase = TWL4030_MADC_GPCH0_LSB,
|
||||
.ctrl = TWL4030_MADC_CTRL_SW2,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Function to read a particular channel value.
|
||||
* @madc - pointer to struct twl4030_madc_data
|
||||
* @reg - lsb of ADC Channel
|
||||
* If the i2c read fails it returns an error else returns 0.
|
||||
*/
|
||||
static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
|
||||
{
|
||||
u8 msb, lsb;
|
||||
int ret;
|
||||
/*
|
||||
* For each ADC channel, we have MSB and LSB register pair. MSB address
|
||||
* is always LSB address+1. reg parameter is the address of LSB register
|
||||
*/
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read MSB register 0x%X\n",
|
||||
reg + 1);
|
||||
return ret;
|
||||
}
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (int)(((msb << 8) | lsb) >> 6);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return battery temperature
|
||||
* Or < 0 on failure.
|
||||
*/
|
||||
static int twl4030battery_temperature(int raw_volt)
|
||||
{
|
||||
u8 val;
|
||||
int temp, curr, volt, res, ret;
|
||||
|
||||
volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
|
||||
/* Getting and calculating the supply current in micro ampers */
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
|
||||
REG_BCICTL2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
|
||||
/* Getting and calculating the thermistor resistance in ohms */
|
||||
res = volt * 1000 / curr;
|
||||
/* calculating temperature */
|
||||
for (temp = 58; temp >= 0; temp--) {
|
||||
int actual = therm_tbl[temp];
|
||||
|
||||
if ((actual - res) >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return temp + 1;
|
||||
}
|
||||
|
||||
static int twl4030battery_current(int raw_volt)
|
||||
{
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
|
||||
TWL4030_BCI_BCICTL1);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
|
||||
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
|
||||
else /* slope of 0.88 mV/mA */
|
||||
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
|
||||
}
|
||||
/*
|
||||
* Function to read channel values
|
||||
* @madc - pointer to twl4030_madc_data struct
|
||||
* @reg_base - Base address of the first channel
|
||||
* @Channels - 16 bit bitmap. If the bit is set, channel value is read
|
||||
* @buf - The channel values are stored here. if read fails error
|
||||
* value is stored
|
||||
* Returns the number of successfully read channels.
|
||||
*/
|
||||
static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
|
||||
u8 reg_base, unsigned
|
||||
long channels, int *buf)
|
||||
{
|
||||
int count = 0, count_req = 0, i;
|
||||
u8 reg;
|
||||
|
||||
for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
|
||||
reg = reg_base + 2 * i;
|
||||
buf[i] = twl4030_madc_channel_raw_read(madc, reg);
|
||||
if (buf[i] < 0) {
|
||||
dev_err(madc->dev,
|
||||
"Unable to read register 0x%X\n", reg);
|
||||
count_req++;
|
||||
continue;
|
||||
}
|
||||
switch (i) {
|
||||
case 10:
|
||||
buf[i] = twl4030battery_current(buf[i]);
|
||||
if (buf[i] < 0) {
|
||||
dev_err(madc->dev, "err reading current\n");
|
||||
count_req++;
|
||||
} else {
|
||||
count++;
|
||||
buf[i] = buf[i] - 750;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
buf[i] = twl4030battery_temperature(buf[i]);
|
||||
if (buf[i] < 0) {
|
||||
dev_err(madc->dev, "err reading temperature\n");
|
||||
count_req++;
|
||||
} else {
|
||||
buf[i] -= 3;
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
count++;
|
||||
/* Analog Input (V) = conv_result * step_size / R
|
||||
* conv_result = decimal value of 10-bit conversion
|
||||
* result
|
||||
* step size = 1.5 / (2 ^ 10 -1)
|
||||
* R = Prescaler ratio for input channels.
|
||||
* Result given in mV hence multiplied by 1000.
|
||||
*/
|
||||
buf[i] = (buf[i] * 3 * 1000 *
|
||||
twl4030_divider_ratios[i].denominator)
|
||||
/ (2 * 1023 *
|
||||
twl4030_divider_ratios[i].numerator);
|
||||
}
|
||||
}
|
||||
if (count_req)
|
||||
dev_err(madc->dev, "%d channel conversion failed\n", count_req);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enables irq.
|
||||
* @madc - pointer to twl4030_madc_data struct
|
||||
* @id - irq number to be enabled
|
||||
* can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
|
||||
* corresponding to RT, SW1, SW2 conversion requests.
|
||||
* If the i2c read fails it returns an error else returns 0.
|
||||
*/
|
||||
static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read imr register 0x%X\n",
|
||||
madc->imr);
|
||||
return ret;
|
||||
}
|
||||
val &= ~(1 << id);
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
|
||||
if (ret) {
|
||||
dev_err(madc->dev,
|
||||
"unable to write imr register 0x%X\n", madc->imr);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disables irq.
|
||||
* @madc - pointer to twl4030_madc_data struct
|
||||
* @id - irq number to be disabled
|
||||
* can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
|
||||
* corresponding to RT, SW1, SW2 conversion requests.
|
||||
* Returns error if i2c read/write fails.
|
||||
*/
|
||||
static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read imr register 0x%X\n",
|
||||
madc->imr);
|
||||
return ret;
|
||||
}
|
||||
val |= (1 << id);
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
|
||||
if (ret) {
|
||||
dev_err(madc->dev,
|
||||
"unable to write imr register 0x%X\n", madc->imr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
|
||||
{
|
||||
struct twl4030_madc_data *madc = _madc;
|
||||
const struct twl4030_madc_conversion_method *method;
|
||||
u8 isr_val, imr_val;
|
||||
int i, len, ret;
|
||||
struct twl4030_madc_request *r;
|
||||
|
||||
mutex_lock(&madc->lock);
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read isr register 0x%X\n",
|
||||
madc->isr);
|
||||
goto err_i2c;
|
||||
}
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read imr register 0x%X\n",
|
||||
madc->imr);
|
||||
goto err_i2c;
|
||||
}
|
||||
isr_val &= ~imr_val;
|
||||
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
|
||||
if (!(isr_val & (1 << i)))
|
||||
continue;
|
||||
ret = twl4030_madc_disable_irq(madc, i);
|
||||
if (ret < 0)
|
||||
dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
|
||||
madc->requests[i].result_pending = 1;
|
||||
}
|
||||
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
|
||||
r = &madc->requests[i];
|
||||
/* No pending results for this method, move to next one */
|
||||
if (!r->result_pending)
|
||||
continue;
|
||||
method = &twl4030_conversion_methods[r->method];
|
||||
/* Read results */
|
||||
len = twl4030_madc_read_channels(madc, method->rbase,
|
||||
r->channels, r->rbuf);
|
||||
/* Return results to caller */
|
||||
if (r->func_cb != NULL) {
|
||||
r->func_cb(len, r->channels, r->rbuf);
|
||||
r->func_cb = NULL;
|
||||
}
|
||||
/* Free request */
|
||||
r->result_pending = 0;
|
||||
r->active = 0;
|
||||
}
|
||||
mutex_unlock(&madc->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
||||
err_i2c:
|
||||
/*
|
||||
* In case of error check whichever request is active
|
||||
* and service the same.
|
||||
*/
|
||||
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
|
||||
r = &madc->requests[i];
|
||||
if (r->active == 0)
|
||||
continue;
|
||||
method = &twl4030_conversion_methods[r->method];
|
||||
/* Read results */
|
||||
len = twl4030_madc_read_channels(madc, method->rbase,
|
||||
r->channels, r->rbuf);
|
||||
/* Return results to caller */
|
||||
if (r->func_cb != NULL) {
|
||||
r->func_cb(len, r->channels, r->rbuf);
|
||||
r->func_cb = NULL;
|
||||
}
|
||||
/* Free request */
|
||||
r->result_pending = 0;
|
||||
r->active = 0;
|
||||
}
|
||||
mutex_unlock(&madc->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
|
||||
struct twl4030_madc_request *req)
|
||||
{
|
||||
struct twl4030_madc_request *p;
|
||||
int ret;
|
||||
|
||||
p = &madc->requests[req->method];
|
||||
memcpy(p, req, sizeof(*req));
|
||||
ret = twl4030_madc_enable_irq(madc, req->method);
|
||||
if (ret < 0) {
|
||||
dev_err(madc->dev, "enable irq failed!!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function which enables the madc conversion
|
||||
* by writing to the control register.
|
||||
* @madc - pointer to twl4030_madc_data struct
|
||||
* @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
|
||||
* corresponding to RT SW1 or SW2 conversion methods.
|
||||
* Returns 0 if succeeds else a negative error value
|
||||
*/
|
||||
static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
|
||||
int conv_method)
|
||||
{
|
||||
const struct twl4030_madc_conversion_method *method;
|
||||
int ret = 0;
|
||||
method = &twl4030_conversion_methods[conv_method];
|
||||
switch (conv_method) {
|
||||
case TWL4030_MADC_SW1:
|
||||
case TWL4030_MADC_SW2:
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
|
||||
TWL4030_MADC_SW_START, method->ctrl);
|
||||
if (ret) {
|
||||
dev_err(madc->dev,
|
||||
"unable to write ctrl register 0x%X\n",
|
||||
method->ctrl);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function that waits for conversion to be ready
|
||||
* @madc - pointer to twl4030_madc_data struct
|
||||
* @timeout_ms - timeout value in milliseconds
|
||||
* @status_reg - ctrl register
|
||||
* returns 0 if succeeds else a negative error value
|
||||
*/
|
||||
static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
|
||||
unsigned int timeout_ms,
|
||||
u8 status_reg)
|
||||
{
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
do {
|
||||
u8 reg;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, ®, status_reg);
|
||||
if (ret) {
|
||||
dev_err(madc->dev,
|
||||
"unable to read status register 0x%X\n",
|
||||
status_reg);
|
||||
return ret;
|
||||
}
|
||||
if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
|
||||
return 0;
|
||||
usleep_range(500, 2000);
|
||||
} while (!time_after(jiffies, timeout));
|
||||
dev_err(madc->dev, "conversion timeout!\n");
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* An exported function which can be called from other kernel drivers.
|
||||
* @req twl4030_madc_request structure
|
||||
* req->rbuf will be filled with read values of channels based on the
|
||||
* channel index. If a particular channel reading fails there will
|
||||
* be a negative error value in the corresponding array element.
|
||||
* returns 0 if succeeds else error value
|
||||
*/
|
||||
int twl4030_madc_conversion(struct twl4030_madc_request *req)
|
||||
{
|
||||
const struct twl4030_madc_conversion_method *method;
|
||||
u8 ch_msb, ch_lsb;
|
||||
int ret;
|
||||
|
||||
if (!req)
|
||||
return -EINVAL;
|
||||
mutex_lock(&twl4030_madc->lock);
|
||||
if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* Do we have a conversion request ongoing */
|
||||
if (twl4030_madc->requests[req->method].active) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
ch_msb = (req->channels >> 8) & 0xff;
|
||||
ch_lsb = req->channels & 0xff;
|
||||
method = &twl4030_conversion_methods[req->method];
|
||||
/* Select channels to be converted */
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1);
|
||||
if (ret) {
|
||||
dev_err(twl4030_madc->dev,
|
||||
"unable to write sel register 0x%X\n", method->sel + 1);
|
||||
return ret;
|
||||
}
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
|
||||
if (ret) {
|
||||
dev_err(twl4030_madc->dev,
|
||||
"unable to write sel register 0x%X\n", method->sel + 1);
|
||||
return ret;
|
||||
}
|
||||
/* Select averaging for all channels if do_avg is set */
|
||||
if (req->do_avg) {
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
|
||||
ch_msb, method->avg + 1);
|
||||
if (ret) {
|
||||
dev_err(twl4030_madc->dev,
|
||||
"unable to write avg register 0x%X\n",
|
||||
method->avg + 1);
|
||||
return ret;
|
||||
}
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
|
||||
ch_lsb, method->avg);
|
||||
if (ret) {
|
||||
dev_err(twl4030_madc->dev,
|
||||
"unable to write sel reg 0x%X\n",
|
||||
method->sel + 1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
|
||||
ret = twl4030_madc_set_irq(twl4030_madc, req);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
twl4030_madc->requests[req->method].active = 1;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
/* With RT method we should not be here anymore */
|
||||
if (req->method == TWL4030_MADC_RT) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
twl4030_madc->requests[req->method].active = 1;
|
||||
/* Wait until conversion is ready (ctrl register returns EOC) */
|
||||
ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
|
||||
if (ret) {
|
||||
twl4030_madc->requests[req->method].active = 0;
|
||||
goto out;
|
||||
}
|
||||
ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
|
||||
req->channels, req->rbuf);
|
||||
twl4030_madc->requests[req->method].active = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&twl4030_madc->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
|
||||
|
||||
/*
|
||||
* Return channel value
|
||||
* Or < 0 on failure.
|
||||
*/
|
||||
int twl4030_get_madc_conversion(int channel_no)
|
||||
{
|
||||
struct twl4030_madc_request req;
|
||||
int temp = 0;
|
||||
int ret;
|
||||
|
||||
req.channels = (1 << channel_no);
|
||||
req.method = TWL4030_MADC_SW2;
|
||||
req.active = 0;
|
||||
req.func_cb = NULL;
|
||||
ret = twl4030_madc_conversion(&req);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (req.rbuf[channel_no] > 0)
|
||||
temp = req.rbuf[channel_no];
|
||||
|
||||
return temp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
|
||||
|
||||
/*
|
||||
* Function to enable or disable bias current for
|
||||
* main battery type reading or temperature sensing
|
||||
* @madc - pointer to twl4030_madc_data struct
|
||||
* @chan - can be one of the two values
|
||||
* TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
|
||||
* TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
|
||||
* sensing
|
||||
* @on - enable or disable chan.
|
||||
*/
|
||||
static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
|
||||
int chan, int on)
|
||||
{
|
||||
int ret;
|
||||
u8 regval;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
|
||||
®val, TWL4030_BCI_BCICTL1);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
|
||||
TWL4030_BCI_BCICTL1);
|
||||
return ret;
|
||||
}
|
||||
if (on)
|
||||
regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
|
||||
else
|
||||
regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
|
||||
regval, TWL4030_BCI_BCICTL1);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
|
||||
TWL4030_BCI_BCICTL1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function that sets MADC software power on bit to enable MADC
|
||||
* @madc - pointer to twl4030_madc_data struct
|
||||
* @on - Enable or disable MADC software powen on bit.
|
||||
* returns error if i2c read/write fails else 0
|
||||
*/
|
||||
static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
|
||||
{
|
||||
u8 regval;
|
||||
int ret;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
|
||||
®val, TWL4030_MADC_CTRL1);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
|
||||
TWL4030_MADC_CTRL1);
|
||||
return ret;
|
||||
}
|
||||
if (on)
|
||||
regval |= TWL4030_MADC_MADCON;
|
||||
else
|
||||
regval &= ~TWL4030_MADC_MADCON;
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
|
||||
if (ret) {
|
||||
dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
|
||||
TWL4030_MADC_CTRL1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize MADC and request for threaded irq
|
||||
*/
|
||||
static int __devinit twl4030_madc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_madc_data *madc;
|
||||
struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
|
||||
int ret;
|
||||
u8 regval;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "platform_data not available\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
madc = kzalloc(sizeof(*madc), GFP_KERNEL);
|
||||
if (!madc)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Phoenix provides 2 interrupt lines. The first one is connected to
|
||||
* the OMAP. The other one can be connected to the other processor such
|
||||
* as modem. Hence two separate ISR and IMR registers.
|
||||
*/
|
||||
madc->imr = (pdata->irq_line == 1) ?
|
||||
TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
|
||||
madc->isr = (pdata->irq_line == 1) ?
|
||||
TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
|
||||
ret = twl4030_madc_set_power(madc, 1);
|
||||
if (ret < 0)
|
||||
goto err_power;
|
||||
ret = twl4030_madc_set_current_generator(madc, 0, 1);
|
||||
if (ret < 0)
|
||||
goto err_current_generator;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
|
||||
®val, TWL4030_BCI_BCICTL1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
|
||||
TWL4030_BCI_BCICTL1);
|
||||
goto err_i2c;
|
||||
}
|
||||
regval |= TWL4030_BCI_MESBAT;
|
||||
ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
|
||||
regval, TWL4030_BCI_BCICTL1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
|
||||
TWL4030_BCI_BCICTL1);
|
||||
goto err_i2c;
|
||||
}
|
||||
platform_set_drvdata(pdev, madc);
|
||||
mutex_init(&madc->lock);
|
||||
ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
|
||||
twl4030_madc_threaded_irq_handler,
|
||||
IRQF_TRIGGER_RISING, "twl4030_madc", madc);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "could not request irq\n");
|
||||
goto err_irq;
|
||||
}
|
||||
twl4030_madc = madc;
|
||||
return 0;
|
||||
err_irq:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
err_i2c:
|
||||
twl4030_madc_set_current_generator(madc, 0, 0);
|
||||
err_current_generator:
|
||||
twl4030_madc_set_power(madc, 0);
|
||||
err_power:
|
||||
kfree(madc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit twl4030_madc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(platform_get_irq(pdev, 0), madc);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
twl4030_madc_set_current_generator(madc, 0, 0);
|
||||
twl4030_madc_set_power(madc, 0);
|
||||
kfree(madc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl4030_madc_driver = {
|
||||
.probe = twl4030_madc_probe,
|
||||
.remove = __exit_p(twl4030_madc_remove),
|
||||
.driver = {
|
||||
.name = "twl4030_madc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init twl4030_madc_init(void)
|
||||
{
|
||||
return platform_driver_register(&twl4030_madc_driver);
|
||||
}
|
||||
|
||||
module_init(twl4030_madc_init);
|
||||
|
||||
static void __exit twl4030_madc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&twl4030_madc_driver);
|
||||
}
|
||||
|
||||
module_exit(twl4030_madc_exit);
|
||||
|
||||
MODULE_DESCRIPTION("TWL4030 ADC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("J Keerthy");
|
||||
MODULE_ALIAS("platform:twl4030_madc");
|
@ -60,6 +60,7 @@ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x
|
||||
input_report_abs(idev, ABS_X, x);
|
||||
input_report_abs(idev, ABS_Y, y);
|
||||
input_report_abs(idev, ABS_PRESSURE, pressure);
|
||||
input_report_key(idev, BTN_TOUCH, 1);
|
||||
input_sync(idev);
|
||||
}
|
||||
|
||||
@ -68,6 +69,7 @@ static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
|
||||
struct input_dev *idev = ts->idev;
|
||||
|
||||
input_report_abs(idev, ABS_PRESSURE, 0);
|
||||
input_report_key(idev, BTN_TOUCH, 0);
|
||||
input_sync(idev);
|
||||
}
|
||||
|
||||
@ -384,7 +386,8 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
|
||||
idev->open = ucb1x00_ts_open;
|
||||
idev->close = ucb1x00_ts_close;
|
||||
|
||||
__set_bit(EV_ABS, idev->evbit);
|
||||
idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
|
||||
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
|
||||
input_set_drvdata(idev, ts);
|
||||
|
||||
|
@ -122,6 +122,7 @@ static struct pci_device_id vx855_pci_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, vx855_pci_tbl);
|
||||
|
||||
static struct pci_driver vx855_pci_driver = {
|
||||
.name = "vx855",
|
||||
|
@ -38,7 +38,6 @@ static int wl1273_core_remove(struct i2c_client *client)
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
mfd_remove_devices(&client->dev);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
kfree(core);
|
||||
|
||||
return 0;
|
||||
@ -79,8 +78,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
|
||||
|
||||
cell = &core->cells[children];
|
||||
cell->name = "wl1273_fm_radio";
|
||||
cell->platform_data = &core;
|
||||
cell->data_size = sizeof(core);
|
||||
cell->mfd_data = &core;
|
||||
children++;
|
||||
|
||||
if (pdata->children & WL1273_CODEC_CHILD) {
|
||||
@ -88,8 +86,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
|
||||
|
||||
dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
|
||||
cell->name = "wl1273-codec";
|
||||
cell->platform_data = &core;
|
||||
cell->data_size = sizeof(core);
|
||||
cell->mfd_data = &core;
|
||||
children++;
|
||||
}
|
||||
|
||||
@ -104,7 +101,6 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
|
||||
err:
|
||||
i2c_set_clientdata(client, NULL);
|
||||
pdata->free_resources();
|
||||
kfree(core);
|
||||
|
||||
|
@ -51,17 +51,25 @@ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
|
||||
int bytes, void *src)
|
||||
{
|
||||
struct i2c_client *i2c = wm831x->control_data;
|
||||
unsigned char msg[bytes + 2];
|
||||
struct i2c_msg xfer[2];
|
||||
int ret;
|
||||
|
||||
reg = cpu_to_be16(reg);
|
||||
memcpy(&msg[0], ®, 2);
|
||||
memcpy(&msg[2], src, bytes);
|
||||
|
||||
ret = i2c_master_send(i2c, msg, bytes + 2);
|
||||
xfer[0].addr = i2c->addr;
|
||||
xfer[0].flags = 0;
|
||||
xfer[0].len = 2;
|
||||
xfer[0].buf = (char *)®
|
||||
|
||||
xfer[1].addr = i2c->addr;
|
||||
xfer[1].flags = I2C_M_NOSTART;
|
||||
xfer[1].len = bytes;
|
||||
xfer[1].buf = (char *)src;
|
||||
|
||||
ret = i2c_transfer(i2c->adapter, xfer, 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret < bytes + 2)
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
|
@ -26,15 +26,6 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
/*
|
||||
* Since generic IRQs don't currently support interrupt controllers on
|
||||
* interrupt driven buses we don't use genirq but instead provide an
|
||||
* interface that looks very much like the standard ones. This leads
|
||||
* to some bodges, including storing interrupt handler information in
|
||||
* the static irq_data table we use to look up the data for individual
|
||||
* interrupts, but hopefully won't last too long.
|
||||
*/
|
||||
|
||||
struct wm831x_irq_data {
|
||||
int primary;
|
||||
int reg;
|
||||
@ -361,6 +352,10 @@ static void wm831x_irq_sync_unlock(struct irq_data *data)
|
||||
/* If there's been a change in the mask write it back
|
||||
* to the hardware. */
|
||||
if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) {
|
||||
dev_dbg(wm831x->dev, "IRQ mask sync: %x = %x\n",
|
||||
WM831X_INTERRUPT_STATUS_1_MASK + i,
|
||||
wm831x->irq_masks_cur[i]);
|
||||
|
||||
wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i];
|
||||
wm831x_reg_write(wm831x,
|
||||
WM831X_INTERRUPT_STATUS_1_MASK + i,
|
||||
@ -371,7 +366,7 @@ static void wm831x_irq_sync_unlock(struct irq_data *data)
|
||||
mutex_unlock(&wm831x->irq_lock);
|
||||
}
|
||||
|
||||
static void wm831x_irq_unmask(struct irq_data *data)
|
||||
static void wm831x_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
|
||||
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
|
||||
@ -380,7 +375,7 @@ static void wm831x_irq_unmask(struct irq_data *data)
|
||||
wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void wm831x_irq_mask(struct irq_data *data)
|
||||
static void wm831x_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
|
||||
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
|
||||
@ -426,8 +421,8 @@ static struct irq_chip wm831x_irq_chip = {
|
||||
.name = "wm831x",
|
||||
.irq_bus_lock = wm831x_irq_lock,
|
||||
.irq_bus_sync_unlock = wm831x_irq_sync_unlock,
|
||||
.irq_mask = wm831x_irq_mask,
|
||||
.irq_unmask = wm831x_irq_unmask,
|
||||
.irq_disable = wm831x_irq_disable,
|
||||
.irq_enable = wm831x_irq_enable,
|
||||
.irq_set_type = wm831x_irq_set_type,
|
||||
};
|
||||
|
||||
@ -449,6 +444,18 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The touch interrupts are visible in the primary register as
|
||||
* an optimisation; open code this to avoid complicating the
|
||||
* main handling loop and so we can also skip iterating the
|
||||
* descriptors.
|
||||
*/
|
||||
if (primary & WM831X_TCHPD_INT)
|
||||
handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD);
|
||||
if (primary & WM831X_TCHDATA_INT)
|
||||
handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA);
|
||||
if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
|
||||
int offset = wm831x_irqs[i].reg - 1;
|
||||
|
||||
@ -481,6 +488,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
|
||||
}
|
||||
|
||||
out:
|
||||
/* Touchscreen interrupts are handled specially in the driver */
|
||||
status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(status_regs); i++) {
|
||||
if (status_regs[i])
|
||||
wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i,
|
||||
@ -517,6 +527,14 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pdata->irq_cmos)
|
||||
i = 0;
|
||||
else
|
||||
i = WM831X_IRQ_OD;
|
||||
|
||||
wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG,
|
||||
WM831X_IRQ_OD, i);
|
||||
|
||||
/* Try to flag /IRQ as a wake source; there are a number of
|
||||
* unconditional wake sources in the PMIC so this isn't
|
||||
* conditional but we don't actually care *too* much if it
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/mfd/wm831x/core.h>
|
||||
@ -113,22 +114,27 @@ static int __devexit wm831x_spi_remove(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m)
|
||||
static int wm831x_spi_suspend(struct device *dev)
|
||||
{
|
||||
struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
|
||||
struct wm831x *wm831x = dev_get_drvdata(dev);
|
||||
|
||||
return wm831x_device_suspend(wm831x);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops wm831x_spi_pm = {
|
||||
.freeze = wm831x_spi_suspend,
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8310_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8310",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_spi_pm,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8311_spi_driver = {
|
||||
@ -136,10 +142,10 @@ static struct spi_driver wm8311_spi_driver = {
|
||||
.name = "wm8311",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_spi_pm,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8312_spi_driver = {
|
||||
@ -147,10 +153,10 @@ static struct spi_driver wm8312_spi_driver = {
|
||||
.name = "wm8312",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_spi_pm,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8320_spi_driver = {
|
||||
@ -158,10 +164,10 @@ static struct spi_driver wm8320_spi_driver = {
|
||||
.name = "wm8320",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_spi_pm,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8321_spi_driver = {
|
||||
@ -169,10 +175,10 @@ static struct spi_driver wm8321_spi_driver = {
|
||||
.name = "wm8321",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_spi_pm,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8325_spi_driver = {
|
||||
@ -180,10 +186,10 @@ static struct spi_driver wm8325_spi_driver = {
|
||||
.name = "wm8325",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_spi_pm,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8326_spi_driver = {
|
||||
@ -191,10 +197,10 @@ static struct spi_driver wm8326_spi_driver = {
|
||||
.name = "wm8326",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_spi_pm,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static int __init wm831x_spi_init(void)
|
||||
|
@ -245,7 +245,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
|
||||
{
|
||||
struct mfd_cell cell = {
|
||||
.name = "wm8400-codec",
|
||||
.driver_data = wm8400,
|
||||
.mfd_data = wm8400,
|
||||
};
|
||||
|
||||
return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
|
||||
|
@ -40,10 +40,8 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < bytes / 2; i++) {
|
||||
buf[i] = be16_to_cpu(buf[i]);
|
||||
|
||||
dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n",
|
||||
buf[i], reg + i, reg + i);
|
||||
be16_to_cpu(buf[i]), reg + i, reg + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -69,7 +67,7 @@ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
return val;
|
||||
return be16_to_cpu(val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm8994_reg_read);
|
||||
|
||||
@ -79,7 +77,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read);
|
||||
* @wm8994: Device to read from
|
||||
* @reg: First register
|
||||
* @count: Number of registers
|
||||
* @buf: Buffer to fill.
|
||||
* @buf: Buffer to fill. The data will be returned big endian.
|
||||
*/
|
||||
int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
|
||||
int count, u16 *buf)
|
||||
@ -97,9 +95,9 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
|
||||
EXPORT_SYMBOL_GPL(wm8994_bulk_read);
|
||||
|
||||
static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
|
||||
int bytes, void *src)
|
||||
int bytes, const void *src)
|
||||
{
|
||||
u16 *buf = src;
|
||||
const u16 *buf = src;
|
||||
int i;
|
||||
|
||||
BUG_ON(bytes % 2);
|
||||
@ -107,9 +105,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
|
||||
|
||||
for (i = 0; i < bytes / 2; i++) {
|
||||
dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n",
|
||||
buf[i], reg + i, reg + i);
|
||||
|
||||
buf[i] = cpu_to_be16(buf[i]);
|
||||
be16_to_cpu(buf[i]), reg + i, reg + i);
|
||||
}
|
||||
|
||||
return wm8994->write_dev(wm8994, reg, bytes, src);
|
||||
@ -127,6 +123,8 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg,
|
||||
{
|
||||
int ret;
|
||||
|
||||
val = cpu_to_be16(val);
|
||||
|
||||
mutex_lock(&wm8994->io_lock);
|
||||
|
||||
ret = wm8994_write(wm8994, reg, 2, &val);
|
||||
@ -137,6 +135,29 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm8994_reg_write);
|
||||
|
||||
/**
|
||||
* wm8994_bulk_write: Write multiple WM8994 registers
|
||||
*
|
||||
* @wm8994: Device to write to
|
||||
* @reg: First register
|
||||
* @count: Number of registers
|
||||
* @buf: Buffer to write from. Data must be big-endian formatted.
|
||||
*/
|
||||
int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg,
|
||||
int count, const u16 *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&wm8994->io_lock);
|
||||
|
||||
ret = wm8994_write(wm8994, reg, count * 2, buf);
|
||||
|
||||
mutex_unlock(&wm8994->io_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm8994_bulk_write);
|
||||
|
||||
/**
|
||||
* wm8994_set_bits: Set the value of a bitfield in a WM8994 register
|
||||
*
|
||||
@ -157,9 +178,13 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
r = be16_to_cpu(r);
|
||||
|
||||
r &= ~mask;
|
||||
r |= val;
|
||||
|
||||
r = cpu_to_be16(r);
|
||||
|
||||
ret = wm8994_write(wm8994, reg, 2, &r);
|
||||
|
||||
out:
|
||||
@ -271,6 +296,11 @@ static int wm8994_suspend(struct device *dev)
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to save LDO registers: %d\n", ret);
|
||||
|
||||
/* Explicitly put the device into reset in case regulators
|
||||
* don't get disabled in order to ensure consistent restart.
|
||||
*/
|
||||
wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994);
|
||||
|
||||
wm8994->suspended = true;
|
||||
|
||||
ret = regulator_bulk_disable(wm8994->num_supplies,
|
||||
@ -552,25 +582,29 @@ static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Currently we allocate the write buffer on the stack; this is OK for
|
||||
* small writes - if we need to do large writes this will need to be
|
||||
* revised.
|
||||
*/
|
||||
static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg,
|
||||
int bytes, void *src)
|
||||
int bytes, const void *src)
|
||||
{
|
||||
struct i2c_client *i2c = wm8994->control_data;
|
||||
unsigned char msg[bytes + 2];
|
||||
struct i2c_msg xfer[2];
|
||||
int ret;
|
||||
|
||||
reg = cpu_to_be16(reg);
|
||||
memcpy(&msg[0], ®, 2);
|
||||
memcpy(&msg[2], src, bytes);
|
||||
|
||||
ret = i2c_master_send(i2c, msg, bytes + 2);
|
||||
xfer[0].addr = i2c->addr;
|
||||
xfer[0].flags = 0;
|
||||
xfer[0].len = 2;
|
||||
xfer[0].buf = (char *)®
|
||||
|
||||
xfer[1].addr = i2c->addr;
|
||||
xfer[1].flags = I2C_M_NOSTART;
|
||||
xfer[1].len = bytes;
|
||||
xfer[1].buf = (char *)src;
|
||||
|
||||
ret = i2c_transfer(i2c->adapter, xfer, 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret < bytes + 2)
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
@ -612,7 +646,8 @@ static const struct i2c_device_id wm8994_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
|
||||
|
||||
UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL);
|
||||
static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume,
|
||||
NULL);
|
||||
|
||||
static struct i2c_driver wm8994_i2c_driver = {
|
||||
.driver = {
|
||||
|
@ -182,7 +182,7 @@ static void wm8994_irq_sync_unlock(struct irq_data *data)
|
||||
mutex_unlock(&wm8994->irq_lock);
|
||||
}
|
||||
|
||||
static void wm8994_irq_unmask(struct irq_data *data)
|
||||
static void wm8994_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
|
||||
@ -191,7 +191,7 @@ static void wm8994_irq_unmask(struct irq_data *data)
|
||||
wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void wm8994_irq_mask(struct irq_data *data)
|
||||
static void wm8994_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
|
||||
@ -204,8 +204,8 @@ static struct irq_chip wm8994_irq_chip = {
|
||||
.name = "wm8994",
|
||||
.irq_bus_lock = wm8994_irq_lock,
|
||||
.irq_bus_sync_unlock = wm8994_irq_sync_unlock,
|
||||
.irq_mask = wm8994_irq_mask,
|
||||
.irq_unmask = wm8994_irq_unmask,
|
||||
.irq_disable = wm8994_irq_disable,
|
||||
.irq_enable = wm8994_irq_enable,
|
||||
};
|
||||
|
||||
/* The processing of the primary interrupt occurs in a thread so that
|
||||
@ -225,9 +225,11 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Apply masking */
|
||||
for (i = 0; i < WM8994_NUM_IRQ_REGS; i++)
|
||||
/* Bit swap and apply masking */
|
||||
for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) {
|
||||
status[i] = be16_to_cpu(status[i]);
|
||||
status[i] &= ~wm8994->irq_masks_cur[i];
|
||||
}
|
||||
|
||||
/* Report */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
|
||||
|
@ -303,8 +303,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
|
||||
|
||||
static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
|
||||
/*
|
||||
* Testing on sh-mobile showed that SDIO IRQs are unmasked when
|
||||
@ -327,8 +326,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
|
||||
|
||||
static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
@ -669,8 +667,7 @@ out:
|
||||
static irqreturn_t tmio_mmc_irq(int irq, void *devid)
|
||||
{
|
||||
struct tmio_mmc_host *host = devid;
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
unsigned int ireg, irq_mask, status;
|
||||
unsigned int sdio_ireg, sdio_irq_mask, sdio_status;
|
||||
|
||||
@ -799,8 +796,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
|
||||
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
|
||||
struct dma_async_tx_descriptor *desc = NULL;
|
||||
struct dma_chan *chan = host->chan_rx;
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
dma_cookie_t cookie;
|
||||
int ret, i;
|
||||
bool aligned = true, multiple = true;
|
||||
@ -869,8 +865,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
|
||||
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
|
||||
struct dma_async_tx_descriptor *desc = NULL;
|
||||
struct dma_chan *chan = host->chan_tx;
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
dma_cookie_t cookie;
|
||||
int ret, i;
|
||||
bool aligned = true, multiple = true;
|
||||
@ -1063,8 +1058,7 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
|
||||
static int tmio_mmc_start_data(struct tmio_mmc_host *host,
|
||||
struct mmc_data *data)
|
||||
{
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
|
||||
pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n",
|
||||
data->blksz, data->blocks);
|
||||
@ -1169,8 +1163,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
static int tmio_mmc_get_ro(struct mmc_host *mmc)
|
||||
{
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
|
||||
return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
|
||||
(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1;
|
||||
@ -1179,8 +1172,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
|
||||
static int tmio_mmc_get_cd(struct mmc_host *mmc)
|
||||
{
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
struct mfd_cell *cell = host->pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *pdata = cell->driver_data;
|
||||
struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
|
||||
|
||||
if (!pdata->get_cd)
|
||||
return -ENOSYS;
|
||||
@ -1199,7 +1191,7 @@ static const struct mmc_host_ops tmio_mmc_ops = {
|
||||
#ifdef CONFIG_PM
|
||||
static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct mmc_host *mmc = platform_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
@ -1214,7 +1206,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
|
||||
|
||||
static int tmio_mmc_resume(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct mmc_host *mmc = platform_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
@ -1237,7 +1229,7 @@ out:
|
||||
|
||||
static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct tmio_mmc_data *pdata;
|
||||
struct resource *res_ctl;
|
||||
struct tmio_mmc_host *host;
|
||||
@ -1252,7 +1244,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
|
||||
if (!res_ctl)
|
||||
goto out;
|
||||
|
||||
pdata = cell->driver_data;
|
||||
pdata = mfd_get_data(dev);
|
||||
if (!pdata || !pdata->hclk)
|
||||
goto out;
|
||||
|
||||
@ -1352,7 +1344,7 @@ out:
|
||||
|
||||
static int __devexit tmio_mmc_remove(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct mmc_host *mmc = platform_get_drvdata(dev);
|
||||
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
@ -319,7 +319,7 @@ static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
|
||||
static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
|
||||
{
|
||||
struct mfd_cell *cell = dev_get_platdata(&dev->dev);
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
int ret;
|
||||
|
||||
if (cell->enable) {
|
||||
@ -363,7 +363,7 @@ static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
|
||||
|
||||
static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
|
||||
{
|
||||
struct mfd_cell *cell = dev_get_platdata(&dev->dev);
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
|
||||
tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE);
|
||||
if (cell->disable)
|
||||
@ -372,8 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
|
||||
|
||||
static int tmio_probe(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev_get_platdata(&dev->dev);
|
||||
struct tmio_nand_data *data = cell->driver_data;
|
||||
struct tmio_nand_data *data = mfd_get_data(dev);
|
||||
struct resource *fcr = platform_get_resource(dev,
|
||||
IORESOURCE_MEM, 0);
|
||||
struct resource *ccr = platform_get_resource(dev,
|
||||
@ -516,7 +515,7 @@ static int tmio_remove(struct platform_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int tmio_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
struct mfd_cell *cell = dev_get_platdata(&dev->dev);
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
|
||||
if (cell->suspend)
|
||||
cell->suspend(dev);
|
||||
@ -527,7 +526,7 @@ static int tmio_suspend(struct platform_device *dev, pm_message_t state)
|
||||
|
||||
static int tmio_resume(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev_get_platdata(&dev->dev);
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
|
||||
/* FIXME - is this required or merely another attack of the broken
|
||||
* SHARP platform? Looks suspicious.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/can.h>
|
||||
@ -1643,7 +1644,7 @@ static int __devinit ican3_probe(struct platform_device *pdev)
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
pdata = mfd_get_data(pdev);
|
||||
if (!pdata)
|
||||
return -ENXIO;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
@ -1145,7 +1146,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
|
||||
struct resource *iomem;
|
||||
struct net_device *netdev;
|
||||
struct ks8842_adapter *adapter;
|
||||
struct ks8842_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct ks8842_platform_data *pdata = mfd_get_data(pdev);
|
||||
u16 id;
|
||||
unsigned i;
|
||||
|
||||
|
@ -39,7 +39,7 @@ struct jz_battery {
|
||||
int irq;
|
||||
int charge_irq;
|
||||
|
||||
struct mfd_cell *cell;
|
||||
const struct mfd_cell *cell;
|
||||
|
||||
int status;
|
||||
long voltage;
|
||||
@ -258,7 +258,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
jz_battery->cell = pdev->dev.platform_data;
|
||||
jz_battery->cell = mfd_get_cell(pdev);
|
||||
|
||||
jz_battery->irq = platform_get_irq(pdev, 0);
|
||||
if (jz_battery->irq < 0) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
struct pm8607_regulator_info {
|
||||
@ -394,47 +395,48 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = {
|
||||
PM8607_LDO(14, LDO14, 0, 4, SUPPLIES_EN12, 6),
|
||||
};
|
||||
|
||||
static inline struct pm8607_regulator_info *find_regulator_info(int id)
|
||||
{
|
||||
struct pm8607_regulator_info *info;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
|
||||
info = &pm8607_regulator_info[i];
|
||||
if (info->desc.id == id)
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_platform_data *pdata = chip->dev->platform_data;
|
||||
struct pm8607_regulator_info *info = NULL;
|
||||
struct regulator_init_data *pdata;
|
||||
struct mfd_cell *cell;
|
||||
int i;
|
||||
|
||||
info = find_regulator_info(pdev->id);
|
||||
if (info == NULL) {
|
||||
dev_err(&pdev->dev, "invalid regulator ID specified\n");
|
||||
cell = pdev->dev.platform_data;
|
||||
if (cell == NULL)
|
||||
return -ENODEV;
|
||||
pdata = cell->mfd_data;
|
||||
if (pdata == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
|
||||
info = &pm8607_regulator_info[i];
|
||||
if (!strcmp(info->desc.name, pdata->constraints.name))
|
||||
break;
|
||||
}
|
||||
if (i > ARRAY_SIZE(pm8607_regulator_info)) {
|
||||
dev_err(&pdev->dev, "Failed to find regulator %s\n",
|
||||
pdata->constraints.name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
|
||||
info->chip = chip;
|
||||
|
||||
/* check DVC ramp slope double */
|
||||
if (!strcmp(info->desc.name, "BUCK3"))
|
||||
if (info->chip->buck3_double)
|
||||
info->slope_double = 1;
|
||||
|
||||
info->regulator = regulator_register(&info->desc, &pdev->dev,
|
||||
pdata->regulator[pdev->id], info);
|
||||
pdata, info);
|
||||
if (IS_ERR(info->regulator)) {
|
||||
dev_err(&pdev->dev, "failed to register regulator %s\n",
|
||||
info->desc.name);
|
||||
return PTR_ERR(info->regulator);
|
||||
}
|
||||
|
||||
/* check DVC ramp slope double */
|
||||
if (info->desc.id == PM8607_ID_BUCK3)
|
||||
if (info->chip->buck3_double)
|
||||
info->slope_double = 1;
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
return 0;
|
||||
}
|
||||
|
@ -108,6 +108,15 @@ config REGULATOR_MAX8952
|
||||
via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS
|
||||
modes ranging from 0.77V to 1.40V by 0.01V steps.
|
||||
|
||||
config REGULATOR_MAX8997
|
||||
tristate "Maxim 8997/8966 regulator"
|
||||
depends on MFD_MAX8997
|
||||
help
|
||||
This driver controls a Maxim 8997/8966 regulator
|
||||
via I2C bus. The provided regulator is suitable for S5PC110,
|
||||
S5PV210, and Exynos-4 chips to control VCC_CORE and
|
||||
VCC_USIM voltages.
|
||||
|
||||
config REGULATOR_MAX8998
|
||||
tristate "Maxim 8998 voltage regulator"
|
||||
depends on MFD_MAX8998
|
||||
@ -214,6 +223,15 @@ config REGULATOR_AB3100
|
||||
AB3100 analog baseband dealing with power regulators
|
||||
for the system.
|
||||
|
||||
config REGULATOR_TPS6105X
|
||||
tristate "TI TPS6105X Power regulators"
|
||||
depends on TPS6105X
|
||||
default y if TPS6105X
|
||||
help
|
||||
This driver supports TPS61050/TPS61052 voltage regulator chips.
|
||||
It is a single boost converter primarily for white LEDs and
|
||||
audio amplifiers.
|
||||
|
||||
config REGULATOR_TPS65023
|
||||
tristate "TI TPS65023 Power regulators"
|
||||
depends on I2C
|
||||
|
@ -18,6 +18,7 @@ obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
|
||||
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
|
||||
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
|
||||
@ -33,7 +34,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
|
||||
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
|
||||
|
||||
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
/* LDO registers and some handy masking definitions for AB3100 */
|
||||
#define AB3100_LDO_A 0x40
|
||||
@ -576,7 +577,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
|
||||
|
||||
static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
|
||||
struct ab3100_platform_data *plfdata = mfd_get_data(pdev);
|
||||
int err = 0;
|
||||
u8 data;
|
||||
int i;
|
||||
|
1213
drivers/regulator/max8997.c
Normal file
1213
drivers/regulator/max8997.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,7 @@
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
@ -336,8 +337,7 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv;
|
||||
struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct mc13783_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_regulator_init_data *init_data;
|
||||
int i, ret;
|
||||
|
||||
@ -381,8 +381,7 @@ err:
|
||||
static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
|
||||
struct mc13783_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
int i;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
@ -520,8 +521,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv;
|
||||
struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct mc13xxx_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13xxx_regulator_init_data *init_data;
|
||||
int i, ret;
|
||||
u32 val;
|
||||
@ -595,8 +595,7 @@ err_free:
|
||||
static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
|
||||
struct mc13xxx_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
int i;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
196
drivers/regulator/tps6105x-regulator.c
Normal file
196
drivers/regulator/tps6105x-regulator.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Driver for TPS61050/61052 boost converters, typically used for white LEDs
|
||||
* or audio amplifiers.
|
||||
*
|
||||
* Copyright (C) 2011 ST-Ericsson SA
|
||||
* Written on behalf of Linaro for ST-Ericsson
|
||||
*
|
||||
* Author: Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps6105x.h>
|
||||
|
||||
static const int tps6105x_voltages[] = {
|
||||
4500000,
|
||||
5000000,
|
||||
5250000,
|
||||
5000000, /* There is an additional 5V */
|
||||
};
|
||||
|
||||
static int tps6105x_regulator_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
/* Activate voltage mode */
|
||||
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
/* Set into shutdown mode */
|
||||
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
u8 regval;
|
||||
int ret;
|
||||
|
||||
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
regval &= TPS6105X_REG0_MODE_MASK;
|
||||
regval >>= TPS6105X_REG0_MODE_SHIFT;
|
||||
|
||||
if (regval == TPS6105X_REG0_MODE_VOLTAGE)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
u8 regval;
|
||||
int ret;
|
||||
|
||||
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regval &= TPS6105X_REG0_VOLTAGE_MASK;
|
||||
regval >>= TPS6105X_REG0_VOLTAGE_SHIFT;
|
||||
return (int) regval;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_VOLTAGE_MASK,
|
||||
selector << TPS6105X_REG0_VOLTAGE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(tps6105x_voltages))
|
||||
return -EINVAL;
|
||||
|
||||
return tps6105x_voltages[selector];
|
||||
}
|
||||
|
||||
static struct regulator_ops tps6105x_regulator_ops = {
|
||||
.enable = tps6105x_regulator_enable,
|
||||
.disable = tps6105x_regulator_disable,
|
||||
.is_enabled = tps6105x_regulator_is_enabled,
|
||||
.get_voltage_sel = tps6105x_regulator_get_voltage_sel,
|
||||
.set_voltage_sel = tps6105x_regulator_set_voltage_sel,
|
||||
.list_voltage = tps6105x_regulator_list_voltage,
|
||||
};
|
||||
|
||||
static struct regulator_desc tps6105x_regulator_desc = {
|
||||
.name = "tps6105x-boost",
|
||||
.ops = &tps6105x_regulator_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.id = 0,
|
||||
.owner = THIS_MODULE,
|
||||
.n_voltages = ARRAY_SIZE(tps6105x_voltages),
|
||||
};
|
||||
|
||||
/*
|
||||
* Registers the chip as a voltage regulator
|
||||
*/
|
||||
static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = mfd_get_data(pdev);
|
||||
struct tps6105x_platform_data *pdata = tps6105x->pdata;
|
||||
int ret;
|
||||
|
||||
/* This instance is not set for regulator mode so bail out */
|
||||
if (pdata->mode != TPS6105X_MODE_VOLTAGE) {
|
||||
dev_info(&pdev->dev,
|
||||
"chip not in voltage mode mode, exit probe \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register regulator with framework */
|
||||
tps6105x->regulator = regulator_register(&tps6105x_regulator_desc,
|
||||
&tps6105x->client->dev,
|
||||
pdata->regulator_data, tps6105x);
|
||||
if (IS_ERR(tps6105x->regulator)) {
|
||||
ret = PTR_ERR(tps6105x->regulator);
|
||||
dev_err(&tps6105x->client->dev,
|
||||
"failed to register regulator\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = platform_get_drvdata(pdev);
|
||||
regulator_unregister(tps6105x->regulator);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tps6105x_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "tps6105x-regulator",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tps6105x_regulator_probe,
|
||||
.remove = __devexit_p(tps6105x_regulator_remove),
|
||||
};
|
||||
|
||||
static __init int tps6105x_regulator_init(void)
|
||||
{
|
||||
return platform_driver_register(&tps6105x_regulator_driver);
|
||||
}
|
||||
subsys_initcall(tps6105x_regulator_init);
|
||||
|
||||
static __exit void tps6105x_regulator_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tps6105x_regulator_driver);
|
||||
}
|
||||
module_exit(tps6105x_regulator_exit);
|
||||
|
||||
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
|
||||
MODULE_DESCRIPTION("TPS6105x regulator driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:tps6105x-regulator");
|
@ -475,6 +475,13 @@ static struct regulator_ops twlfixed_ops = {
|
||||
.get_status = twlreg_get_status,
|
||||
};
|
||||
|
||||
static struct regulator_ops twl6030_fixed_resource = {
|
||||
.enable = twlreg_enable,
|
||||
.disable = twlreg_disable,
|
||||
.is_enabled = twlreg_is_enabled,
|
||||
.get_status = twlreg_get_status,
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
|
||||
@ -538,6 +545,20 @@ static struct regulator_ops twlfixed_ops = {
|
||||
}, \
|
||||
}
|
||||
|
||||
#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay, remap_conf) { \
|
||||
.base = offset, \
|
||||
.id = num, \
|
||||
.delay = turnon_delay, \
|
||||
.remap = remap_conf, \
|
||||
.desc = { \
|
||||
.name = #label, \
|
||||
.id = TWL6030_REG_##label, \
|
||||
.ops = &twl6030_fixed_resource, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/*
|
||||
* We list regulators here if systems need some level of
|
||||
* software control over them after boot.
|
||||
@ -577,7 +598,8 @@ static struct twlreg_info twl_regs[] = {
|
||||
TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
|
||||
TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
|
||||
TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
|
||||
TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21)
|
||||
TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21),
|
||||
TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0, 0x21),
|
||||
};
|
||||
|
||||
static int __devinit twlreg_probe(struct platform_device *pdev)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_bitbang.h>
|
||||
#include <linux/spi/xilinx_spi.h>
|
||||
@ -470,7 +471,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev)
|
||||
struct spi_master *master;
|
||||
u8 i;
|
||||
|
||||
pdata = dev->dev.platform_data;
|
||||
pdata = mfd_get_data(dev);
|
||||
if (pdata) {
|
||||
num_cs = pdata->num_chipselect;
|
||||
little_endian = pdata->little_endian;
|
||||
|
@ -185,7 +185,7 @@ static struct platform_driver ohci_hcd_tmio_driver;
|
||||
|
||||
static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1);
|
||||
struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2);
|
||||
@ -274,7 +274,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
struct tmio_hcd *tmio = hcd_to_tmio(hcd);
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
tmio_stop_hc(dev);
|
||||
@ -293,7 +293,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev)
|
||||
#ifdef CONFIG_PM
|
||||
static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
struct tmio_hcd *tmio = hcd_to_tmio(hcd);
|
||||
@ -326,7 +326,7 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s
|
||||
|
||||
static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
struct tmio_hcd *tmio = hcd_to_tmio(hcd);
|
||||
|
@ -12,11 +12,12 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define MAX_BRIGHTNESS (0xFF)
|
||||
#define MIN_BRIGHTNESS (0)
|
||||
@ -161,32 +162,13 @@ static const struct backlight_ops pm860x_backlight_ops = {
|
||||
.get_brightness = pm860x_backlight_get_brightness,
|
||||
};
|
||||
|
||||
static int __check_device(struct pm860x_backlight_pdata *pdata, char *name)
|
||||
{
|
||||
struct pm860x_backlight_pdata *p = pdata;
|
||||
int ret = -EINVAL;
|
||||
|
||||
while (p && p->id) {
|
||||
if ((p->id != PM8606_ID_BACKLIGHT) || (p->flags < 0))
|
||||
break;
|
||||
|
||||
if (!strncmp(name, pm860x_backlight_name[p->flags],
|
||||
MFD_NAME_SIZE)) {
|
||||
ret = (int)p->flags;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pm860x_backlight_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_platform_data *pm860x_pdata;
|
||||
struct pm860x_backlight_pdata *pdata = NULL;
|
||||
struct pm860x_backlight_data *data;
|
||||
struct backlight_device *bl;
|
||||
struct mfd_cell *cell;
|
||||
struct resource *res;
|
||||
struct backlight_properties props;
|
||||
unsigned char value;
|
||||
@ -199,10 +181,10 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdev->dev.parent->platform_data) {
|
||||
pm860x_pdata = pdev->dev.parent->platform_data;
|
||||
pdata = pm860x_pdata->backlight;
|
||||
}
|
||||
cell = pdev->dev.platform_data;
|
||||
if (cell == NULL)
|
||||
return -ENODEV;
|
||||
pdata = cell->mfd_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "platform data isn't assigned to "
|
||||
"backlight\n");
|
||||
@ -219,7 +201,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
|
||||
data->current_brightness = MAX_BRIGHTNESS;
|
||||
data->pwm = pdata->pwm;
|
||||
data->iset = pdata->iset;
|
||||
data->port = __check_device(pdata, name);
|
||||
data->port = pdata->flags;
|
||||
if (data->port < 0) {
|
||||
dev_err(&pdev->dev, "wrong platform data is assigned");
|
||||
kfree(data);
|
||||
|
@ -250,8 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
|
||||
*/
|
||||
static int tmiofb_hw_stop(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
struct tmio_fb_data *data = cell->driver_data;
|
||||
struct tmio_fb_data *data = mfd_get_data(dev);
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
struct tmiofb_par *par = info->par;
|
||||
|
||||
@ -268,7 +267,7 @@ static int tmiofb_hw_stop(struct platform_device *dev)
|
||||
*/
|
||||
static int tmiofb_hw_init(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
struct tmiofb_par *par = info->par;
|
||||
const struct resource *nlcr = &cell->resources[0];
|
||||
@ -312,8 +311,7 @@ static int tmiofb_hw_init(struct platform_device *dev)
|
||||
*/
|
||||
static void tmiofb_hw_mode(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
struct tmio_fb_data *data = cell->driver_data;
|
||||
struct tmio_fb_data *data = mfd_get_data(dev);
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
struct fb_videomode *mode = info->mode;
|
||||
struct tmiofb_par *par = info->par;
|
||||
@ -559,9 +557,8 @@ static int tmiofb_ioctl(struct fb_info *fbi,
|
||||
static struct fb_videomode *
|
||||
tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||
{
|
||||
struct mfd_cell *cell =
|
||||
info->device->platform_data;
|
||||
struct tmio_fb_data *data = cell->driver_data;
|
||||
struct tmio_fb_data *data =
|
||||
mfd_get_data(to_platform_device(info->device));
|
||||
struct fb_videomode *best = NULL;
|
||||
int i;
|
||||
|
||||
@ -581,9 +578,8 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
{
|
||||
|
||||
struct fb_videomode *mode;
|
||||
struct mfd_cell *cell =
|
||||
info->device->platform_data;
|
||||
struct tmio_fb_data *data = cell->driver_data;
|
||||
struct tmio_fb_data *data =
|
||||
mfd_get_data(to_platform_device(info->device));
|
||||
|
||||
mode = tmiofb_find_mode(info, var);
|
||||
if (!mode || var->bits_per_pixel > 16)
|
||||
@ -683,8 +679,8 @@ static struct fb_ops tmiofb_ops = {
|
||||
|
||||
static int __devinit tmiofb_probe(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
struct tmio_fb_data *data = cell->driver_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct tmio_fb_data *data = mfd_get_data(dev);
|
||||
struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1);
|
||||
struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2);
|
||||
@ -811,7 +807,7 @@ err_ioremap_ccr:
|
||||
|
||||
static int __devexit tmiofb_remove(struct platform_device *dev)
|
||||
{
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
int irq = platform_get_irq(dev, 0);
|
||||
struct tmiofb_par *par;
|
||||
@ -941,7 +937,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
|
||||
#ifdef CONFIG_FB_TMIO_ACCELL
|
||||
struct tmiofb_par *par = info->par;
|
||||
#endif
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
int retval = 0;
|
||||
|
||||
console_lock();
|
||||
@ -973,7 +969,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
|
||||
static int tmiofb_resume(struct platform_device *dev)
|
||||
{
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
struct mfd_cell *cell = dev->dev.platform_data;
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
int retval = 0;
|
||||
|
||||
console_lock();
|
||||
|
@ -90,7 +90,7 @@ struct ds1wm_data {
|
||||
void __iomem *map;
|
||||
int bus_shift; /* # of shifts to calc register offsets */
|
||||
struct platform_device *pdev;
|
||||
struct mfd_cell *cell;
|
||||
const struct mfd_cell *cell;
|
||||
int irq;
|
||||
int active_high;
|
||||
int slave_present;
|
||||
@ -216,7 +216,7 @@ static int ds1wm_find_divisor(int gclk)
|
||||
static void ds1wm_up(struct ds1wm_data *ds1wm_data)
|
||||
{
|
||||
int divisor;
|
||||
struct ds1wm_driver_data *plat = ds1wm_data->cell->driver_data;
|
||||
struct ds1wm_driver_data *plat = mfd_get_data(ds1wm_data->pdev);
|
||||
|
||||
if (ds1wm_data->cell->enable)
|
||||
ds1wm_data->cell->enable(ds1wm_data->pdev);
|
||||
@ -330,16 +330,11 @@ static int ds1wm_probe(struct platform_device *pdev)
|
||||
struct ds1wm_data *ds1wm_data;
|
||||
struct ds1wm_driver_data *plat;
|
||||
struct resource *res;
|
||||
struct mfd_cell *cell;
|
||||
int ret;
|
||||
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
|
||||
cell = pdev->dev.platform_data;
|
||||
if (!cell)
|
||||
return -ENODEV;
|
||||
|
||||
ds1wm_data = kzalloc(sizeof(*ds1wm_data), GFP_KERNEL);
|
||||
if (!ds1wm_data)
|
||||
return -ENOMEM;
|
||||
@ -356,13 +351,13 @@ static int ds1wm_probe(struct platform_device *pdev)
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
plat = cell->driver_data;
|
||||
plat = mfd_get_data(pdev);
|
||||
|
||||
/* calculate bus shift from mem resource */
|
||||
ds1wm_data->bus_shift = resource_size(res) >> 3;
|
||||
|
||||
ds1wm_data->pdev = pdev;
|
||||
ds1wm_data->cell = cell;
|
||||
ds1wm_data->cell = mfd_get_cell(pdev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/mfd/rdc321x.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
#define RDC_WDT_MASK 0x80000000 /* Mask */
|
||||
#define RDC_WDT_EN 0x00800000 /* Enable bit */
|
||||
@ -231,7 +232,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
|
||||
struct resource *r;
|
||||
struct rdc321x_wdt_pdata *pdata;
|
||||
|
||||
pdata = platform_get_drvdata(pdev);
|
||||
pdata = mfd_get_data(pdev);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data supplied\n");
|
||||
return -ENODEV;
|
||||
|
@ -698,6 +698,7 @@ struct twl4030_platform_data {
|
||||
struct regulator_init_data *vana;
|
||||
struct regulator_init_data *vcxio;
|
||||
struct regulator_init_data *vusb;
|
||||
struct regulator_init_data *clk32kg;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@ -777,5 +778,6 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
|
||||
|
||||
/* INTERNAL LDOs */
|
||||
#define TWL6030_REG_VRTC 47
|
||||
#define TWL6030_REG_CLK32KG 48
|
||||
|
||||
#endif /* End of __TWL4030_H */
|
||||
|
141
include/linux/i2c/twl4030-madc.h
Normal file
141
include/linux/i2c/twl4030-madc.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* twl4030_madc.h - Header for TWL4030 MADC
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* J Keerthy <j-keerthy@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TWL4030_MADC_H
|
||||
#define _TWL4030_MADC_H
|
||||
|
||||
struct twl4030_madc_conversion_method {
|
||||
u8 sel;
|
||||
u8 avg;
|
||||
u8 rbase;
|
||||
u8 ctrl;
|
||||
};
|
||||
|
||||
#define TWL4030_MADC_MAX_CHANNELS 16
|
||||
|
||||
|
||||
/*
|
||||
* twl4030_madc_request- madc request packet for channel conversion
|
||||
* @channels: 16 bit bitmap for individual channels
|
||||
* @do_avgP: sample the input channel for 4 consecutive cycles
|
||||
* @method: RT, SW1, SW2
|
||||
* @type: Polling or interrupt based method
|
||||
*/
|
||||
|
||||
struct twl4030_madc_request {
|
||||
unsigned long channels;
|
||||
u16 do_avg;
|
||||
u16 method;
|
||||
u16 type;
|
||||
bool active;
|
||||
bool result_pending;
|
||||
int rbuf[TWL4030_MADC_MAX_CHANNELS];
|
||||
void (*func_cb)(int len, int channels, int *buf);
|
||||
};
|
||||
|
||||
enum conversion_methods {
|
||||
TWL4030_MADC_RT,
|
||||
TWL4030_MADC_SW1,
|
||||
TWL4030_MADC_SW2,
|
||||
TWL4030_MADC_NUM_METHODS
|
||||
};
|
||||
|
||||
enum sample_type {
|
||||
TWL4030_MADC_WAIT,
|
||||
TWL4030_MADC_IRQ_ONESHOT,
|
||||
TWL4030_MADC_IRQ_REARM
|
||||
};
|
||||
|
||||
#define TWL4030_MADC_CTRL1 0x00
|
||||
#define TWL4030_MADC_CTRL2 0x01
|
||||
|
||||
#define TWL4030_MADC_RTSELECT_LSB 0x02
|
||||
#define TWL4030_MADC_SW1SELECT_LSB 0x06
|
||||
#define TWL4030_MADC_SW2SELECT_LSB 0x0A
|
||||
|
||||
#define TWL4030_MADC_RTAVERAGE_LSB 0x04
|
||||
#define TWL4030_MADC_SW1AVERAGE_LSB 0x08
|
||||
#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C
|
||||
|
||||
#define TWL4030_MADC_CTRL_SW1 0x12
|
||||
#define TWL4030_MADC_CTRL_SW2 0x13
|
||||
|
||||
#define TWL4030_MADC_RTCH0_LSB 0x17
|
||||
#define TWL4030_MADC_GPCH0_LSB 0x37
|
||||
|
||||
#define TWL4030_MADC_MADCON (1 << 0) /* MADC power on */
|
||||
#define TWL4030_MADC_BUSY (1 << 0) /* MADC busy */
|
||||
/* MADC conversion completion */
|
||||
#define TWL4030_MADC_EOC_SW (1 << 1)
|
||||
/* MADC SWx start conversion */
|
||||
#define TWL4030_MADC_SW_START (1 << 5)
|
||||
#define TWL4030_MADC_ADCIN0 (1 << 0)
|
||||
#define TWL4030_MADC_ADCIN1 (1 << 1)
|
||||
#define TWL4030_MADC_ADCIN2 (1 << 2)
|
||||
#define TWL4030_MADC_ADCIN3 (1 << 3)
|
||||
#define TWL4030_MADC_ADCIN4 (1 << 4)
|
||||
#define TWL4030_MADC_ADCIN5 (1 << 5)
|
||||
#define TWL4030_MADC_ADCIN6 (1 << 6)
|
||||
#define TWL4030_MADC_ADCIN7 (1 << 7)
|
||||
#define TWL4030_MADC_ADCIN8 (1 << 8)
|
||||
#define TWL4030_MADC_ADCIN9 (1 << 9)
|
||||
#define TWL4030_MADC_ADCIN10 (1 << 10)
|
||||
#define TWL4030_MADC_ADCIN11 (1 << 11)
|
||||
#define TWL4030_MADC_ADCIN12 (1 << 12)
|
||||
#define TWL4030_MADC_ADCIN13 (1 << 13)
|
||||
#define TWL4030_MADC_ADCIN14 (1 << 14)
|
||||
#define TWL4030_MADC_ADCIN15 (1 << 15)
|
||||
|
||||
/* Fixed channels */
|
||||
#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1
|
||||
#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8
|
||||
#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9
|
||||
#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10
|
||||
#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11
|
||||
#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12
|
||||
|
||||
/* Step size and prescaler ratio */
|
||||
#define TEMP_STEP_SIZE 147
|
||||
#define TEMP_PSR_R 100
|
||||
#define CURR_STEP_SIZE 147
|
||||
#define CURR_PSR_R1 44
|
||||
#define CURR_PSR_R2 88
|
||||
|
||||
#define TWL4030_BCI_BCICTL1 0x23
|
||||
#define TWL4030_BCI_CGAIN 0x020
|
||||
#define TWL4030_BCI_MESBAT (1 << 1)
|
||||
#define TWL4030_BCI_TYPEN (1 << 4)
|
||||
#define TWL4030_BCI_ITHEN (1 << 3)
|
||||
|
||||
#define REG_BCICTL2 0x024
|
||||
#define TWL4030_BCI_ITHSENS 0x007
|
||||
|
||||
struct twl4030_madc_user_parms {
|
||||
int channel;
|
||||
int average;
|
||||
int status;
|
||||
u16 result;
|
||||
};
|
||||
|
||||
int twl4030_madc_conversion(struct twl4030_madc_request *conv);
|
||||
int twl4030_get_madc_conversion(int channel_no);
|
||||
#endif
|
@ -131,9 +131,11 @@ enum {
|
||||
PM8607_ID_LDO8,
|
||||
PM8607_ID_LDO9,
|
||||
PM8607_ID_LDO10,
|
||||
PM8607_ID_LDO11,
|
||||
PM8607_ID_LDO12,
|
||||
PM8607_ID_LDO13,
|
||||
PM8607_ID_LDO14,
|
||||
PM8607_ID_LDO15,
|
||||
|
||||
PM8607_ID_RG_MAX,
|
||||
};
|
||||
@ -310,8 +312,6 @@ struct pm860x_chip {
|
||||
|
||||
};
|
||||
|
||||
#define PM8607_MAX_REGULATOR PM8607_ID_RG_MAX /* 3 Bucks, 13 LDOs */
|
||||
|
||||
enum {
|
||||
GI2C_PORT = 0,
|
||||
PI2C_PORT,
|
||||
@ -351,23 +351,31 @@ struct pm860x_platform_data {
|
||||
struct pm860x_led_pdata *led;
|
||||
struct pm860x_touch_pdata *touch;
|
||||
struct pm860x_power_pdata *power;
|
||||
struct regulator_init_data *regulator;
|
||||
|
||||
unsigned short companion_addr; /* I2C address of companion chip */
|
||||
int i2c_port; /* Controlled by GI2C or PI2C */
|
||||
int irq_mode; /* Clear interrupt by read/write(0/1) */
|
||||
int irq_base; /* IRQ base number of 88pm860x */
|
||||
struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
|
||||
int num_leds;
|
||||
int num_backlights;
|
||||
int num_regulators;
|
||||
};
|
||||
|
||||
extern char pm860x_backlight_name[][MFD_NAME_SIZE];
|
||||
extern char pm860x_led_name[][MFD_NAME_SIZE];
|
||||
|
||||
extern int pm860x_reg_read(struct i2c_client *, int);
|
||||
extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
|
||||
extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
|
||||
extern int pm860x_bulk_write(struct i2c_client *, int, int, unsigned char *);
|
||||
extern int pm860x_set_bits(struct i2c_client *, int, unsigned char,
|
||||
unsigned char);
|
||||
extern int pm860x_page_reg_read(struct i2c_client *, int);
|
||||
extern int pm860x_page_reg_write(struct i2c_client *, int, unsigned char);
|
||||
extern int pm860x_page_bulk_read(struct i2c_client *, int, int,
|
||||
unsigned char *);
|
||||
extern int pm860x_page_bulk_write(struct i2c_client *, int, int,
|
||||
unsigned char *);
|
||||
extern int pm860x_page_set_bits(struct i2c_client *, int, unsigned char,
|
||||
unsigned char);
|
||||
|
||||
extern int pm860x_device_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata) __devinit ;
|
||||
|
@ -111,8 +111,8 @@
|
||||
* @dev: parent device
|
||||
* @lock: read/write operations lock
|
||||
* @irq_lock: genirq bus lock
|
||||
* @revision: chip revision
|
||||
* @irq: irq line
|
||||
* @chip_id: chip revision id
|
||||
* @write: register write
|
||||
* @read: register read
|
||||
* @rx_buf: rx buf for SPI
|
||||
@ -124,7 +124,7 @@ struct ab8500 {
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
struct mutex irq_lock;
|
||||
int revision;
|
||||
|
||||
int irq_base;
|
||||
int irq;
|
||||
u8 chip_id;
|
||||
|
32
include/linux/mfd/ab8500/gpadc.h
Normal file
32
include/linux/mfd/ab8500/gpadc.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2010 ST-Ericsson SA
|
||||
* Licensed under GPLv2.
|
||||
*
|
||||
* Author: Arun R Murthy <arun.murthy@stericsson.com>
|
||||
* Author: Daniel Willerud <daniel.willerud@stericsson.com>
|
||||
*/
|
||||
|
||||
#ifndef _AB8500_GPADC_H
|
||||
#define _AB8500_GPADC_H
|
||||
|
||||
/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */
|
||||
#define BAT_CTRL 0x01
|
||||
#define BTEMP_BALL 0x02
|
||||
#define MAIN_CHARGER_V 0x03
|
||||
#define ACC_DETECT1 0x04
|
||||
#define ACC_DETECT2 0x05
|
||||
#define ADC_AUX1 0x06
|
||||
#define ADC_AUX2 0x07
|
||||
#define MAIN_BAT_V 0x08
|
||||
#define VBUS_V 0x09
|
||||
#define MAIN_CHARGER_C 0x0A
|
||||
#define USB_CHARGER_C 0x0B
|
||||
#define BK_BAT_V 0x0C
|
||||
#define DIE_TEMP 0x0D
|
||||
|
||||
struct ab8500_gpadc;
|
||||
|
||||
struct ab8500_gpadc *ab8500_gpadc_get(char *name);
|
||||
int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input);
|
||||
|
||||
#endif /* _AB8500_GPADC_H */
|
254
include/linux/mfd/ab8500/sysctrl.h
Normal file
254
include/linux/mfd/ab8500/sysctrl.h
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2010
|
||||
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
#ifndef __AB8500_SYSCTRL_H
|
||||
#define __AB8500_SYSCTRL_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#ifdef CONFIG_AB8500_CORE
|
||||
|
||||
int ab8500_sysctrl_read(u16 reg, u8 *value);
|
||||
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
|
||||
|
||||
#else
|
||||
|
||||
static inline int ab8500_sysctrl_read(u16 reg, u8 *value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_AB8500_CORE */
|
||||
|
||||
static inline int ab8500_sysctrl_set(u16 reg, u8 bits)
|
||||
{
|
||||
return ab8500_sysctrl_write(reg, bits, bits);
|
||||
}
|
||||
|
||||
static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
|
||||
{
|
||||
return ab8500_sysctrl_write(reg, bits, 0);
|
||||
}
|
||||
|
||||
/* Registers */
|
||||
#define AB8500_TURNONSTATUS 0x100
|
||||
#define AB8500_RESETSTATUS 0x101
|
||||
#define AB8500_PONKEY1PRESSSTATUS 0x102
|
||||
#define AB8500_SYSCLKREQSTATUS 0x142
|
||||
#define AB8500_STW4500CTRL1 0x180
|
||||
#define AB8500_STW4500CTRL2 0x181
|
||||
#define AB8500_STW4500CTRL3 0x200
|
||||
#define AB8500_MAINWDOGCTRL 0x201
|
||||
#define AB8500_MAINWDOGTIMER 0x202
|
||||
#define AB8500_LOWBAT 0x203
|
||||
#define AB8500_BATTOK 0x204
|
||||
#define AB8500_SYSCLKTIMER 0x205
|
||||
#define AB8500_SMPSCLKCTRL 0x206
|
||||
#define AB8500_SMPSCLKSEL1 0x207
|
||||
#define AB8500_SMPSCLKSEL2 0x208
|
||||
#define AB8500_SMPSCLKSEL3 0x209
|
||||
#define AB8500_SYSULPCLKCONF 0x20A
|
||||
#define AB8500_SYSULPCLKCTRL1 0x20B
|
||||
#define AB8500_SYSCLKCTRL 0x20C
|
||||
#define AB8500_SYSCLKREQ1VALID 0x20D
|
||||
#define AB8500_SYSTEMCTRLSUP 0x20F
|
||||
#define AB8500_SYSCLKREQ1RFCLKBUF 0x210
|
||||
#define AB8500_SYSCLKREQ2RFCLKBUF 0x211
|
||||
#define AB8500_SYSCLKREQ3RFCLKBUF 0x212
|
||||
#define AB8500_SYSCLKREQ4RFCLKBUF 0x213
|
||||
#define AB8500_SYSCLKREQ5RFCLKBUF 0x214
|
||||
#define AB8500_SYSCLKREQ6RFCLKBUF 0x215
|
||||
#define AB8500_SYSCLKREQ7RFCLKBUF 0x216
|
||||
#define AB8500_SYSCLKREQ8RFCLKBUF 0x217
|
||||
#define AB8500_DITHERCLKCTRL 0x220
|
||||
#define AB8500_SWATCTRL 0x230
|
||||
#define AB8500_HIQCLKCTRL 0x232
|
||||
#define AB8500_VSIMSYSCLKCTRL 0x233
|
||||
|
||||
/* Bits */
|
||||
#define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
|
||||
#define AB8500_TURNONSTATUS_PONKEY1DBF BIT(1)
|
||||
#define AB8500_TURNONSTATUS_PONKEY2DBF BIT(2)
|
||||
#define AB8500_TURNONSTATUS_RTCALARM BIT(3)
|
||||
#define AB8500_TURNONSTATUS_MAINCHDET BIT(4)
|
||||
#define AB8500_TURNONSTATUS_VBUSDET BIT(5)
|
||||
#define AB8500_TURNONSTATUS_USBIDDETECT BIT(6)
|
||||
|
||||
#define AB8500_RESETSTATUS_RESETN4500NSTATUS BIT(0)
|
||||
#define AB8500_RESETSTATUS_SWRESETN4500NSTATUS BIT(2)
|
||||
|
||||
#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_MASK 0x7F
|
||||
#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_SHIFT 0
|
||||
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ1STATUS BIT(0)
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ2STATUS BIT(1)
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ3STATUS BIT(2)
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ4STATUS BIT(3)
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ5STATUS BIT(4)
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ6STATUS BIT(5)
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ7STATUS BIT(6)
|
||||
#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ8STATUS BIT(7)
|
||||
|
||||
#define AB8500_STW4500CTRL1_SWOFF BIT(0)
|
||||
#define AB8500_STW4500CTRL1_SWRESET4500N BIT(1)
|
||||
#define AB8500_STW4500CTRL1_THDB8500SWOFF BIT(2)
|
||||
|
||||
#define AB8500_STW4500CTRL2_RESETNVAUX1VALID BIT(0)
|
||||
#define AB8500_STW4500CTRL2_RESETNVAUX2VALID BIT(1)
|
||||
#define AB8500_STW4500CTRL2_RESETNVAUX3VALID BIT(2)
|
||||
#define AB8500_STW4500CTRL2_RESETNVMODVALID BIT(3)
|
||||
#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY1VALID BIT(4)
|
||||
#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY2VALID BIT(5)
|
||||
#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY3VALID BIT(6)
|
||||
#define AB8500_STW4500CTRL2_RESETNVSMPS1VALID BIT(7)
|
||||
|
||||
#define AB8500_STW4500CTRL3_CLK32KOUT2DIS BIT(0)
|
||||
#define AB8500_STW4500CTRL3_RESETAUDN BIT(1)
|
||||
#define AB8500_STW4500CTRL3_RESETDENCN BIT(2)
|
||||
#define AB8500_STW4500CTRL3_THSDENA BIT(3)
|
||||
|
||||
#define AB8500_MAINWDOGCTRL_MAINWDOGENA BIT(0)
|
||||
#define AB8500_MAINWDOGCTRL_MAINWDOGKICK BIT(1)
|
||||
#define AB8500_MAINWDOGCTRL_WDEXPTURNONVALID BIT(4)
|
||||
|
||||
#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_MASK 0x7F
|
||||
#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_SHIFT 0
|
||||
|
||||
#define AB8500_LOWBAT_LOWBATENA BIT(0)
|
||||
#define AB8500_LOWBAT_LOWBAT_MASK 0x7E
|
||||
#define AB8500_LOWBAT_LOWBAT_SHIFT 1
|
||||
|
||||
#define AB8500_BATTOK_BATTOKSEL0THF_MASK 0x0F
|
||||
#define AB8500_BATTOK_BATTOKSEL0THF_SHIFT 0
|
||||
#define AB8500_BATTOK_BATTOKSEL1THF_MASK 0xF0
|
||||
#define AB8500_BATTOK_BATTOKSEL1THF_SHIFT 4
|
||||
|
||||
#define AB8500_SYSCLKTIMER_SYSCLKTIMER_MASK 0x0F
|
||||
#define AB8500_SYSCLKTIMER_SYSCLKTIMER_SHIFT 0
|
||||
#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_MASK 0xF0
|
||||
#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_SHIFT 4
|
||||
|
||||
#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_MASK 0x03
|
||||
#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_SHIFT 0
|
||||
#define AB8500_SMPSCLKCTRL_3M2CLKINTENA BIT(2)
|
||||
|
||||
#define AB8500_SMPSCLKSEL1_VARMCLKSEL_MASK 0x07
|
||||
#define AB8500_SMPSCLKSEL1_VARMCLKSEL_SHIFT 0
|
||||
#define AB8500_SMPSCLKSEL1_VAPECLKSEL_MASK 0x38
|
||||
#define AB8500_SMPSCLKSEL1_VAPECLKSEL_SHIFT 3
|
||||
|
||||
#define AB8500_SMPSCLKSEL2_VMODCLKSEL_MASK 0x07
|
||||
#define AB8500_SMPSCLKSEL2_VMODCLKSEL_SHIFT 0
|
||||
#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_MASK 0x38
|
||||
#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_SHIFT 3
|
||||
|
||||
#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_MASK 0x07
|
||||
#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_SHIFT 0
|
||||
#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_MASK 0x38
|
||||
#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_SHIFT 3
|
||||
|
||||
#define AB8500_SYSULPCLKCONF_ULPCLKCONF_MASK 0x03
|
||||
#define AB8500_SYSULPCLKCONF_ULPCLKCONF_SHIFT 0
|
||||
#define AB8500_SYSULPCLKCONF_CLK27MHZSTRE BIT(2)
|
||||
#define AB8500_SYSULPCLKCONF_TVOUTCLKDELN BIT(3)
|
||||
#define AB8500_SYSULPCLKCONF_TVOUTCLKINV BIT(4)
|
||||
#define AB8500_SYSULPCLKCONF_ULPCLKSTRE BIT(5)
|
||||
#define AB8500_SYSULPCLKCONF_CLK27MHZBUFENA BIT(6)
|
||||
#define AB8500_SYSULPCLKCONF_CLK27MHZPDENA BIT(7)
|
||||
|
||||
#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK 0x03
|
||||
#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT 0
|
||||
#define AB8500_SYSULPCLKCTRL1_ULPCLKREQ BIT(2)
|
||||
#define AB8500_SYSULPCLKCTRL1_4500SYSCLKREQ BIT(3)
|
||||
#define AB8500_SYSULPCLKCTRL1_AUDIOCLKENA BIT(4)
|
||||
#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ BIT(5)
|
||||
#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ BIT(6)
|
||||
#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ BIT(7)
|
||||
|
||||
#define AB8500_SYSCLKCTRL_TVOUTPLLENA BIT(0)
|
||||
#define AB8500_SYSCLKCTRL_TVOUTCLKENA BIT(1)
|
||||
#define AB8500_SYSCLKCTRL_USBCLKENA BIT(2)
|
||||
|
||||
#define AB8500_SYSCLKREQ1VALID_SYSCLKREQ1VALID BIT(0)
|
||||
#define AB8500_SYSCLKREQ1VALID_ULPCLKREQ1VALID BIT(1)
|
||||
#define AB8500_SYSCLKREQ1VALID_USBSYSCLKREQ1VALID BIT(2)
|
||||
|
||||
#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_MASK 0x03
|
||||
#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_SHIFT 0
|
||||
#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_MASK 0x0C
|
||||
#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_SHIFT 2
|
||||
#define AB8500_SYSTEMCTRLSUP_INTDB8500NOD BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF2 BIT(2)
|
||||
#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF3 BIT(3)
|
||||
#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF4 BIT(4)
|
||||
|
||||
#define AB8500_DITHERCLKCTRL_VARMDITHERENA BIT(0)
|
||||
#define AB8500_DITHERCLKCTRL_VSMPS3DITHERENA BIT(1)
|
||||
#define AB8500_DITHERCLKCTRL_VSMPS1DITHERENA BIT(2)
|
||||
#define AB8500_DITHERCLKCTRL_VSMPS2DITHERENA BIT(3)
|
||||
#define AB8500_DITHERCLKCTRL_VMODDITHERENA BIT(4)
|
||||
#define AB8500_DITHERCLKCTRL_VAPEDITHERENA BIT(5)
|
||||
#define AB8500_DITHERCLKCTRL_DITHERDEL_MASK 0xC0
|
||||
#define AB8500_DITHERCLKCTRL_DITHERDEL_SHIFT 6
|
||||
|
||||
#define AB8500_SWATCTRL_UPDATERF BIT(0)
|
||||
#define AB8500_SWATCTRL_SWATENABLE BIT(1)
|
||||
#define AB8500_SWATCTRL_RFOFFTIMER_MASK 0x1C
|
||||
#define AB8500_SWATCTRL_RFOFFTIMER_SHIFT 2
|
||||
#define AB8500_SWATCTRL_SWATBIT5 BIT(6)
|
||||
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ1HIQENAVALID BIT(0)
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ2HIQENAVALID BIT(1)
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ3HIQENAVALID BIT(2)
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ4HIQENAVALID BIT(3)
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ5HIQENAVALID BIT(4)
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ6HIQENAVALID BIT(5)
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ7HIQENAVALID BIT(6)
|
||||
#define AB8500_HIQCLKCTRL_SYSCLKREQ8HIQENAVALID BIT(7)
|
||||
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ1VALID BIT(0)
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ2VALID BIT(1)
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ3VALID BIT(2)
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ4VALID BIT(3)
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ5VALID BIT(4)
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ6VALID BIT(5)
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
|
||||
#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
|
||||
|
||||
#endif /* __AB8500_SYSCTRL_H */
|
@ -186,7 +186,6 @@ struct abx500_init_settings {
|
||||
struct ab3550_platform_data {
|
||||
struct {unsigned int base; unsigned int count; } irq;
|
||||
void *dev_data[AB3550_NUM_DEVICES];
|
||||
size_t dev_data_sz[AB3550_NUM_DEVICES];
|
||||
struct abx500_init_settings *init_settings;
|
||||
unsigned int init_settings_sz;
|
||||
};
|
||||
|
@ -25,22 +25,20 @@ struct mfd_cell {
|
||||
const char *name;
|
||||
int id;
|
||||
|
||||
/* refcounting for multiple drivers to use a single cell */
|
||||
atomic_t *usage_count;
|
||||
int (*enable)(struct platform_device *dev);
|
||||
int (*disable)(struct platform_device *dev);
|
||||
|
||||
int (*suspend)(struct platform_device *dev);
|
||||
int (*resume)(struct platform_device *dev);
|
||||
|
||||
/* driver-specific data for MFD-aware "cell" drivers */
|
||||
void *driver_data;
|
||||
|
||||
/* platform_data can be used to either pass data to "generic"
|
||||
driver or as a hook to mfd_cell for the "cell" drivers */
|
||||
void *platform_data;
|
||||
size_t data_size;
|
||||
/* mfd_data can be used to pass data to client drivers */
|
||||
void *mfd_data;
|
||||
|
||||
/*
|
||||
* This resources can be specified relatively to the parent device.
|
||||
* For accessing device you should use resources from device
|
||||
* These resources can be specified relative to the parent device.
|
||||
* For accessing hardware you should use resources from the platform dev
|
||||
*/
|
||||
int num_resources;
|
||||
const struct resource *resources;
|
||||
@ -55,11 +53,47 @@ struct mfd_cell {
|
||||
bool pm_runtime_no_callbacks;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convenience functions for clients using shared cells. Refcounting
|
||||
* happens automatically, with the cell's enable/disable callbacks
|
||||
* being called only when a device is first being enabled or no other
|
||||
* clients are making use of it.
|
||||
*/
|
||||
extern int mfd_cell_enable(struct platform_device *pdev);
|
||||
extern int mfd_cell_disable(struct platform_device *pdev);
|
||||
|
||||
/*
|
||||
* Given a platform device that's been created by mfd_add_devices(), fetch
|
||||
* the mfd_cell that created it.
|
||||
*/
|
||||
static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev)
|
||||
{
|
||||
return pdev->dev.platform_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a platform device that's been created by mfd_add_devices(), fetch
|
||||
* the .mfd_data entry from the mfd_cell that created it.
|
||||
*/
|
||||
static inline void *mfd_get_data(struct platform_device *pdev)
|
||||
{
|
||||
return mfd_get_cell(pdev)->mfd_data;
|
||||
}
|
||||
|
||||
extern int mfd_add_devices(struct device *parent, int id,
|
||||
const struct mfd_cell *cells, int n_devs,
|
||||
struct mfd_cell *cells, int n_devs,
|
||||
struct resource *mem_base,
|
||||
int irq_base);
|
||||
|
||||
extern void mfd_remove_devices(struct device *parent);
|
||||
|
||||
/*
|
||||
* For MFD drivers with clients sharing access to resources, these create
|
||||
* multiple platform devices per cell. Contention handling must still be
|
||||
* handled via drivers (ie, with enable/disable hooks).
|
||||
*/
|
||||
extern int mfd_shared_platform_driver_register(struct platform_driver *drv,
|
||||
const char *cellname);
|
||||
extern void mfd_shared_platform_driver_unregister(struct platform_driver *drv);
|
||||
|
||||
#endif
|
||||
|
347
include/linux/mfd/max8997-private.h
Normal file
347
include/linux/mfd/max8997-private.h
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* max8997.h - Voltage regulator driver for the Maxim 8997
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electrnoics
|
||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_MAX8997_PRIV_H
|
||||
#define __LINUX_MFD_MAX8997_PRIV_H
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
enum max8997_pmic_reg {
|
||||
MAX8997_REG_PMIC_ID0 = 0x00,
|
||||
MAX8997_REG_PMIC_ID1 = 0x01,
|
||||
MAX8997_REG_INTSRC = 0x02,
|
||||
MAX8997_REG_INT1 = 0x03,
|
||||
MAX8997_REG_INT2 = 0x04,
|
||||
MAX8997_REG_INT3 = 0x05,
|
||||
MAX8997_REG_INT4 = 0x06,
|
||||
|
||||
MAX8997_REG_INT1MSK = 0x08,
|
||||
MAX8997_REG_INT2MSK = 0x09,
|
||||
MAX8997_REG_INT3MSK = 0x0a,
|
||||
MAX8997_REG_INT4MSK = 0x0b,
|
||||
|
||||
MAX8997_REG_STATUS1 = 0x0d,
|
||||
MAX8997_REG_STATUS2 = 0x0e,
|
||||
MAX8997_REG_STATUS3 = 0x0f,
|
||||
MAX8997_REG_STATUS4 = 0x10,
|
||||
|
||||
MAX8997_REG_MAINCON1 = 0x13,
|
||||
MAX8997_REG_MAINCON2 = 0x14,
|
||||
MAX8997_REG_BUCKRAMP = 0x15,
|
||||
|
||||
MAX8997_REG_BUCK1CTRL = 0x18,
|
||||
MAX8997_REG_BUCK1DVS1 = 0x19,
|
||||
MAX8997_REG_BUCK1DVS2 = 0x1a,
|
||||
MAX8997_REG_BUCK1DVS3 = 0x1b,
|
||||
MAX8997_REG_BUCK1DVS4 = 0x1c,
|
||||
MAX8997_REG_BUCK1DVS5 = 0x1d,
|
||||
MAX8997_REG_BUCK1DVS6 = 0x1e,
|
||||
MAX8997_REG_BUCK1DVS7 = 0x1f,
|
||||
MAX8997_REG_BUCK1DVS8 = 0x20,
|
||||
MAX8997_REG_BUCK2CTRL = 0x21,
|
||||
MAX8997_REG_BUCK2DVS1 = 0x22,
|
||||
MAX8997_REG_BUCK2DVS2 = 0x23,
|
||||
MAX8997_REG_BUCK2DVS3 = 0x24,
|
||||
MAX8997_REG_BUCK2DVS4 = 0x25,
|
||||
MAX8997_REG_BUCK2DVS5 = 0x26,
|
||||
MAX8997_REG_BUCK2DVS6 = 0x27,
|
||||
MAX8997_REG_BUCK2DVS7 = 0x28,
|
||||
MAX8997_REG_BUCK2DVS8 = 0x29,
|
||||
MAX8997_REG_BUCK3CTRL = 0x2a,
|
||||
MAX8997_REG_BUCK3DVS = 0x2b,
|
||||
MAX8997_REG_BUCK4CTRL = 0x2c,
|
||||
MAX8997_REG_BUCK4DVS = 0x2d,
|
||||
MAX8997_REG_BUCK5CTRL = 0x2e,
|
||||
MAX8997_REG_BUCK5DVS1 = 0x2f,
|
||||
MAX8997_REG_BUCK5DVS2 = 0x30,
|
||||
MAX8997_REG_BUCK5DVS3 = 0x31,
|
||||
MAX8997_REG_BUCK5DVS4 = 0x32,
|
||||
MAX8997_REG_BUCK5DVS5 = 0x33,
|
||||
MAX8997_REG_BUCK5DVS6 = 0x34,
|
||||
MAX8997_REG_BUCK5DVS7 = 0x35,
|
||||
MAX8997_REG_BUCK5DVS8 = 0x36,
|
||||
MAX8997_REG_BUCK6CTRL = 0x37,
|
||||
MAX8997_REG_BUCK6BPSKIPCTRL = 0x38,
|
||||
MAX8997_REG_BUCK7CTRL = 0x39,
|
||||
MAX8997_REG_BUCK7DVS = 0x3a,
|
||||
MAX8997_REG_LDO1CTRL = 0x3b,
|
||||
MAX8997_REG_LDO2CTRL = 0x3c,
|
||||
MAX8997_REG_LDO3CTRL = 0x3d,
|
||||
MAX8997_REG_LDO4CTRL = 0x3e,
|
||||
MAX8997_REG_LDO5CTRL = 0x3f,
|
||||
MAX8997_REG_LDO6CTRL = 0x40,
|
||||
MAX8997_REG_LDO7CTRL = 0x41,
|
||||
MAX8997_REG_LDO8CTRL = 0x42,
|
||||
MAX8997_REG_LDO9CTRL = 0x43,
|
||||
MAX8997_REG_LDO10CTRL = 0x44,
|
||||
MAX8997_REG_LDO11CTRL = 0x45,
|
||||
MAX8997_REG_LDO12CTRL = 0x46,
|
||||
MAX8997_REG_LDO13CTRL = 0x47,
|
||||
MAX8997_REG_LDO14CTRL = 0x48,
|
||||
MAX8997_REG_LDO15CTRL = 0x49,
|
||||
MAX8997_REG_LDO16CTRL = 0x4a,
|
||||
MAX8997_REG_LDO17CTRL = 0x4b,
|
||||
MAX8997_REG_LDO18CTRL = 0x4c,
|
||||
MAX8997_REG_LDO21CTRL = 0x4d,
|
||||
|
||||
MAX8997_REG_MBCCTRL1 = 0x50,
|
||||
MAX8997_REG_MBCCTRL2 = 0x51,
|
||||
MAX8997_REG_MBCCTRL3 = 0x52,
|
||||
MAX8997_REG_MBCCTRL4 = 0x53,
|
||||
MAX8997_REG_MBCCTRL5 = 0x54,
|
||||
MAX8997_REG_MBCCTRL6 = 0x55,
|
||||
MAX8997_REG_OTPCGHCVS = 0x56,
|
||||
|
||||
MAX8997_REG_SAFEOUTCTRL = 0x5a,
|
||||
|
||||
MAX8997_REG_LBCNFG1 = 0x5e,
|
||||
MAX8997_REG_LBCNFG2 = 0x5f,
|
||||
MAX8997_REG_BBCCTRL = 0x60,
|
||||
|
||||
MAX8997_REG_FLASH1_CUR = 0x63, /* 0x63 ~ 0x6e for FLASH */
|
||||
MAX8997_REG_FLASH2_CUR = 0x64,
|
||||
MAX8997_REG_MOVIE_CUR = 0x65,
|
||||
MAX8997_REG_GSMB_CUR = 0x66,
|
||||
MAX8997_REG_BOOST_CNTL = 0x67,
|
||||
MAX8997_REG_LEN_CNTL = 0x68,
|
||||
MAX8997_REG_FLASH_CNTL = 0x69,
|
||||
MAX8997_REG_WDT_CNTL = 0x6a,
|
||||
MAX8997_REG_MAXFLASH1 = 0x6b,
|
||||
MAX8997_REG_MAXFLASH2 = 0x6c,
|
||||
MAX8997_REG_FLASHSTATUS = 0x6d,
|
||||
MAX8997_REG_FLASHSTATUSMASK = 0x6e,
|
||||
|
||||
MAX8997_REG_GPIOCNTL1 = 0x70,
|
||||
MAX8997_REG_GPIOCNTL2 = 0x71,
|
||||
MAX8997_REG_GPIOCNTL3 = 0x72,
|
||||
MAX8997_REG_GPIOCNTL4 = 0x73,
|
||||
MAX8997_REG_GPIOCNTL5 = 0x74,
|
||||
MAX8997_REG_GPIOCNTL6 = 0x75,
|
||||
MAX8997_REG_GPIOCNTL7 = 0x76,
|
||||
MAX8997_REG_GPIOCNTL8 = 0x77,
|
||||
MAX8997_REG_GPIOCNTL9 = 0x78,
|
||||
MAX8997_REG_GPIOCNTL10 = 0x79,
|
||||
MAX8997_REG_GPIOCNTL11 = 0x7a,
|
||||
MAX8997_REG_GPIOCNTL12 = 0x7b,
|
||||
|
||||
MAX8997_REG_LDO1CONFIG = 0x80,
|
||||
MAX8997_REG_LDO2CONFIG = 0x81,
|
||||
MAX8997_REG_LDO3CONFIG = 0x82,
|
||||
MAX8997_REG_LDO4CONFIG = 0x83,
|
||||
MAX8997_REG_LDO5CONFIG = 0x84,
|
||||
MAX8997_REG_LDO6CONFIG = 0x85,
|
||||
MAX8997_REG_LDO7CONFIG = 0x86,
|
||||
MAX8997_REG_LDO8CONFIG = 0x87,
|
||||
MAX8997_REG_LDO9CONFIG = 0x88,
|
||||
MAX8997_REG_LDO10CONFIG = 0x89,
|
||||
MAX8997_REG_LDO11CONFIG = 0x8a,
|
||||
MAX8997_REG_LDO12CONFIG = 0x8b,
|
||||
MAX8997_REG_LDO13CONFIG = 0x8c,
|
||||
MAX8997_REG_LDO14CONFIG = 0x8d,
|
||||
MAX8997_REG_LDO15CONFIG = 0x8e,
|
||||
MAX8997_REG_LDO16CONFIG = 0x8f,
|
||||
MAX8997_REG_LDO17CONFIG = 0x90,
|
||||
MAX8997_REG_LDO18CONFIG = 0x91,
|
||||
MAX8997_REG_LDO21CONFIG = 0x92,
|
||||
|
||||
MAX8997_REG_DVSOKTIMER1 = 0x97,
|
||||
MAX8997_REG_DVSOKTIMER2 = 0x98,
|
||||
MAX8997_REG_DVSOKTIMER4 = 0x99,
|
||||
MAX8997_REG_DVSOKTIMER5 = 0x9a,
|
||||
|
||||
MAX8997_REG_PMIC_END = 0x9b,
|
||||
};
|
||||
|
||||
enum max8997_muic_reg {
|
||||
MAX8997_MUIC_REG_ID = 0x0,
|
||||
MAX8997_MUIC_REG_INT1 = 0x1,
|
||||
MAX8997_MUIC_REG_INT2 = 0x2,
|
||||
MAX8997_MUIC_REG_INT3 = 0x3,
|
||||
MAX8997_MUIC_REG_STATUS1 = 0x4,
|
||||
MAX8997_MUIC_REG_STATUS2 = 0x5,
|
||||
MAX8997_MUIC_REG_STATUS3 = 0x6,
|
||||
MAX8997_MUIC_REG_INTMASK1 = 0x7,
|
||||
MAX8997_MUIC_REG_INTMASK2 = 0x8,
|
||||
MAX8997_MUIC_REG_INTMASK3 = 0x9,
|
||||
MAX8997_MUIC_REG_CDETCTRL = 0xa,
|
||||
|
||||
MAX8997_MUIC_REG_CONTROL1 = 0xc,
|
||||
MAX8997_MUIC_REG_CONTROL2 = 0xd,
|
||||
MAX8997_MUIC_REG_CONTROL3 = 0xe,
|
||||
|
||||
MAX8997_MUIC_REG_END = 0xf,
|
||||
};
|
||||
|
||||
enum max8997_haptic_reg {
|
||||
MAX8997_HAPTIC_REG_GENERAL = 0x00,
|
||||
MAX8997_HAPTIC_REG_CONF1 = 0x01,
|
||||
MAX8997_HAPTIC_REG_CONF2 = 0x02,
|
||||
MAX8997_HAPTIC_REG_DRVCONF = 0x03,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF1 = 0x04,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF2 = 0x05,
|
||||
MAX8997_HAPTIC_REG_SIGCONF1 = 0x06,
|
||||
MAX8997_HAPTIC_REG_SIGCONF2 = 0x07,
|
||||
MAX8997_HAPTIC_REG_SIGCONF3 = 0x08,
|
||||
MAX8997_HAPTIC_REG_SIGCONF4 = 0x09,
|
||||
MAX8997_HAPTIC_REG_SIGDC1 = 0x0a,
|
||||
MAX8997_HAPTIC_REG_SIGDC2 = 0x0b,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC1 = 0x0c,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC2 = 0x0d,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC3 = 0x0e,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC4 = 0x0f,
|
||||
MAX8997_HAPTIC_REG_MTR_REV = 0x10,
|
||||
|
||||
MAX8997_HAPTIC_REG_END = 0x11,
|
||||
};
|
||||
|
||||
/* slave addr = 0x0c: using "2nd part" of rev4 datasheet */
|
||||
enum max8997_rtc_reg {
|
||||
MAX8997_RTC_CTRLMASK = 0x02,
|
||||
MAX8997_RTC_CTRL = 0x03,
|
||||
MAX8997_RTC_UPDATE1 = 0x04,
|
||||
MAX8997_RTC_UPDATE2 = 0x05,
|
||||
MAX8997_RTC_WTSR_SMPL = 0x06,
|
||||
|
||||
MAX8997_RTC_SEC = 0x10,
|
||||
MAX8997_RTC_MIN = 0x11,
|
||||
MAX8997_RTC_HOUR = 0x12,
|
||||
MAX8997_RTC_DAY_OF_WEEK = 0x13,
|
||||
MAX8997_RTC_MONTH = 0x14,
|
||||
MAX8997_RTC_YEAR = 0x15,
|
||||
MAX8997_RTC_DAY_OF_MONTH = 0x16,
|
||||
MAX8997_RTC_ALARM1_SEC = 0x17,
|
||||
MAX8997_RTC_ALARM1_MIN = 0x18,
|
||||
MAX8997_RTC_ALARM1_HOUR = 0x19,
|
||||
MAX8997_RTC_ALARM1_DAY_OF_WEEK = 0x1a,
|
||||
MAX8997_RTC_ALARM1_MONTH = 0x1b,
|
||||
MAX8997_RTC_ALARM1_YEAR = 0x1c,
|
||||
MAX8997_RTC_ALARM1_DAY_OF_MONTH = 0x1d,
|
||||
MAX8997_RTC_ALARM2_SEC = 0x1e,
|
||||
MAX8997_RTC_ALARM2_MIN = 0x1f,
|
||||
MAX8997_RTC_ALARM2_HOUR = 0x20,
|
||||
MAX8997_RTC_ALARM2_DAY_OF_WEEK = 0x21,
|
||||
MAX8997_RTC_ALARM2_MONTH = 0x22,
|
||||
MAX8997_RTC_ALARM2_YEAR = 0x23,
|
||||
MAX8997_RTC_ALARM2_DAY_OF_MONTH = 0x24,
|
||||
};
|
||||
|
||||
enum max8997_irq_source {
|
||||
PMIC_INT1 = 0,
|
||||
PMIC_INT2,
|
||||
PMIC_INT3,
|
||||
PMIC_INT4,
|
||||
|
||||
FUEL_GAUGE, /* Ignored (MAX17042 driver handles) */
|
||||
|
||||
MUIC_INT1,
|
||||
MUIC_INT2,
|
||||
MUIC_INT3,
|
||||
|
||||
GPIO_LOW, /* Not implemented */
|
||||
GPIO_HI, /* Not implemented */
|
||||
|
||||
FLASH_STATUS, /* Not implemented */
|
||||
|
||||
MAX8997_IRQ_GROUP_NR,
|
||||
};
|
||||
|
||||
enum max8997_irq {
|
||||
MAX8997_PMICIRQ_PWRONR,
|
||||
MAX8997_PMICIRQ_PWRONF,
|
||||
MAX8997_PMICIRQ_PWRON1SEC,
|
||||
MAX8997_PMICIRQ_JIGONR,
|
||||
MAX8997_PMICIRQ_JIGONF,
|
||||
MAX8997_PMICIRQ_LOWBAT2,
|
||||
MAX8997_PMICIRQ_LOWBAT1,
|
||||
|
||||
MAX8997_PMICIRQ_JIGR,
|
||||
MAX8997_PMICIRQ_JIGF,
|
||||
MAX8997_PMICIRQ_MR,
|
||||
MAX8997_PMICIRQ_DVS1OK,
|
||||
MAX8997_PMICIRQ_DVS2OK,
|
||||
MAX8997_PMICIRQ_DVS3OK,
|
||||
MAX8997_PMICIRQ_DVS4OK,
|
||||
|
||||
MAX8997_PMICIRQ_CHGINS,
|
||||
MAX8997_PMICIRQ_CHGRM,
|
||||
MAX8997_PMICIRQ_DCINOVP,
|
||||
MAX8997_PMICIRQ_TOPOFFR,
|
||||
MAX8997_PMICIRQ_CHGRSTF,
|
||||
MAX8997_PMICIRQ_MBCHGTMEXPD,
|
||||
|
||||
MAX8997_PMICIRQ_RTC60S,
|
||||
MAX8997_PMICIRQ_RTCA1,
|
||||
MAX8997_PMICIRQ_RTCA2,
|
||||
MAX8997_PMICIRQ_SMPL_INT,
|
||||
MAX8997_PMICIRQ_RTC1S,
|
||||
MAX8997_PMICIRQ_WTSR,
|
||||
|
||||
MAX8997_MUICIRQ_ADCError,
|
||||
MAX8997_MUICIRQ_ADCLow,
|
||||
MAX8997_MUICIRQ_ADC,
|
||||
|
||||
MAX8997_MUICIRQ_VBVolt,
|
||||
MAX8997_MUICIRQ_DBChg,
|
||||
MAX8997_MUICIRQ_DCDTmr,
|
||||
MAX8997_MUICIRQ_ChgDetRun,
|
||||
MAX8997_MUICIRQ_ChgTyp,
|
||||
|
||||
MAX8997_MUICIRQ_OVP,
|
||||
|
||||
MAX8997_IRQ_NR,
|
||||
};
|
||||
|
||||
#define MAX8997_REG_BUCK1DVS(x) (MAX8997_REG_BUCK1DVS1 + (x) - 1)
|
||||
#define MAX8997_REG_BUCK2DVS(x) (MAX8997_REG_BUCK2DVS1 + (x) - 1)
|
||||
#define MAX8997_REG_BUCK5DVS(x) (MAX8997_REG_BUCK5DVS1 + (x) - 1)
|
||||
|
||||
struct max8997_dev {
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */
|
||||
struct i2c_client *rtc; /* slave addr 0x0c */
|
||||
struct i2c_client *haptic; /* slave addr 0x90 */
|
||||
struct i2c_client *muic; /* slave addr 0x4a */
|
||||
struct mutex iolock;
|
||||
|
||||
int type;
|
||||
struct platform_device *battery; /* battery control (not fuel gauge) */
|
||||
|
||||
bool wakeup;
|
||||
|
||||
/* For hibernation */
|
||||
u8 reg_dump[MAX8997_REG_PMIC_END + MAX8997_MUIC_REG_END +
|
||||
MAX8997_HAPTIC_REG_END];
|
||||
};
|
||||
|
||||
enum max8997_types {
|
||||
TYPE_MAX8997,
|
||||
TYPE_MAX8966,
|
||||
};
|
||||
|
||||
extern int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
|
||||
extern int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count,
|
||||
u8 *buf);
|
||||
extern int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value);
|
||||
extern int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count,
|
||||
u8 *buf);
|
||||
extern int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask);
|
||||
|
||||
#endif /* __LINUX_MFD_MAX8997_PRIV_H */
|
114
include/linux/mfd/max8997.h
Normal file
114
include/linux/mfd/max8997.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* max8997.h - Driver for the Maxim 8997/8966
|
||||
*
|
||||
* Copyright (C) 2009-2010 Samsung Electrnoics
|
||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* This driver is based on max8998.h
|
||||
*
|
||||
* MAX8997 has PMIC, MUIC, HAPTIC, RTC, FLASH, and Fuel Gauge devices.
|
||||
* Except Fuel Gauge, every device shares the same I2C bus and included in
|
||||
* this mfd driver. Although the fuel gauge is included in the chip, it is
|
||||
* excluded from the driver because a) it has a different I2C bus from
|
||||
* others and b) it can be enabled simply by using MAX17042 driver.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_MAX8998_H
|
||||
#define __LINUX_MFD_MAX8998_H
|
||||
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* MAX8997/8966 regulator IDs */
|
||||
enum max8998_regulators {
|
||||
MAX8997_LDO1 = 0,
|
||||
MAX8997_LDO2,
|
||||
MAX8997_LDO3,
|
||||
MAX8997_LDO4,
|
||||
MAX8997_LDO5,
|
||||
MAX8997_LDO6,
|
||||
MAX8997_LDO7,
|
||||
MAX8997_LDO8,
|
||||
MAX8997_LDO9,
|
||||
MAX8997_LDO10,
|
||||
MAX8997_LDO11,
|
||||
MAX8997_LDO12,
|
||||
MAX8997_LDO13,
|
||||
MAX8997_LDO14,
|
||||
MAX8997_LDO15,
|
||||
MAX8997_LDO16,
|
||||
MAX8997_LDO17,
|
||||
MAX8997_LDO18,
|
||||
MAX8997_LDO21,
|
||||
MAX8997_BUCK1,
|
||||
MAX8997_BUCK2,
|
||||
MAX8997_BUCK3,
|
||||
MAX8997_BUCK4,
|
||||
MAX8997_BUCK5,
|
||||
MAX8997_BUCK6,
|
||||
MAX8997_BUCK7,
|
||||
MAX8997_EN32KHZ_AP,
|
||||
MAX8997_EN32KHZ_CP,
|
||||
MAX8997_ENVICHG,
|
||||
MAX8997_ESAFEOUT1,
|
||||
MAX8997_ESAFEOUT2,
|
||||
MAX8997_CHARGER_CV, /* control MBCCV of MBCCTRL3 */
|
||||
MAX8997_CHARGER, /* charger current, MBCCTRL4 */
|
||||
MAX8997_CHARGER_TOPOFF, /* MBCCTRL5 */
|
||||
|
||||
MAX8997_REG_MAX,
|
||||
};
|
||||
|
||||
struct max8997_regulator_data {
|
||||
int id;
|
||||
struct regulator_init_data *initdata;
|
||||
};
|
||||
|
||||
struct max8997_platform_data {
|
||||
bool wakeup;
|
||||
/* IRQ: Not implemented */
|
||||
/* ---- PMIC ---- */
|
||||
struct max8997_regulator_data *regulators;
|
||||
int num_regulators;
|
||||
|
||||
/*
|
||||
* SET1~3 DVS GPIOs control Buck1, 2, and 5 simultaneously. Therefore,
|
||||
* With buckx_gpiodvs enabled, the buckx cannot be controlled
|
||||
* independently. To control buckx (of 1, 2, and 5) independently,
|
||||
* disable buckx_gpiodvs and control with BUCKxDVS1 register.
|
||||
*
|
||||
* When buckx_gpiodvs and bucky_gpiodvs are both enabled, set_voltage
|
||||
* on buckx will change the voltage of bucky at the same time.
|
||||
*
|
||||
*/
|
||||
bool ignore_gpiodvs_side_effect;
|
||||
int buck125_gpios[3]; /* GPIO of [0]SET1, [1]SET2, [2]SET3 */
|
||||
int buck125_default_idx; /* Default value of SET1, 2, 3 */
|
||||
unsigned int buck1_voltage[8]; /* buckx_voltage in uV */
|
||||
bool buck1_gpiodvs;
|
||||
unsigned int buck2_voltage[8];
|
||||
bool buck2_gpiodvs;
|
||||
unsigned int buck5_voltage[8];
|
||||
bool buck5_gpiodvs;
|
||||
|
||||
/* MUIC: Not implemented */
|
||||
/* HAPTIC: Not implemented */
|
||||
/* RTC: Not implemented */
|
||||
/* Flash: Not implemented */
|
||||
/* Charger control: Not implemented */
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_MAX8998_H */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user