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:
Linus Torvalds 2011-03-24 07:59:01 -07:00
commit a6a1d6485e
110 changed files with 6077 additions and 803 deletions

View 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.

View File

@ -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 */

View File

@ -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 = {

View File

@ -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 */

View File

@ -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,

View File

@ -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
};

View File

@ -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,
};

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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) {

View 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");

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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 = &regulator_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(&regulator_pdata[i], &pdata->regulator[i],
sizeof(struct regulator_init_data));
regulator_devs[i].mfd_data = &regulator_pdata[i];
regulator_devs[i].num_resources = 1;
regulator_devs[i].resources = &regulator_resources[j];
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
&regulator_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, &regulator_devs[0],
ARRAY_SIZE(regulator_devs),
&regulator_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);

View File

@ -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 },

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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");

View File

@ -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
View 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");

View 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");

View File

@ -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,
};

View File

@ -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)

View File

@ -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,
},
};

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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,

View File

@ -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
View 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");

View File

@ -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,

View File

@ -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",
&regulator_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,

View File

@ -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");

View File

@ -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)

View File

@ -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,
},
};

View File

@ -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);

View File

@ -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),

View File

@ -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);

View File

@ -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),

View File

@ -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
View 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, &regval);
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");

View File

@ -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");

View File

@ -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 &&

View File

@ -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
View 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, &reg, 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,
&regval, 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,
&regval, 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,
&regval, 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");

View File

@ -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);

View File

@ -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",

View File

@ -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);

View File

@ -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], &reg, 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 *)&reg;
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;

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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], &reg, 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 *)&reg;
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 = {

View File

@ -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++) {

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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);

View 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, &regval);
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, &regval);
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");

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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) {

View File

@ -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;

View File

@ -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 */

View 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

View File

@ -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 ;

View File

@ -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;

View 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 */

View 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 */

View File

@ -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;
};

View File

@ -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

View 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
View 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