浏览代码

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: (57 commits)
  regulator: Fix 88pm8607.c printk format warning
  input: Add support for Qualcomm PMIC8XXX power key
  input: Add Qualcomm pm8xxx keypad controller driver
  mfd: Add omap-usbhs runtime PM support
  mfd: Fix ASIC3 SD Host Controller Configuration size
  mfd: Fix omap_usbhs_alloc_children error handling
  mfd: Fix omap usbhs crash when rmmoding ehci or ohci
  mfd: Add ASIC3 LED support
  leds: Add ASIC3 LED support
  mfd: Update twl4030-code maintainer e-mail address
  mfd: Correct the name and bitmask for ab8500-gpadc BTempPullUp
  mfd: Add manual ab8500-gpadc batt temp activation for AB8500 3.0
  mfd: Provide ab8500-core enumerators for chip cuts
  mfd: Check twl4030-power remove script error condition after i2cwrite
  mfd: Fix twl6030 irq definitions
  mfd: Add phoenix lite (twl6025) support to twl6030
  mfd: Avoid to use constraint name in 88pm860x regulator driver
  mfd: Remove checking on max8925 regulator[0]
  mfd: Remove unused parameter from 88pm860x API
  mfd: Avoid to allocate 88pm860x static platform data
  ...
Linus Torvalds 14 年之前
父节点
当前提交
9f1912c48c
共有 93 个文件被更改,包括 3330 次插入534 次删除
  1. 2 0
      MAINTAINERS
  2. 1 1
      arch/arm/mach-omap2/board-rx51-peripherals.c
  3. 1 2
      drivers/dma/timb_dma.c
  4. 1 2
      drivers/gpio/janz-ttl.c
  5. 1 2
      drivers/gpio/rdc321x-gpio.c
  6. 3 3
      drivers/gpio/timbgpio.c
  7. 1 2
      drivers/i2c/busses/i2c-ocores.c
  8. 1 2
      drivers/i2c/busses/i2c-xiic.c
  9. 11 0
      drivers/input/keyboard/Kconfig
  10. 1 0
      drivers/input/keyboard/Makefile
  11. 799 0
      drivers/input/keyboard/pmic8xxx-keypad.c
  12. 11 0
      drivers/input/misc/Kconfig
  13. 1 0
      drivers/input/misc/Makefile
  14. 231 0
      drivers/input/misc/pmic8xxx-pwrkey.c
  15. 1 2
      drivers/input/misc/twl4030-vibra.c
  16. 10 0
      drivers/leds/Kconfig
  17. 1 0
      drivers/leds/Makefile
  18. 1 6
      drivers/leds/leds-88pm860x.c
  19. 165 0
      drivers/leds/leds-asic3.c
  20. 3 4
      drivers/leds/leds-mc13783.c
  21. 1 2
      drivers/media/radio/radio-timb.c
  22. 1 1
      drivers/media/radio/radio-wl1273.c
  23. 1 2
      drivers/media/video/timblogiw.c
  24. 75 80
      drivers/mfd/88pm860x-core.c
  25. 56 28
      drivers/mfd/Kconfig
  26. 2 0
      drivers/mfd/Makefile
  27. 4 2
      drivers/mfd/ab3100-core.c
  28. 4 2
      drivers/mfd/ab3550-core.c
  29. 16 16
      drivers/mfd/ab8500-core.c
  30. 33 1
      drivers/mfd/ab8500-gpadc.c
  31. 74 9
      drivers/mfd/asic3.c
  32. 4 2
      drivers/mfd/davinci_voicecodec.c
  33. 4 1
      drivers/mfd/htc-pasic3.c
  34. 2 1
      drivers/mfd/janz-cmodio.c
  35. 1 1
      drivers/mfd/max8925-core.c
  36. 7 5
      drivers/mfd/mc13xxx-core.c
  37. 7 0
      drivers/mfd/mfd-core.c
  38. 26 126
      drivers/mfd/omap-usb-host.c
  39. 212 0
      drivers/mfd/pm8921-core.c
  40. 371 0
      drivers/mfd/pm8xxx-irq.c
  41. 4 2
      drivers/mfd/rdc321x-southbridge.c
  42. 4 2
      drivers/mfd/t7l66xb.c
  43. 2 1
      drivers/mfd/tc6387xb.c
  44. 7 3
      drivers/mfd/tc6393xb.c
  45. 54 27
      drivers/mfd/timberdale.c
  46. 2 1
      drivers/mfd/tps6105x.c
  47. 2 2
      drivers/mfd/tps6586x.c
  48. 215 37
      drivers/mfd/twl-core.c
  49. 6 4
      drivers/mfd/twl4030-codec.c
  50. 3 3
      drivers/mfd/twl4030-power.c
  51. 2 2
      drivers/mfd/twl6030-irq.c
  52. 4 3
      drivers/mfd/wl1273-core.c
  53. 12 1
      drivers/mfd/wm831x-core.c
  54. 14 13
      drivers/mfd/wm831x-irq.c
  55. 2 1
      drivers/mfd/wm8400-core.c
  56. 1 1
      drivers/mmc/host/tmio_mmc.c
  57. 1 1
      drivers/mtd/nand/tmio_nand.c
  58. 1 2
      drivers/net/can/janz-ican3.c
  59. 1 2
      drivers/net/ks8842.c
  60. 2 8
      drivers/power/max8925_power.c
  61. 13 17
      drivers/regulator/88pm8607.c
  62. 1 2
      drivers/regulator/ab3100.c
  63. 2 2
      drivers/regulator/db8500-prcmu.c
  64. 8 3
      drivers/regulator/max8925-regulator.c
  65. 4 3
      drivers/regulator/mc13783-regulator.c
  66. 4 3
      drivers/regulator/mc13892-regulator.c
  67. 2 2
      drivers/regulator/tps6105x-regulator.c
  68. 10 0
      drivers/rtc/Kconfig
  69. 1 0
      drivers/rtc/Makefile
  70. 427 0
      drivers/rtc/rtc-88pm860x.c
  71. 1 2
      drivers/spi/xilinx_spi.c
  72. 1 6
      drivers/video/backlight/88pm860x_bl.c
  73. 5 7
      drivers/video/tmiofb.c
  74. 10 2
      drivers/w1/masters/ds1wm.c
  75. 1 2
      drivers/watchdog/rdc321x_wdt.c
  76. 52 2
      include/linux/i2c/twl.h
  77. 52 0
      include/linux/input/pmic8xxx-keypad.h
  78. 31 0
      include/linux/input/pmic8xxx-pwrkey.h
  79. 6 0
      include/linux/mfd/88pm860x.h
  80. 8 0
      include/linux/mfd/abx500.h
  81. 20 3
      include/linux/mfd/asic3.h
  82. 3 20
      include/linux/mfd/core.h
  83. 81 0
      include/linux/mfd/pm8xxx/core.h
  84. 59 0
      include/linux/mfd/pm8xxx/irq.h
  85. 31 0
      include/linux/mfd/pm8xxx/pm8921.h
  86. 1 1
      include/linux/mfd/twl4030-codec.h
  87. 0 26
      include/linux/mfd/wm831x/core.h
  88. 4 0
      include/linux/mfd/wm831x/pdata.h
  89. 1 2
      sound/soc/codecs/cq93vc.c
  90. 2 4
      sound/soc/codecs/twl4030.c
  91. 1 2
      sound/soc/codecs/wl1273.c
  92. 1 1
      sound/soc/codecs/wm8400.c
  93. 1 1
      sound/soc/davinci/davinci-vcif.c

+ 2 - 0
MAINTAINERS

@@ -931,6 +931,8 @@ F:	drivers/mmc/host/msm_sdcc.h
 F:	drivers/tty/serial/msm_serial.h
 F:	drivers/tty/serial/msm_serial.h
 F:	drivers/tty/serial/msm_serial.c
 F:	drivers/tty/serial/msm_serial.c
 F:	drivers/platform/msm/
 F:	drivers/platform/msm/
+F:	drivers/*/pm8???-*
+F:	include/linux/mfd/pm8xxx/
 T:	git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
 T:	git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
 S:	Maintained
 S:	Maintained
 
 

+ 1 - 1
arch/arm/mach-omap2/board-rx51-peripherals.c

@@ -729,7 +729,7 @@ static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
 	{ .resource = RES_RESET, .devgroup = -1,
 	{ .resource = RES_RESET, .devgroup = -1,
 	  .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
 	  .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
 	},
 	},
-	{ .resource = RES_Main_Ref, .devgroup = -1,
+	{ .resource = RES_MAIN_REF, .devgroup = -1,
 	  .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
 	  .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
 	},
 	},
 	{ 0, 0},
 	{ 0, 0},

+ 1 - 2
drivers/dma/timb_dma.c

@@ -27,7 +27,6 @@
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
 #include <linux/timb_dma.h>
 #include <linux/timb_dma.h>
@@ -685,7 +684,7 @@ static irqreturn_t td_irq(int irq, void *devid)
 
 
 static int __devinit td_probe(struct platform_device *pdev)
 static int __devinit td_probe(struct platform_device *pdev)
 {
 {
-	struct timb_dma_platform_data *pdata = mfd_get_data(pdev);
+	struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
 	struct timb_dma *td;
 	struct timb_dma *td;
 	struct resource *iomem;
 	struct resource *iomem;
 	int irq;
 	int irq;

+ 1 - 2
drivers/gpio/janz-ttl.c

@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
@@ -150,7 +149,7 @@ static int __devinit ttl_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct resource *res;
 	int ret;
 	int ret;
 
 
-	pdata = mfd_get_data(pdev);
+	pdata = pdev->dev.platform_data;
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(dev, "no platform data\n");
 		dev_err(dev, "no platform data\n");
 		ret = -ENXIO;
 		ret = -ENXIO;

+ 1 - 2
drivers/gpio/rdc321x-gpio.c

@@ -27,7 +27,6 @@
 #include <linux/pci.h>
 #include <linux/pci.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/mfd/rdc321x.h>
 #include <linux/mfd/rdc321x.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
 struct rdc321x_gpio {
 struct rdc321x_gpio {
@@ -136,7 +135,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
 	struct rdc321x_gpio *rdc321x_gpio_dev;
 	struct rdc321x_gpio *rdc321x_gpio_dev;
 	struct rdc321x_gpio_pdata *pdata;
 	struct rdc321x_gpio_pdata *pdata;
 
 
-	pdata = mfd_get_data(pdev);
+	pdata = pdev->dev.platform_data;
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		return -ENODEV;
 		return -ENODEV;

+ 3 - 3
drivers/gpio/timbgpio.c

@@ -23,7 +23,6 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/timb_gpio.h>
 #include <linux/timb_gpio.h>
@@ -229,7 +228,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
 	struct gpio_chip *gc;
 	struct gpio_chip *gc;
 	struct timbgpio *tgpio;
 	struct timbgpio *tgpio;
 	struct resource *iomem;
 	struct resource *iomem;
-	struct timbgpio_platform_data *pdata = mfd_get_data(pdev);
+	struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
 	int irq = platform_get_irq(pdev, 0);
 	int irq = platform_get_irq(pdev, 0);
 
 
 	if (!pdata || pdata->nr_pins > 32) {
 	if (!pdata || pdata->nr_pins > 32) {
@@ -320,13 +319,14 @@ err_mem:
 static int __devexit timbgpio_remove(struct platform_device *pdev)
 static int __devexit timbgpio_remove(struct platform_device *pdev)
 {
 {
 	int err;
 	int err;
+	struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
 	struct timbgpio *tgpio = platform_get_drvdata(pdev);
 	struct timbgpio *tgpio = platform_get_drvdata(pdev);
 	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	int irq = platform_get_irq(pdev, 0);
 	int irq = platform_get_irq(pdev, 0);
 
 
 	if (irq >= 0 && tgpio->irq_base > 0) {
 	if (irq >= 0 && tgpio->irq_base > 0) {
 		int i;
 		int i;
-		for (i = 0; i < tgpio->gpio.ngpio; i++) {
+		for (i = 0; i < pdata->nr_pins; i++) {
 			irq_set_chip(tgpio->irq_base + i, NULL);
 			irq_set_chip(tgpio->irq_base + i, NULL);
 			irq_set_chip_data(tgpio->irq_base + i, NULL);
 			irq_set_chip_data(tgpio->irq_base + i, NULL);
 		}
 		}

+ 1 - 2
drivers/i2c/busses/i2c-ocores.c

@@ -49,7 +49,6 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
@@ -306,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
-	pdata = mfd_get_data(pdev);
+	pdata = pdev->dev.platform_data;
 	if (pdata) {
 	if (pdata) {
 		i2c->regstep = pdata->regstep;
 		i2c->regstep = pdata->regstep;
 		i2c->clock_khz = pdata->clock_khz;
 		i2c->clock_khz = pdata->clock_khz;

+ 1 - 2
drivers/i2c/busses/i2c-xiic.c

@@ -34,7 +34,6 @@
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
@@ -705,7 +704,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev)
 	if (irq < 0)
 	if (irq < 0)
 		goto resource_missing;
 		goto resource_missing;
 
 
-	pdata = mfd_get_data(pdev);
+	pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
 	if (!pdata)
 	if (!pdata)
 		return -EINVAL;
 		return -EINVAL;
 
 

+ 11 - 0
drivers/input/keyboard/Kconfig

@@ -412,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called pxa930_rotary.
 	  module will be called pxa930_rotary.
 
 
+config KEYBOARD_PMIC8XXX
+	tristate "Qualcomm PMIC8XXX keypad support"
+	depends on MFD_PM8XXX
+	help
+	  Say Y here if you want to enable the driver for the PMIC8XXX
+	  keypad provided as a reference design from Qualcomm. This is intended
+	  to support upto 18x8 matrix based keypad design.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called pmic8xxx-keypad.
+
 config KEYBOARD_SAMSUNG
 config KEYBOARD_SAMSUNG
 	tristate "Samsung keypad support"
 	tristate "Samsung keypad support"
 	depends on SAMSUNG_DEV_KEYPAD
 	depends on SAMSUNG_DEV_KEYPAD

+ 1 - 0
drivers/input/keyboard/Makefile

@@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_NOMADIK)		+= nomadik-ske-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP4)		+= omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP4)		+= omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
+obj-$(CONFIG_KEYBOARD_PMIC8XXX)		+= pmic8xxx-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o
 obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o

+ 799 - 0
drivers/input/keyboard/pmic8xxx-keypad.c

@@ -0,0 +1,799 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/input/pmic8xxx-keypad.h>
+
+#define PM8XXX_MAX_ROWS		18
+#define PM8XXX_MAX_COLS		8
+#define PM8XXX_ROW_SHIFT	3
+#define PM8XXX_MATRIX_MAX_SIZE	(PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS)
+
+#define PM8XXX_MIN_ROWS		5
+#define PM8XXX_MIN_COLS		5
+
+#define MAX_SCAN_DELAY		128
+#define MIN_SCAN_DELAY		1
+
+/* in nanoseconds */
+#define MAX_ROW_HOLD_DELAY	122000
+#define MIN_ROW_HOLD_DELAY	30500
+
+#define MAX_DEBOUNCE_TIME	20
+#define MIN_DEBOUNCE_TIME	5
+
+#define KEYP_CTRL			0x148
+
+#define KEYP_CTRL_EVNTS			BIT(0)
+#define KEYP_CTRL_EVNTS_MASK		0x3
+
+#define KEYP_CTRL_SCAN_COLS_SHIFT	5
+#define KEYP_CTRL_SCAN_COLS_MIN		5
+#define KEYP_CTRL_SCAN_COLS_BITS	0x3
+
+#define KEYP_CTRL_SCAN_ROWS_SHIFT	2
+#define KEYP_CTRL_SCAN_ROWS_MIN		5
+#define KEYP_CTRL_SCAN_ROWS_BITS	0x7
+
+#define KEYP_CTRL_KEYP_EN		BIT(7)
+
+#define KEYP_SCAN			0x149
+
+#define KEYP_SCAN_READ_STATE		BIT(0)
+#define KEYP_SCAN_DBOUNCE_SHIFT		1
+#define KEYP_SCAN_PAUSE_SHIFT		3
+#define KEYP_SCAN_ROW_HOLD_SHIFT	6
+
+#define KEYP_TEST			0x14A
+
+#define KEYP_TEST_CLEAR_RECENT_SCAN	BIT(6)
+#define KEYP_TEST_CLEAR_OLD_SCAN	BIT(5)
+#define KEYP_TEST_READ_RESET		BIT(4)
+#define KEYP_TEST_DTEST_EN		BIT(3)
+#define KEYP_TEST_ABORT_READ		BIT(0)
+
+#define KEYP_TEST_DBG_SELECT_SHIFT	1
+
+/* bits of these registers represent
+ * '0' for key press
+ * '1' for key release
+ */
+#define KEYP_RECENT_DATA		0x14B
+#define KEYP_OLD_DATA			0x14C
+
+#define KEYP_CLOCK_FREQ			32768
+
+/**
+ * struct pmic8xxx_kp - internal keypad data structure
+ * @pdata - keypad platform data pointer
+ * @input - input device pointer for keypad
+ * @key_sense_irq - key press/release irq number
+ * @key_stuck_irq - key stuck notification irq number
+ * @keycodes - array to hold the key codes
+ * @dev - parent device pointer
+ * @keystate - present key press/release state
+ * @stuckstate - present state when key stuck irq
+ * @ctrl_reg - control register value
+ */
+struct pmic8xxx_kp {
+	const struct pm8xxx_keypad_platform_data *pdata;
+	struct input_dev *input;
+	int key_sense_irq;
+	int key_stuck_irq;
+
+	unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE];
+
+	struct device *dev;
+	u16 keystate[PM8XXX_MAX_ROWS];
+	u16 stuckstate[PM8XXX_MAX_ROWS];
+
+	u8 ctrl_reg;
+};
+
+static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp,
+				 u8 data, u16 reg)
+{
+	int rc;
+
+	rc = pm8xxx_writeb(kp->dev->parent, reg, data);
+	return rc;
+}
+
+static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp,
+				 u8 *data, u16 reg, unsigned num_bytes)
+{
+	int rc;
+
+	rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes);
+	return rc;
+}
+
+static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp,
+				 u8 *data, u16 reg)
+{
+	int rc;
+
+	rc = pmic8xxx_kp_read(kp, data, reg, 1);
+	return rc;
+}
+
+static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
+{
+	/* all keys pressed on that particular row? */
+	if (col == 0x00)
+		return 1 << kp->pdata->num_cols;
+	else
+		return col & ((1 << kp->pdata->num_cols) - 1);
+}
+
+/*
+ * Synchronous read protocol for RevB0 onwards:
+ *
+ * 1. Write '1' to ReadState bit in KEYP_SCAN register
+ * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
+ *    synchronously
+ * 3. Read rows in old array first if events are more than one
+ * 4. Read rows in recent array
+ * 5. Wait 4*32KHz clocks
+ * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
+ *    synchronously exit read mode.
+ */
+static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
+{
+	int rc;
+	u8 scan_val;
+
+	rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+	if (rc < 0) {
+		dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	scan_val |= 0x1;
+
+	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+	if (rc < 0) {
+		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* 2 * 32KHz clocks */
+	udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
+
+	return rc;
+}
+
+static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
+					u16 data_reg, int read_rows)
+{
+	int rc, row;
+	u8 new_data[PM8XXX_MAX_ROWS];
+
+	rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows);
+	if (rc)
+		return rc;
+
+	for (row = 0; row < kp->pdata->num_rows; row++) {
+		dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
+					new_data[row]);
+		state[row] = pmic8xxx_col_state(kp, new_data[row]);
+	}
+
+	return rc;
+}
+
+static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
+					 u16 *old_state)
+{
+	int rc, read_rows;
+	u8 scan_val;
+
+	if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
+		read_rows = PM8XXX_MIN_ROWS;
+	else
+		read_rows = kp->pdata->num_rows;
+
+	pmic8xxx_chk_sync_read(kp);
+
+	if (old_state) {
+		rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA,
+						read_rows);
+		if (rc < 0) {
+			dev_err(kp->dev,
+				"Error reading KEYP_OLD_DATA, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA,
+					 read_rows);
+	if (rc < 0) {
+		dev_err(kp->dev,
+			"Error reading KEYP_RECENT_DATA, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* 4 * 32KHz clocks */
+	udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
+
+	rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+	if (rc < 0) {
+		dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	scan_val &= 0xFE;
+	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+	if (rc < 0)
+		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+
+	return rc;
+}
+
+static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
+					 u16 *old_state)
+{
+	int row, col, code;
+
+	for (row = 0; row < kp->pdata->num_rows; row++) {
+		int bits_changed = new_state[row] ^ old_state[row];
+
+		if (!bits_changed)
+			continue;
+
+		for (col = 0; col < kp->pdata->num_cols; col++) {
+			if (!(bits_changed & (1 << col)))
+				continue;
+
+			dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col,
+					!(new_state[row] & (1 << col)) ?
+					"pressed" : "released");
+
+			code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT);
+
+			input_event(kp->input, EV_MSC, MSC_SCAN, code);
+			input_report_key(kp->input,
+					kp->keycodes[code],
+					!(new_state[row] & (1 << col)));
+
+			input_sync(kp->input);
+		}
+	}
+}
+
+static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
+{
+	int row, found_first = -1;
+	u16 check, row_state;
+
+	check = 0;
+	for (row = 0; row < kp->pdata->num_rows; row++) {
+		row_state = (~new_state[row]) &
+				 ((1 << kp->pdata->num_cols) - 1);
+
+		if (hweight16(row_state) > 1) {
+			if (found_first == -1)
+				found_first = row;
+			if (check & row_state) {
+				dev_dbg(kp->dev, "detected ghost key on row[%d]"
+					 " and row[%d]\n", found_first, row);
+				return true;
+			}
+		}
+		check |= row_state;
+	}
+	return false;
+}
+
+static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events)
+{
+	u16 new_state[PM8XXX_MAX_ROWS];
+	u16 old_state[PM8XXX_MAX_ROWS];
+	int rc;
+
+	switch (events) {
+	case 0x1:
+		rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL);
+		if (rc < 0)
+			return rc;
+
+		/* detecting ghost key is not an error */
+		if (pmic8xxx_detect_ghost_keys(kp, new_state))
+			return 0;
+		__pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate);
+		memcpy(kp->keystate, new_state, sizeof(new_state));
+	break;
+	case 0x3: /* two events - eventcounter is gray-coded */
+		rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+		if (rc < 0)
+			return rc;
+
+		__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
+		__pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
+		memcpy(kp->keystate, new_state, sizeof(new_state));
+	break;
+	case 0x2:
+		dev_dbg(kp->dev, "Some key events were lost\n");
+		rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+		if (rc < 0)
+			return rc;
+		__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
+		__pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
+		memcpy(kp->keystate, new_state, sizeof(new_state));
+	break;
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+/*
+ * NOTE: We are reading recent and old data registers blindly
+ * whenever key-stuck interrupt happens, because events counter doesn't
+ * get updated when this interrupt happens due to key stuck doesn't get
+ * considered as key state change.
+ *
+ * We are not using old data register contents after they are being read
+ * because it might report the key which was pressed before the key being stuck
+ * as stuck key because it's pressed status is stored in the old data
+ * register.
+ */
+static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)
+{
+	u16 new_state[PM8XXX_MAX_ROWS];
+	u16 old_state[PM8XXX_MAX_ROWS];
+	int rc;
+	struct pmic8xxx_kp *kp = data;
+
+	rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+	if (rc < 0) {
+		dev_err(kp->dev, "failed to read keypad matrix\n");
+		return IRQ_HANDLED;
+	}
+
+	__pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
+{
+	struct pmic8xxx_kp *kp = data;
+	u8 ctrl_val, events;
+	int rc;
+
+	rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
+	if (rc < 0) {
+		dev_err(kp->dev, "failed to read keyp_ctrl register\n");
+		return IRQ_HANDLED;
+	}
+
+	events = ctrl_val & KEYP_CTRL_EVNTS_MASK;
+
+	rc = pmic8xxx_kp_scan_matrix(kp, events);
+	if (rc < 0)
+		dev_err(kp->dev, "failed to scan matrix\n");
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
+{
+	int bits, rc, cycles;
+	u8 scan_val = 0, ctrl_val = 0;
+	static const u8 row_bits[] = {
+		0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
+	};
+
+	/* Find column bits */
+	if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
+		bits = 0;
+	else
+		bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
+	ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
+		KEYP_CTRL_SCAN_COLS_SHIFT;
+
+	/* Find row bits */
+	if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
+		bits = 0;
+	else
+		bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
+
+	ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
+
+	rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
+	if (rc < 0) {
+		dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
+		return rc;
+	}
+
+	bits = (kp->pdata->debounce_ms / 5) - 1;
+
+	scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
+
+	bits = fls(kp->pdata->scan_delay_ms) - 1;
+	scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
+
+	/* Row hold time is a multiple of 32KHz cycles. */
+	cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
+
+	scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
+
+	rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+	if (rc)
+		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+
+	return rc;
+
+}
+
+static int  __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
+			struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
+{
+	int	rc, i;
+
+	if (gpio_start < 0 || num_gpios < 0)
+		return -EINVAL;
+
+	for (i = 0; i < num_gpios; i++) {
+		rc = pm8xxx_gpio_config(gpio_start + i, gpio_config);
+		if (rc) {
+			dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():"
+					"for PM GPIO [%d] rc=%d.\n",
+					__func__, gpio_start + i, rc);
+			return rc;
+		}
+	 }
+
+	return 0;
+}
+
+static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
+{
+	int rc;
+
+	kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
+
+	rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+	if (rc < 0)
+		dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
+{
+	int rc;
+
+	kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
+
+	rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+	if (rc < 0)
+		return rc;
+
+	return rc;
+}
+
+static int pmic8xxx_kp_open(struct input_dev *dev)
+{
+	struct pmic8xxx_kp *kp = input_get_drvdata(dev);
+
+	return pmic8xxx_kp_enable(kp);
+}
+
+static void pmic8xxx_kp_close(struct input_dev *dev)
+{
+	struct pmic8xxx_kp *kp = input_get_drvdata(dev);
+
+	pmic8xxx_kp_disable(kp);
+}
+
+/*
+ * keypad controller should be initialized in the following sequence
+ * only, otherwise it might get into FSM stuck state.
+ *
+ * - Initialize keypad control parameters, like no. of rows, columns,
+ *   timing values etc.,
+ * - configure rows and column gpios pull up/down.
+ * - set irq edge type.
+ * - enable the keypad controller.
+ */
+static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
+{
+	const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev);
+	const struct matrix_keymap_data *keymap_data;
+	struct pmic8xxx_kp *kp;
+	int rc;
+	u8 ctrl_val;
+
+	struct pm_gpio kypd_drv = {
+		.direction	= PM_GPIO_DIR_OUT,
+		.output_buffer	= PM_GPIO_OUT_BUF_OPEN_DRAIN,
+		.output_value	= 0,
+		.pull		= PM_GPIO_PULL_NO,
+		.vin_sel	= PM_GPIO_VIN_S3,
+		.out_strength	= PM_GPIO_STRENGTH_LOW,
+		.function	= PM_GPIO_FUNC_1,
+		.inv_int_pol	= 1,
+	};
+
+	struct pm_gpio kypd_sns = {
+		.direction	= PM_GPIO_DIR_IN,
+		.pull		= PM_GPIO_PULL_UP_31P5,
+		.vin_sel	= PM_GPIO_VIN_S3,
+		.out_strength	= PM_GPIO_STRENGTH_NO,
+		.function	= PM_GPIO_FUNC_NORMAL,
+		.inv_int_pol	= 1,
+	};
+
+
+	if (!pdata || !pdata->num_cols || !pdata->num_rows ||
+		pdata->num_cols > PM8XXX_MAX_COLS ||
+		pdata->num_rows > PM8XXX_MAX_ROWS ||
+		pdata->num_cols < PM8XXX_MIN_COLS) {
+		dev_err(&pdev->dev, "invalid platform data\n");
+		return -EINVAL;
+	}
+
+	if (!pdata->scan_delay_ms ||
+		pdata->scan_delay_ms > MAX_SCAN_DELAY ||
+		pdata->scan_delay_ms < MIN_SCAN_DELAY ||
+		!is_power_of_2(pdata->scan_delay_ms)) {
+		dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
+		return -EINVAL;
+	}
+
+	if (!pdata->row_hold_ns ||
+		pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
+		pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
+		((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
+		dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
+		return -EINVAL;
+	}
+
+	if (!pdata->debounce_ms ||
+		((pdata->debounce_ms % 5) != 0) ||
+		pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
+		pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
+		dev_err(&pdev->dev, "invalid debounce time supplied\n");
+		return -EINVAL;
+	}
+
+	keymap_data = pdata->keymap_data;
+	if (!keymap_data) {
+		dev_err(&pdev->dev, "no keymap data supplied\n");
+		return -EINVAL;
+	}
+
+	kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+	if (!kp)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, kp);
+
+	kp->pdata	= pdata;
+	kp->dev		= &pdev->dev;
+
+	kp->input = input_allocate_device();
+	if (!kp->input) {
+		dev_err(&pdev->dev, "unable to allocate input device\n");
+		rc = -ENOMEM;
+		goto err_alloc_device;
+	}
+
+	kp->key_sense_irq = platform_get_irq(pdev, 0);
+	if (kp->key_sense_irq < 0) {
+		dev_err(&pdev->dev, "unable to get keypad sense irq\n");
+		rc = -ENXIO;
+		goto err_get_irq;
+	}
+
+	kp->key_stuck_irq = platform_get_irq(pdev, 1);
+	if (kp->key_stuck_irq < 0) {
+		dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
+		rc = -ENXIO;
+		goto err_get_irq;
+	}
+
+	kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
+	kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
+
+	kp->input->dev.parent	= &pdev->dev;
+
+	kp->input->id.bustype	= BUS_I2C;
+	kp->input->id.version	= 0x0001;
+	kp->input->id.product	= 0x0001;
+	kp->input->id.vendor	= 0x0001;
+
+	kp->input->evbit[0]	= BIT_MASK(EV_KEY);
+
+	if (pdata->rep)
+		__set_bit(EV_REP, kp->input->evbit);
+
+	kp->input->keycode	= kp->keycodes;
+	kp->input->keycodemax	= PM8XXX_MATRIX_MAX_SIZE;
+	kp->input->keycodesize	= sizeof(kp->keycodes);
+	kp->input->open		= pmic8xxx_kp_open;
+	kp->input->close	= pmic8xxx_kp_close;
+
+	matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
+					kp->input->keycode, kp->input->keybit);
+
+	input_set_capability(kp->input, EV_MSC, MSC_SCAN);
+	input_set_drvdata(kp->input, kp);
+
+	/* initialize keypad state */
+	memset(kp->keystate, 0xff, sizeof(kp->keystate));
+	memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
+
+	rc = pmic8xxx_kpd_init(kp);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "unable to initialize keypad controller\n");
+		goto err_get_irq;
+	}
+
+	rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start,
+					pdata->num_cols, kp, &kypd_sns);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
+		goto err_gpio_config;
+	}
+
+	rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start,
+					pdata->num_rows, kp, &kypd_drv);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
+		goto err_gpio_config;
+	}
+
+	rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq,
+				 IRQF_TRIGGER_RISING, "pmic-keypad", kp);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "failed to request keypad sense irq\n");
+		goto err_get_irq;
+	}
+
+	rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq,
+				 IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
+		goto err_req_stuck_irq;
+	}
+
+	rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n");
+		goto err_pmic_reg_read;
+	}
+
+	kp->ctrl_reg = ctrl_val;
+
+	rc = input_register_device(kp->input);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "unable to register keypad input device\n");
+		goto err_pmic_reg_read;
+	}
+
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+	return 0;
+
+err_pmic_reg_read:
+	free_irq(kp->key_stuck_irq, NULL);
+err_req_stuck_irq:
+	free_irq(kp->key_sense_irq, NULL);
+err_gpio_config:
+err_get_irq:
+	input_free_device(kp->input);
+err_alloc_device:
+	platform_set_drvdata(pdev, NULL);
+	kfree(kp);
+	return rc;
+}
+
+static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev)
+{
+	struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	free_irq(kp->key_stuck_irq, NULL);
+	free_irq(kp->key_sense_irq, NULL);
+	input_unregister_device(kp->input);
+	kfree(kp);
+
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pmic8xxx_kp_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+	struct input_dev *input_dev = kp->input;
+
+	if (device_may_wakeup(dev)) {
+		enable_irq_wake(kp->key_sense_irq);
+	} else {
+		mutex_lock(&input_dev->mutex);
+
+		if (input_dev->users)
+			pmic8xxx_kp_disable(kp);
+
+		mutex_unlock(&input_dev->mutex);
+	}
+
+	return 0;
+}
+
+static int pmic8xxx_kp_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+	struct input_dev *input_dev = kp->input;
+
+	if (device_may_wakeup(dev)) {
+		disable_irq_wake(kp->key_sense_irq);
+	} else {
+		mutex_lock(&input_dev->mutex);
+
+		if (input_dev->users)
+			pmic8xxx_kp_enable(kp);
+
+		mutex_unlock(&input_dev->mutex);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
+			 pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
+
+static struct platform_driver pmic8xxx_kp_driver = {
+	.probe		= pmic8xxx_kp_probe,
+	.remove		= __devexit_p(pmic8xxx_kp_remove),
+	.driver		= {
+		.name = PM8XXX_KEYPAD_DEV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &pm8xxx_kp_pm_ops,
+	},
+};
+
+static int __init pmic8xxx_kp_init(void)
+{
+	return platform_driver_register(&pmic8xxx_kp_driver);
+}
+module_init(pmic8xxx_kp_init);
+
+static void __exit pmic8xxx_kp_exit(void)
+{
+	platform_driver_unregister(&pmic8xxx_kp_driver);
+}
+module_exit(pmic8xxx_kp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC8XXX keypad driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:pmic8xxx_keypad");
+MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");

+ 11 - 0
drivers/input/misc/Kconfig

@@ -330,6 +330,17 @@ config INPUT_PWM_BEEPER
 	  To compile this driver as a module, choose M here: the module will be
 	  To compile this driver as a module, choose M here: the module will be
 	  called pwm-beeper.
 	  called pwm-beeper.
 
 
+config INPUT_PMIC8XXX_PWRKEY
+	tristate "PMIC8XXX power key support"
+	depends on MFD_PM8XXX
+	help
+	  Say Y here if you want support for the PMIC8XXX power key.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pmic8xxx-pwrkey.
+
 config INPUT_GPIO_ROTARY_ENCODER
 config INPUT_GPIO_ROTARY_ENCODER
 	tristate "Rotary encoders connected to GPIO pins"
 	tristate "Rotary encoders connected to GPIO pins"
 	depends on GPIOLIB && GENERIC_GPIO
 	depends on GPIOLIB && GENERIC_GPIO

+ 1 - 0
drivers/input/misc/Makefile

@@ -33,6 +33,7 @@ obj-$(CONFIG_INPUT_PCF8574)		+= pcf8574_keypad.o
 obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
 obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
+obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
 obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o

+ 231 - 0
drivers/input/misc/pmic8xxx-pwrkey.c

@@ -0,0 +1,231 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/log2.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/input/pmic8xxx-pwrkey.h>
+
+#define PON_CNTL_1 0x1C
+#define PON_CNTL_PULL_UP BIT(7)
+#define PON_CNTL_TRIG_DELAY_MASK (0x7)
+
+/**
+ * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
+ * @key_press_irq: key press irq number
+ */
+struct pmic8xxx_pwrkey {
+	struct input_dev *pwr;
+	int key_press_irq;
+};
+
+static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
+{
+	struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+	input_report_key(pwrkey->pwr, KEY_POWER, 1);
+	input_sync(pwrkey->pwr);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
+{
+	struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+	input_report_key(pwrkey->pwr, KEY_POWER, 0);
+	input_sync(pwrkey->pwr);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pmic8xxx_pwrkey_suspend(struct device *dev)
+{
+	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(pwrkey->key_press_irq);
+
+	return 0;
+}
+
+static int pmic8xxx_pwrkey_resume(struct device *dev)
+{
+	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(pwrkey->key_press_irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
+		pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
+
+static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
+{
+	struct input_dev *pwr;
+	int key_release_irq = platform_get_irq(pdev, 0);
+	int key_press_irq = platform_get_irq(pdev, 1);
+	int err;
+	unsigned int delay;
+	u8 pon_cntl;
+	struct pmic8xxx_pwrkey *pwrkey;
+	const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev);
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "power key platform data not supplied\n");
+		return -EINVAL;
+	}
+
+	if (pdata->kpd_trigger_delay_us > 62500) {
+		dev_err(&pdev->dev, "invalid power key trigger delay\n");
+		return -EINVAL;
+	}
+
+	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
+	if (!pwrkey)
+		return -ENOMEM;
+
+	pwr = input_allocate_device();
+	if (!pwr) {
+		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+		err = -ENOMEM;
+		goto free_pwrkey;
+	}
+
+	input_set_capability(pwr, EV_KEY, KEY_POWER);
+
+	pwr->name = "pmic8xxx_pwrkey";
+	pwr->phys = "pmic8xxx_pwrkey/input0";
+	pwr->dev.parent = &pdev->dev;
+
+	delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
+	delay = 1 + ilog2(delay);
+
+	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
+		goto free_input_dev;
+	}
+
+	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+	if (pdata->pull_up)
+		pon_cntl |= PON_CNTL_PULL_UP;
+	else
+		pon_cntl &= ~PON_CNTL_PULL_UP;
+
+	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+		goto free_input_dev;
+	}
+
+	err = input_register_device(pwr);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
+		goto free_input_dev;
+	}
+
+	pwrkey->key_press_irq = key_press_irq;
+	pwrkey->pwr = pwr;
+
+	platform_set_drvdata(pdev, pwrkey);
+
+	err = request_irq(key_press_irq, pwrkey_press_irq,
+		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+				 key_press_irq, err);
+		goto unreg_input_dev;
+	}
+
+	err = request_irq(key_release_irq, pwrkey_release_irq,
+		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+				 key_release_irq, err);
+
+		goto free_press_irq;
+	}
+
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+	return 0;
+
+free_press_irq:
+	free_irq(key_press_irq, NULL);
+unreg_input_dev:
+	platform_set_drvdata(pdev, NULL);
+	input_unregister_device(pwr);
+	pwr = NULL;
+free_input_dev:
+	input_free_device(pwr);
+free_pwrkey:
+	kfree(pwrkey);
+	return err;
+}
+
+static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
+{
+	struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
+	int key_release_irq = platform_get_irq(pdev, 0);
+	int key_press_irq = platform_get_irq(pdev, 1);
+
+	device_init_wakeup(&pdev->dev, 0);
+
+	free_irq(key_press_irq, pwrkey);
+	free_irq(key_release_irq, pwrkey);
+	input_unregister_device(pwrkey->pwr);
+	platform_set_drvdata(pdev, NULL);
+	kfree(pwrkey);
+
+	return 0;
+}
+
+static struct platform_driver pmic8xxx_pwrkey_driver = {
+	.probe		= pmic8xxx_pwrkey_probe,
+	.remove		= __devexit_p(pmic8xxx_pwrkey_remove),
+	.driver		= {
+		.name	= PM8XXX_PWRKEY_DEV_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &pm8xxx_pwr_key_pm_ops,
+	},
+};
+
+static int __init pmic8xxx_pwrkey_init(void)
+{
+	return platform_driver_register(&pmic8xxx_pwrkey_driver);
+}
+module_init(pmic8xxx_pwrkey_init);
+
+static void __exit pmic8xxx_pwrkey_exit(void)
+{
+	platform_driver_unregister(&pmic8xxx_pwrkey_driver);
+}
+module_exit(pmic8xxx_pwrkey_exit);
+
+MODULE_ALIAS("platform:pmic8xxx_pwrkey");
+MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");

+ 1 - 2
drivers/input/misc/twl4030-vibra.c

@@ -29,7 +29,6 @@
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 #include <linux/mfd/twl4030-codec.h>
 #include <linux/mfd/twl4030-codec.h>
-#include <linux/mfd/core.h>
 #include <linux/input.h>
 #include <linux/input.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
@@ -197,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
 
 
 static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 {
 {
-	struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev);
+	struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
 	struct vibra_info *info;
 	struct vibra_info *info;
 	int ret;
 	int ret;
 
 

+ 10 - 0
drivers/leds/Kconfig

@@ -389,6 +389,16 @@ config LEDS_NETXBIG
 	  and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
 	  and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
 	  controlled through a GPIO extension bus.
 	  controlled through a GPIO extension bus.
 
 
+config LEDS_ASIC3
+	bool "LED support for the HTC ASIC3"
+	depends on MFD_ASIC3
+	default y
+	help
+	  This option enables support for the LEDs on the HTC ASIC3. The HTC
+	  ASIC3 LED GPIOs are inputs, not outputs, thus the leds-gpio driver
+	  cannot be used. This driver supports hardware blinking with an on+off
+	  period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
+
 config LEDS_TRIGGERS
 config LEDS_TRIGGERS
 	bool "LED Trigger support"
 	bool "LED Trigger support"
 	depends on LEDS_CLASS
 	depends on LEDS_CLASS

+ 1 - 0
drivers/leds/Makefile

@@ -42,6 +42,7 @@ obj-$(CONFIG_LEDS_DELL_NETBOOKS)	+= dell-led.o
 obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
 obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
 obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
 obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
 obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
+obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
 
 
 # LED SPI Drivers
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o

+ 1 - 6
drivers/leds/leds-88pm860x.c

@@ -17,7 +17,6 @@
 #include <linux/leds.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
-#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/mfd/88pm860x.h>
 
 
 #define LED_PWM_SHIFT		(3)
 #define LED_PWM_SHIFT		(3)
@@ -171,7 +170,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct pm860x_led_pdata *pdata;
 	struct pm860x_led_pdata *pdata;
 	struct pm860x_led *data;
 	struct pm860x_led *data;
-	struct mfd_cell *cell;
 	struct resource *res;
 	struct resource *res;
 	int ret;
 	int ret;
 
 
@@ -181,10 +179,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	cell = pdev->dev.platform_data;
-	if (cell == NULL)
-		return -ENODEV;
-	pdata = cell->mfd_data;
+	pdata = pdev->dev.platform_data;
 	if (pdata == NULL) {
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "No platform data!\n");
 		dev_err(&pdev->dev, "No platform data!\n");
 		return -EINVAL;
 		return -EINVAL;

+ 165 - 0
drivers/leds/leds-asic3.c

@@ -0,0 +1,165 @@
+/*
+ *  Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/asic3.h>
+#include <linux/mfd/core.h>
+
+/*
+ *	The HTC ASIC3 LED GPIOs are inputs, not outputs.
+ *	Hence we turn the LEDs on/off via the TimeBase register.
+ */
+
+/*
+ *	When TimeBase is 4 the clock resolution is about 32Hz.
+ *	This driver supports hardware blinking with an on+off
+ *	period from 62ms (2 clocks) to 125s (4000 clocks).
+ */
+#define MS_TO_CLK(ms)	DIV_ROUND_CLOSEST(((ms)*1024), 32000)
+#define CLK_TO_MS(clk)	(((clk)*32000)/1024)
+#define MAX_CLK		4000            /* Fits into 12-bit Time registers */
+#define MAX_MS		CLK_TO_MS(MAX_CLK)
+
+static const unsigned int led_n_base[ASIC3_NUM_LEDS] = {
+	[0] = ASIC3_LED_0_Base,
+	[1] = ASIC3_LED_1_Base,
+	[2] = ASIC3_LED_2_Base,
+};
+
+static void brightness_set(struct led_classdev *cdev,
+	enum led_brightness value)
+{
+	struct platform_device *pdev = to_platform_device(cdev->dev->parent);
+	const struct mfd_cell *cell = mfd_get_cell(pdev);
+	struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+	u32 timebase;
+	unsigned int base;
+
+	timebase = (value == LED_OFF) ? 0 : (LED_EN|0x4);
+
+	base = led_n_base[cell->id];
+	asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), 32);
+	asic3_write_register(asic, (base + ASIC3_LED_DutyTime), 32);
+	asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
+	asic3_write_register(asic, (base + ASIC3_LED_TimeBase), timebase);
+}
+
+static int blink_set(struct led_classdev *cdev,
+	unsigned long *delay_on,
+	unsigned long *delay_off)
+{
+	struct platform_device *pdev = to_platform_device(cdev->dev->parent);
+	const struct mfd_cell *cell = mfd_get_cell(pdev);
+	struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+	u32 on;
+	u32 off;
+	unsigned int base;
+
+	if (*delay_on > MAX_MS || *delay_off > MAX_MS)
+		return -EINVAL;
+
+	if (*delay_on == 0 && *delay_off == 0) {
+		/* If both are zero then a sensible default should be chosen */
+		on = MS_TO_CLK(500);
+		off = MS_TO_CLK(500);
+	} else {
+		on = MS_TO_CLK(*delay_on);
+		off = MS_TO_CLK(*delay_off);
+		if ((on + off) > MAX_CLK)
+			return -EINVAL;
+	}
+
+	base = led_n_base[cell->id];
+	asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), (on + off));
+	asic3_write_register(asic, (base + ASIC3_LED_DutyTime), on);
+	asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
+	asic3_write_register(asic, (base + ASIC3_LED_TimeBase), (LED_EN|0x4));
+
+	*delay_on = CLK_TO_MS(on);
+	*delay_off = CLK_TO_MS(off);
+
+	return 0;
+}
+
+static int __devinit asic3_led_probe(struct platform_device *pdev)
+{
+	struct asic3_led *led = pdev->dev.platform_data;
+	int ret;
+
+	ret = mfd_cell_enable(pdev);
+	if (ret < 0)
+		goto ret0;
+
+	led->cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
+	if (!led->cdev) {
+		ret = -ENOMEM;
+		goto ret1;
+	}
+
+	led->cdev->name = led->name;
+	led->cdev->default_trigger = led->default_trigger;
+	led->cdev->brightness_set = brightness_set;
+	led->cdev->blink_set = blink_set;
+
+	ret = led_classdev_register(&pdev->dev, led->cdev);
+	if (ret < 0)
+		goto ret2;
+
+	return 0;
+
+ret2:
+	kfree(led->cdev);
+ret1:
+	(void) mfd_cell_disable(pdev);
+ret0:
+	return ret;
+}
+
+static int __devexit asic3_led_remove(struct platform_device *pdev)
+{
+	struct asic3_led *led = pdev->dev.platform_data;
+
+	led_classdev_unregister(led->cdev);
+
+	kfree(led->cdev);
+
+	return mfd_cell_disable(pdev);
+}
+
+static struct platform_driver asic3_led_driver = {
+	.probe		= asic3_led_probe,
+	.remove		= __devexit_p(asic3_led_remove),
+	.driver		= {
+		.name	= "leds-asic3",
+		.owner	= THIS_MODULE,
+	},
+};
+
+MODULE_ALIAS("platform:leds-asic3");
+
+static int __init asic3_led_init(void)
+{
+	return platform_driver_register(&asic3_led_driver);
+}
+
+static void __exit asic3_led_exit(void)
+{
+	platform_driver_unregister(&asic3_led_driver);
+}
+
+module_init(asic3_led_init);
+module_exit(asic3_led_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("HTC ASIC3 LED driver");
+MODULE_LICENSE("GPL");

+ 3 - 4
drivers/leds/leds-mc13783.c

@@ -22,7 +22,6 @@
 #include <linux/leds.h>
 #include <linux/leds.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/mfd/mc13783.h>
 #include <linux/mfd/mc13783.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
 struct mc13783_led {
 struct mc13783_led {
@@ -184,7 +183,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
 
 
 static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
 static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
 {
 {
-	struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+	struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
 	struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
 	int ret = 0;
 	int ret = 0;
 	int reg = 0;
 	int reg = 0;
@@ -265,7 +264,7 @@ out:
 
 
 static int __devinit mc13783_led_probe(struct platform_device *pdev)
 static int __devinit mc13783_led_probe(struct platform_device *pdev)
 {
 {
-	struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+	struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct mc13783_led_platform_data *led_cur;
 	struct mc13783_led_platform_data *led_cur;
 	struct mc13783_led *led, *led_dat;
 	struct mc13783_led *led, *led_dat;
 	int ret, i;
 	int ret, i;
@@ -352,7 +351,7 @@ err_free:
 
 
 static int __devexit mc13783_led_remove(struct platform_device *pdev)
 static int __devexit mc13783_led_remove(struct platform_device *pdev)
 {
 {
-	struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+	struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct mc13783_led *led = platform_get_drvdata(pdev);
 	struct mc13783_led *led = platform_get_drvdata(pdev);
 	struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
 	struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
 	int i;
 	int i;

+ 1 - 2
drivers/media/radio/radio-timb.c

@@ -21,7 +21,6 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-device.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
@@ -149,7 +148,7 @@ static const struct v4l2_file_operations timbradio_fops = {
 
 
 static int __devinit timbradio_probe(struct platform_device *pdev)
 static int __devinit timbradio_probe(struct platform_device *pdev)
 {
 {
-	struct timb_radio_platform_data *pdata = mfd_get_data(pdev);
+	struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
 	struct timbradio *tr;
 	struct timbradio *tr;
 	int err;
 	int err;
 
 

+ 1 - 1
drivers/media/radio/radio-wl1273.c

@@ -1990,7 +1990,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
 
 
 static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 {
 {
-	struct wl1273_core **core = mfd_get_data(pdev);
+	struct wl1273_core **core = pdev->dev.platform_data;
 	struct wl1273_device *radio;
 	struct wl1273_device *radio;
 	struct v4l2_ctrl *ctrl;
 	struct v4l2_ctrl *ctrl;
 	int r = 0;
 	int r = 0;

+ 1 - 2
drivers/media/video/timblogiw.c

@@ -24,7 +24,6 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
 #include <linux/dmaengine.h>
-#include <linux/mfd/core.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/list.h>
@@ -791,7 +790,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev)
 {
 {
 	int err;
 	int err;
 	struct timblogiw *lw = NULL;
 	struct timblogiw *lw = NULL;
-	struct timb_video_platform_data *pdata = mfd_get_data(pdev);
+	struct timb_video_platform_data *pdata = pdev->dev.platform_data;
 
 
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(&pdev->dev, "No platform data\n");
 		dev_err(&pdev->dev, "No platform data\n");

+ 75 - 80
drivers/mfd/88pm860x-core.c

@@ -21,13 +21,13 @@
 
 
 #define INT_STATUS_NUM			3
 #define INT_STATUS_NUM			3
 
 
-static struct resource bk_resources[] __initdata = {
+static struct resource bk_resources[] __devinitdata = {
 	{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
 	{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
 	{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
 	{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
 	{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
 	{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
 };
 };
 
 
-static struct resource led_resources[] __initdata = {
+static struct resource led_resources[] __devinitdata = {
 	{PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,},
 	{PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,},
 	{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
 	{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
 	{PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,},
 	{PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,},
@@ -36,7 +36,7 @@ static struct resource led_resources[] __initdata = {
 	{PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,},
 	{PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,},
 };
 };
 
 
-static struct resource regulator_resources[] __initdata = {
+static struct resource regulator_resources[] __devinitdata = {
 	{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
 	{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
 	{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
 	{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
 	{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
 	{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
@@ -57,15 +57,15 @@ static struct resource regulator_resources[] __initdata = {
 	{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
 	{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
 };
 };
 
 
-static struct resource touch_resources[] __initdata = {
+static struct resource touch_resources[] __devinitdata = {
 	{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
 	{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
 };
 };
 
 
-static struct resource onkey_resources[] __initdata = {
+static struct resource onkey_resources[] __devinitdata = {
 	{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
 	{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
 };
 };
 
 
-static struct resource codec_resources[] __initdata = {
+static struct resource codec_resources[] __devinitdata = {
 	/* Headset microphone insertion or removal */
 	/* Headset microphone insertion or removal */
 	{PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
 	{PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
 	/* Hook-switch press or release */
 	/* Hook-switch press or release */
@@ -76,12 +76,12 @@ static struct resource codec_resources[] __initdata = {
 	{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
 	{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
 };
 };
 
 
-static struct resource battery_resources[] __initdata = {
+static struct resource battery_resources[] __devinitdata = {
 	{PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
 	{PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
 	{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
 	{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
 };
 };
 
 
-static struct resource charger_resources[] __initdata = {
+static struct resource charger_resources[] __devinitdata = {
 	{PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
 	{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_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",       IORESOURCE_IRQ,},
 	{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout",    IORESOURCE_IRQ,},
 	{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout",    IORESOURCE_IRQ,},
@@ -90,13 +90,17 @@ static struct resource charger_resources[] __initdata = {
 	{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
 	{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
 };
 };
 
 
-static struct mfd_cell bk_devs[] __initdata = {
+static struct resource rtc_resources[] __devinitdata = {
+	{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
+};
+
+static struct mfd_cell bk_devs[] = {
 	{"88pm860x-backlight", 0,},
 	{"88pm860x-backlight", 0,},
 	{"88pm860x-backlight", 1,},
 	{"88pm860x-backlight", 1,},
 	{"88pm860x-backlight", 2,},
 	{"88pm860x-backlight", 2,},
 };
 };
 
 
-static struct mfd_cell led_devs[] __initdata = {
+static struct mfd_cell led_devs[] = {
 	{"88pm860x-led", 0,},
 	{"88pm860x-led", 0,},
 	{"88pm860x-led", 1,},
 	{"88pm860x-led", 1,},
 	{"88pm860x-led", 2,},
 	{"88pm860x-led", 2,},
@@ -105,7 +109,7 @@ static struct mfd_cell led_devs[] __initdata = {
 	{"88pm860x-led", 5,},
 	{"88pm860x-led", 5,},
 };
 };
 
 
-static struct mfd_cell regulator_devs[] __initdata = {
+static struct mfd_cell regulator_devs[] = {
 	{"88pm860x-regulator", 0,},
 	{"88pm860x-regulator", 0,},
 	{"88pm860x-regulator", 1,},
 	{"88pm860x-regulator", 1,},
 	{"88pm860x-regulator", 2,},
 	{"88pm860x-regulator", 2,},
@@ -126,15 +130,15 @@ static struct mfd_cell regulator_devs[] __initdata = {
 	{"88pm860x-regulator", 17,},
 	{"88pm860x-regulator", 17,},
 };
 };
 
 
-static struct mfd_cell touch_devs[] __initdata = {
+static struct mfd_cell touch_devs[] = {
 	{"88pm860x-touch", -1,},
 	{"88pm860x-touch", -1,},
 };
 };
 
 
-static struct mfd_cell onkey_devs[] __initdata = {
+static struct mfd_cell onkey_devs[] = {
 	{"88pm860x-onkey", -1,},
 	{"88pm860x-onkey", -1,},
 };
 };
 
 
-static struct mfd_cell codec_devs[] __initdata = {
+static struct mfd_cell codec_devs[] = {
 	{"88pm860x-codec", -1,},
 	{"88pm860x-codec", -1,},
 };
 };
 
 
@@ -143,11 +147,10 @@ static struct mfd_cell power_devs[] = {
 	{"88pm860x-charger", -1,},
 	{"88pm860x-charger", -1,},
 };
 };
 
 
-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;
+static struct mfd_cell rtc_devs[] = {
+	{"88pm860x-rtc", -1,},
+};
+
 
 
 struct pm860x_irq_data {
 struct pm860x_irq_data {
 	int	reg;
 	int	reg;
@@ -501,7 +504,6 @@ static void device_irq_exit(struct pm860x_chip *chip)
 }
 }
 
 
 static void __devinit device_bk_init(struct pm860x_chip *chip,
 static void __devinit device_bk_init(struct pm860x_chip *chip,
-				     struct i2c_client *i2c,
 				     struct pm860x_platform_data *pdata)
 				     struct pm860x_platform_data *pdata)
 {
 {
 	int ret;
 	int ret;
@@ -514,13 +516,12 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
 		pdata->num_backlights = ARRAY_SIZE(bk_devs);
 		pdata->num_backlights = ARRAY_SIZE(bk_devs);
 
 
 	for (i = 0; i < pdata->num_backlights; i++) {
 	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];
+		bk_devs[i].platform_data = &pdata->backlight[i];
+		bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
 
 
 		for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
 		for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
 			id = bk_resources[j].start;
 			id = bk_resources[j].start;
-			if (bk_pdata[i].flags != id)
+			if (pdata->backlight[i].flags != id)
 				continue;
 				continue;
 
 
 			bk_devs[i].num_resources = 1;
 			bk_devs[i].num_resources = 1;
@@ -538,7 +539,6 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
 }
 }
 
 
 static void __devinit device_led_init(struct pm860x_chip *chip,
 static void __devinit device_led_init(struct pm860x_chip *chip,
-				      struct i2c_client *i2c,
 				      struct pm860x_platform_data *pdata)
 				      struct pm860x_platform_data *pdata)
 {
 {
 	int ret;
 	int ret;
@@ -551,13 +551,12 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
 		pdata->num_leds = ARRAY_SIZE(led_devs);
 		pdata->num_leds = ARRAY_SIZE(led_devs);
 
 
 	for (i = 0; i < pdata->num_leds; i++) {
 	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];
+		led_devs[i].platform_data = &pdata->led[i];
+		led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
 
 
 		for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
 		for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
 			id = led_resources[j].start;
 			id = led_resources[j].start;
-			if (led_pdata[i].flags != id)
+			if (pdata->led[i].flags != id)
 				continue;
 				continue;
 
 
 			led_devs[i].num_resources = 1;
 			led_devs[i].num_resources = 1;
@@ -575,12 +574,11 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
 }
 }
 
 
 static void __devinit device_regulator_init(struct pm860x_chip *chip,
 static void __devinit device_regulator_init(struct pm860x_chip *chip,
-					    struct i2c_client *i2c,
 					    struct pm860x_platform_data *pdata)
 					    struct pm860x_platform_data *pdata)
 {
 {
 	struct regulator_init_data *initdata;
 	struct regulator_init_data *initdata;
 	int ret;
 	int ret;
-	int i, j;
+	int i, seq;
 
 
 	if ((pdata == NULL) || (pdata->regulator == NULL))
 	if ((pdata == NULL) || (pdata->regulator == NULL))
 		return;
 		return;
@@ -588,41 +586,21 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip,
 	if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
 	if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
 		pdata->num_regulators = ARRAY_SIZE(regulator_devs);
 		pdata->num_regulators = ARRAY_SIZE(regulator_devs);
 
 
-	for (i = 0, j = -1; i < pdata->num_regulators; i++) {
+	for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
 		initdata = &pdata->regulator[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);
+		seq = *(unsigned int *)initdata->driver_data;
+		if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
+			dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
+				seq, initdata->constraints.name);
 			goto out;
 			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].platform_data = &pdata->regulator[i];
+		regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
 		regulator_devs[i].num_resources = 1;
 		regulator_devs[i].num_resources = 1;
-		regulator_devs[i].resources = &regulator_resources[j];
+		regulator_devs[i].resources = &regulator_resources[seq];
 
 
 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
-				      &regulator_resources[j], 0);
+				      &regulator_resources[seq], 0);
 		if (ret < 0) {
 		if (ret < 0) {
 			dev_err(chip->dev, "Failed to add regulator subdev\n");
 			dev_err(chip->dev, "Failed to add regulator subdev\n");
 			goto out;
 			goto out;
@@ -632,17 +610,35 @@ out:
 	return;
 	return;
 }
 }
 
 
+static void __devinit device_rtc_init(struct pm860x_chip *chip,
+				      struct pm860x_platform_data *pdata)
+{
+	int ret;
+
+	if ((pdata == NULL))
+		return;
+
+	rtc_devs[0].platform_data = pdata->rtc;
+	rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
+	rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
+	rtc_devs[0].resources = &rtc_resources[0];
+	ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+			      ARRAY_SIZE(rtc_devs), &rtc_resources[0],
+			      chip->irq_base);
+	if (ret < 0)
+		dev_err(chip->dev, "Failed to add rtc subdev\n");
+}
+
 static void __devinit device_touch_init(struct pm860x_chip *chip,
 static void __devinit device_touch_init(struct pm860x_chip *chip,
-					struct i2c_client *i2c,
 					struct pm860x_platform_data *pdata)
 					struct pm860x_platform_data *pdata)
 {
 {
 	int ret;
 	int ret;
 
 
-	if ((pdata == NULL) || (pdata->touch == NULL))
+	if (pdata == NULL)
 		return;
 		return;
 
 
-	memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata));
-	touch_devs[0].mfd_data = &touch_pdata;
+	touch_devs[0].platform_data = pdata->touch;
+	touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
 	touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
 	touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
 	touch_devs[0].resources = &touch_resources[0];
 	touch_devs[0].resources = &touch_resources[0];
 	ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
 	ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
@@ -653,16 +649,15 @@ static void __devinit device_touch_init(struct pm860x_chip *chip,
 }
 }
 
 
 static void __devinit device_power_init(struct pm860x_chip *chip,
 static void __devinit device_power_init(struct pm860x_chip *chip,
-					struct i2c_client *i2c,
 					struct pm860x_platform_data *pdata)
 					struct pm860x_platform_data *pdata)
 {
 {
 	int ret;
 	int ret;
 
 
-	if ((pdata == NULL) || (pdata->power == NULL))
+	if (pdata == NULL)
 		return;
 		return;
 
 
-	memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata));
-	power_devs[0].mfd_data = &power_pdata;
+	power_devs[0].platform_data = pdata->power;
+	power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
 	power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
 	power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
 	power_devs[0].resources = &battery_resources[0],
 	power_devs[0].resources = &battery_resources[0],
 	ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
 	ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
@@ -670,7 +665,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
 	if (ret < 0)
 	if (ret < 0)
 		dev_err(chip->dev, "Failed to add battery subdev\n");
 		dev_err(chip->dev, "Failed to add battery subdev\n");
 
 
-	power_devs[1].mfd_data = &power_pdata;
+	power_devs[1].platform_data = pdata->power;
+	power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
 	power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
 	power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
 	power_devs[1].resources = &charger_resources[0],
 	power_devs[1].resources = &charger_resources[0],
 	ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
 	ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
@@ -680,7 +676,6 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
 }
 }
 
 
 static void __devinit device_onkey_init(struct pm860x_chip *chip,
 static void __devinit device_onkey_init(struct pm860x_chip *chip,
-					struct i2c_client *i2c,
 					struct pm860x_platform_data *pdata)
 					struct pm860x_platform_data *pdata)
 {
 {
 	int ret;
 	int ret;
@@ -695,7 +690,6 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip,
 }
 }
 
 
 static void __devinit device_codec_init(struct pm860x_chip *chip,
 static void __devinit device_codec_init(struct pm860x_chip *chip,
-					struct i2c_client *i2c,
 					struct pm860x_platform_data *pdata)
 					struct pm860x_platform_data *pdata)
 {
 {
 	int ret;
 	int ret;
@@ -763,11 +757,12 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	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);
+	device_regulator_init(chip, pdata);
+	device_rtc_init(chip, pdata);
+	device_onkey_init(chip, pdata);
+	device_touch_init(chip, pdata);
+	device_power_init(chip, pdata);
+	device_codec_init(chip, pdata);
 out:
 out:
 	return;
 	return;
 }
 }
@@ -779,8 +774,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
 
 
 	switch (chip->id) {
 	switch (chip->id) {
 	case CHIP_PM8606:
 	case CHIP_PM8606:
-		device_bk_init(chip, chip->client, pdata);
-		device_led_init(chip, chip->client, pdata);
+		device_bk_init(chip, pdata);
+		device_led_init(chip, pdata);
 		break;
 		break;
 	case CHIP_PM8607:
 	case CHIP_PM8607:
 		device_8607_init(chip, chip->client, pdata);
 		device_8607_init(chip, chip->client, pdata);
@@ -790,8 +785,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
 	if (chip->companion) {
 	if (chip->companion) {
 		switch (chip->id) {
 		switch (chip->id) {
 		case CHIP_PM8607:
 		case CHIP_PM8607:
-			device_bk_init(chip, chip->companion, pdata);
-			device_led_init(chip, chip->companion, pdata);
+			device_bk_init(chip, pdata);
+			device_led_init(chip, pdata);
 			break;
 			break;
 		case CHIP_PM8606:
 		case CHIP_PM8606:
 			device_8607_init(chip, chip->companion, pdata);
 			device_8607_init(chip, chip->companion, pdata);

+ 56 - 28
drivers/mfd/Kconfig

@@ -157,6 +157,20 @@ config TPS6507X
 	  This driver can also be built as a module.  If so, the module
 	  This driver can also be built as a module.  If so, the module
 	  will be called tps6507x.
 	  will be called tps6507x.
 
 
+config MFD_TPS6586X
+	bool "TPS6586x Power Management chips"
+	depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
+	select MFD_CORE
+	help
+	  If you say yes here you get support for the TPS6586X series of
+	  Power Management chips.
+	  This driver provides common support for accessing the device,
+	  additional drivers must be enabled in order to use the
+	  functionality of the device.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tps6586x.
+
 config MENELAUS
 config MENELAUS
 	bool "Texas Instruments TWL92330/Menelaus PM chip"
 	bool "Texas Instruments TWL92330/Menelaus PM chip"
 	depends on I2C=y && ARCH_OMAP2
 	depends on I2C=y && ARCH_OMAP2
@@ -455,6 +469,20 @@ config MFD_PCF50633
 	  facilities, and registers devices for the various functions
 	  facilities, and registers devices for the various functions
 	  so that function-specific drivers can bind to them.
 	  so that function-specific drivers can bind to them.
 
 
+config PCF50633_ADC
+	tristate "Support for NXP PCF50633 ADC"
+	depends on MFD_PCF50633
+	help
+	 Say yes here if you want to include support for ADC in the
+	 NXP PCF50633 chip.
+
+config PCF50633_GPIO
+	tristate "Support for NXP PCF50633 GPIO"
+	depends on MFD_PCF50633
+	help
+	 Say yes here if you want to include support GPIO for pins on
+	 the PCF50633 chip.
+
 config MFD_MC13783
 config MFD_MC13783
 	tristate
 	tristate
 
 
@@ -470,20 +498,6 @@ config MFD_MC13XXX
 	  additional drivers must be enabled in order to use the
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 	  functionality of the device.
 
 
-config PCF50633_ADC
-	tristate "Support for NXP PCF50633 ADC"
-	depends on MFD_PCF50633
-	help
-	 Say yes here if you want to include support for ADC in the
-	 NXP PCF50633 chip.
-
-config PCF50633_GPIO
-	tristate "Support for NXP PCF50633 GPIO"
-	depends on MFD_PCF50633
-	help
-	 Say yes here if you want to include support GPIO for pins on
-	 the PCF50633 chip.
-
 config ABX500_CORE
 config ABX500_CORE
 	bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
 	bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
 	default y if ARCH_U300 || ARCH_U8500
 	default y if ARCH_U300 || ARCH_U8500
@@ -649,20 +663,6 @@ config MFD_JZ4740_ADC
 	  Say yes here if you want support for the ADC unit in the JZ4740 SoC.
 	  Say yes here if you want support for the ADC unit in the JZ4740 SoC.
 	  This driver is necessary for jz4740-battery and jz4740-hwmon driver.
 	  This driver is necessary for jz4740-battery and jz4740-hwmon driver.
 
 
-config MFD_TPS6586X
-	bool "TPS6586x Power Management chips"
-	depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
-	select MFD_CORE
-	help
-	  If you say yes here you get support for the TPS6586X series of
-	  Power Management chips.
-	  This driver provides common support for accessing the device,
-	  additional drivers must be enabled in order to use the
-	  functionality of the device.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called tps6586x.
-
 config MFD_VX855
 config MFD_VX855
 	tristate "Support for VIA VX855/VX875 integrated south bridge"
 	tristate "Support for VIA VX855/VX875 integrated south bridge"
 	depends on PCI
 	depends on PCI
@@ -691,6 +691,34 @@ config MFD_OMAP_USB_HOST
 	  This MFD driver does the required setup functionalities for
 	  This MFD driver does the required setup functionalities for
 	  OMAP USB Host drivers.
 	  OMAP USB Host drivers.
 
 
+config MFD_PM8XXX
+	tristate
+
+config MFD_PM8921_CORE
+	tristate "Qualcomm PM8921 PMIC chip"
+	depends on MSM_SSBI
+	select MFD_CORE
+	select MFD_PM8XXX
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in PM8921 PMIC chip.
+
+	  This is required if your board has a PM8921 and uses its features,
+	  such as: MPPs, GPIOs, regulators, interrupts, and PWM.
+
+	  Say M here if you want to include support for PM8921 chip as a module.
+	  This will build a module called "pm8921-core".
+
+config MFD_PM8XXX_IRQ
+	bool "Support for Qualcomm PM8xxx IRQ features"
+	depends on MFD_PM8XXX
+	default y if MFD_PM8XXX
+	help
+	  This is the IRQ driver for Qualcomm PM 8xxx PMIC chips.
+
+	  This is required to use certain other PM 8xxx features, such as GPIO
+	  and MPP.
+
 endif # MFD_SUPPORT
 endif # MFD_SUPPORT
 
 
 menu "Multimedia Capabilities Port drivers"
 menu "Multimedia Capabilities Port drivers"

+ 2 - 0
drivers/mfd/Makefile

@@ -91,3 +91,5 @@ obj-$(CONFIG_MFD_VX855)		+= vx855.o
 obj-$(CONFIG_MFD_WL1273_CORE)	+= wl1273-core.o
 obj-$(CONFIG_MFD_WL1273_CORE)	+= wl1273-core.o
 obj-$(CONFIG_MFD_CS5535)	+= cs5535-mfd.o
 obj-$(CONFIG_MFD_CS5535)	+= cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)	+= omap-usb-host.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)	+= omap-usb-host.o
+obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o
+obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o

+ 4 - 2
drivers/mfd/ab3100-core.c

@@ -949,8 +949,10 @@ static int __devinit ab3100_probe(struct i2c_client *client,
 		goto exit_no_ops;
 		goto exit_no_ops;
 
 
 	/* Set up and register the platform devices. */
 	/* Set up and register the platform devices. */
-	for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++)
-		ab3100_devs[i].mfd_data = ab3100_plf_data;
+	for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
+		ab3100_devs[i].platform_data = ab3100_plf_data;
+		ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data);
+	}
 
 
 	err = mfd_add_devices(&client->dev, 0, ab3100_devs,
 	err = mfd_add_devices(&client->dev, 0, ab3100_devs,
 		ARRAY_SIZE(ab3100_devs), NULL, 0);
 		ARRAY_SIZE(ab3100_devs), NULL, 0);

+ 4 - 2
drivers/mfd/ab3550-core.c

@@ -1320,8 +1320,10 @@ static int __init ab3550_probe(struct i2c_client *client,
 		goto exit_no_ops;
 		goto exit_no_ops;
 
 
 	/* Set up and register the platform devices. */
 	/* Set up and register the platform devices. */
-	for (i = 0; i < AB3550_NUM_DEVICES; i++)
-		ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i];
+	for (i = 0; i < AB3550_NUM_DEVICES; i++) {
+		ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i];
+		ab3550_devs[i].pdata_size = ab3550_plf_data->dev_data_sz[i];
+	}
 
 
 	err = mfd_add_devices(&client->dev, 0, ab3550_devs,
 	err = mfd_add_devices(&client->dev, 0, ab3550_devs,
 		ARRAY_SIZE(ab3550_devs), NULL,
 		ARRAY_SIZE(ab3550_devs), NULL,

+ 16 - 16
drivers/mfd/ab8500-core.c

@@ -254,8 +254,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
 		if (new == old)
 		if (new == old)
 			continue;
 			continue;
 
 
-		/* Interrupt register 12 does'nt exist prior to version 0x20 */
-		if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+		/* Interrupt register 12 doesn't exist prior to version 2.0 */
+		if (ab8500_irq_regoffset[i] == 11 &&
+			ab8500->chip_id < AB8500_CUT2P0)
 			continue;
 			continue;
 
 
 		ab8500->oldmask[i] = new;
 		ab8500->oldmask[i] = new;
@@ -307,8 +308,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
 		int status;
 		int status;
 		u8 value;
 		u8 value;
 
 
-		/* Interrupt register 12 does'nt exist prior to version 0x20 */
-		if (regoffset == 11 && ab8500->chip_id < 0x20)
+		/* Interrupt register 12 doesn't exist prior to version 2.0 */
+		if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
 			continue;
 			continue;
 
 
 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -724,17 +725,15 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	/*
-	 * 0x0 - Early Drop
-	 * 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 ||
-		value == 0x30) {
+	switch (value) {
+	case AB8500_CUTEARLY:
+	case AB8500_CUT1P0:
+	case AB8500_CUT1P1:
+	case AB8500_CUT2P0:
+	case AB8500_CUT3P0:
 		dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
 		dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
-	} else {
+		break;
+	default:
 		dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
 		dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -763,8 +762,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 
 
 	/* Clear and mask all interrupts */
 	/* Clear and mask all interrupts */
 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-		/* Interrupt register 12 does'nt exist prior to version 0x20 */
-		if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+		/* Interrupt register 12 doesn't exist prior to version 2.0 */
+		if (ab8500_irq_regoffset[i] == 11 &&
+			ab8500->chip_id < AB8500_CUT2P0)
 			continue;
 			continue;
 
 
 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
 		get_register_interruptible(ab8500, AB8500_INTERRUPT,

+ 33 - 1
drivers/mfd/ab8500-gpadc.c

@@ -57,6 +57,7 @@
 #define SW_AVG_16			0x60
 #define SW_AVG_16			0x60
 #define ADC_SW_CONV			0x04
 #define ADC_SW_CONV			0x04
 #define EN_ICHAR			0x80
 #define EN_ICHAR			0x80
+#define BTEMP_PULL_UP			0x08
 #define EN_BUF				0x40
 #define EN_BUF				0x40
 #define DIS_ZERO			0x00
 #define DIS_ZERO			0x00
 #define GPADC_BUSY			0x01
 #define GPADC_BUSY			0x01
@@ -101,6 +102,7 @@ struct adc_cal_data {
 
 
 /**
 /**
  * struct ab8500_gpadc - AB8500 GPADC device information
  * struct ab8500_gpadc - AB8500 GPADC device information
+ * @chip_id			ABB chip id
  * @dev:			pointer to the struct device
  * @dev:			pointer to the struct device
  * @node:			a list of AB8500 GPADCs, hence prepared for
  * @node:			a list of AB8500 GPADCs, hence prepared for
 				reentrance
 				reentrance
@@ -112,6 +114,7 @@ struct adc_cal_data {
  * @cal_data			array of ADC calibration data structs
  * @cal_data			array of ADC calibration data structs
  */
  */
 struct ab8500_gpadc {
 struct ab8500_gpadc {
+	u8 chip_id;
 	struct device *dev;
 	struct device *dev;
 	struct list_head node;
 	struct list_head node;
 	struct completion ab8500_gpadc_complete;
 	struct completion ab8500_gpadc_complete;
@@ -274,6 +277,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
 		dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
 		dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
 		goto out;
 		goto out;
 	}
 	}
+
 	/* Select the input source and set average samples to 16 */
 	/* Select the input source and set average samples to 16 */
 	ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
 	ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
 		AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
 		AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
@@ -282,9 +286,11 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
 			"gpadc_conversion: set avg samples failed\n");
 			"gpadc_conversion: set avg samples failed\n");
 		goto out;
 		goto out;
 	}
 	}
+
 	/*
 	/*
 	 * Enable ADC, buffering, select rising edge and enable ADC path
 	 * Enable ADC, buffering, select rising edge and enable ADC path
-	 * charging current sense if it needed
+	 * charging current sense if it needed, ABB 3.0 needs some special
+	 * treatment too.
 	 */
 	 */
 	switch (input) {
 	switch (input) {
 	case MAIN_CHARGER_C:
 	case MAIN_CHARGER_C:
@@ -294,6 +300,23 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
 			EN_BUF | EN_ICHAR,
 			EN_BUF | EN_ICHAR,
 			EN_BUF | EN_ICHAR);
 			EN_BUF | EN_ICHAR);
 		break;
 		break;
+	case BTEMP_BALL:
+		if (gpadc->chip_id >= AB8500_CUT3P0) {
+			/* Turn on btemp pull-up on ABB 3.0 */
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF | BTEMP_PULL_UP,
+				EN_BUF | BTEMP_PULL_UP);
+
+		 /*
+		  * Delay might be needed for ABB8500 cut 3.0, if not, remove
+		  * when hardware will be availible
+		  */
+			msleep(1);
+			break;
+		}
+		/* Intentional fallthrough */
 	default:
 	default:
 		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
 		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
 			AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
 			AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
@@ -304,6 +327,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
 			"gpadc_conversion: select falling edge failed\n");
 			"gpadc_conversion: select falling edge failed\n");
 		goto out;
 		goto out;
 	}
 	}
+
 	ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
 	ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
 		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
 		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
 	if (ret < 0) {
 	if (ret < 0) {
@@ -552,6 +576,14 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
 		goto fail;
 		goto fail;
 	}
 	}
 
 
+	/* Get Chip ID of the ABB ASIC  */
+	ret = abx500_get_chip_id(gpadc->dev);
+	if (ret < 0) {
+		dev_err(gpadc->dev, "failed to get chip ID\n");
+		goto fail_irq;
+	}
+	gpadc->chip_id = (u8) ret;
+
 	/* VTVout LDO used to power up ab8500-GPADC */
 	/* VTVout LDO used to power up ab8500-GPADC */
 	gpadc->regu = regulator_get(&pdev->dev, "vddadc");
 	gpadc->regu = regulator_get(&pdev->dev, "vddadc");
 	if (IS_ERR(gpadc->regu)) {
 	if (IS_ERR(gpadc->regu)) {

+ 74 - 9
drivers/mfd/asic3.c

@@ -88,19 +88,19 @@ struct asic3 {
 
 
 static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
 static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
 
 
-static inline void asic3_write_register(struct asic3 *asic,
-				 unsigned int reg, u32 value)
+void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value)
 {
 {
 	iowrite16(value, asic->mapping +
 	iowrite16(value, asic->mapping +
 		  (reg >> asic->bus_shift));
 		  (reg >> asic->bus_shift));
 }
 }
+EXPORT_SYMBOL_GPL(asic3_write_register);
 
 
-static inline u32 asic3_read_register(struct asic3 *asic,
-			       unsigned int reg)
+u32 asic3_read_register(struct asic3 *asic, unsigned int reg)
 {
 {
 	return ioread16(asic->mapping +
 	return ioread16(asic->mapping +
 			(reg >> asic->bus_shift));
 			(reg >> asic->bus_shift));
 }
 }
+EXPORT_SYMBOL_GPL(asic3_read_register);
 
 
 static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
 static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
 {
 {
@@ -676,7 +676,8 @@ static struct mfd_cell asic3_cell_ds1wm = {
 	.name          = "ds1wm",
 	.name          = "ds1wm",
 	.enable        = ds1wm_enable,
 	.enable        = ds1wm_enable,
 	.disable       = ds1wm_disable,
 	.disable       = ds1wm_disable,
-	.mfd_data      = &ds1wm_pdata,
+	.platform_data = &ds1wm_pdata,
+	.pdata_size    = sizeof(ds1wm_pdata),
 	.num_resources = ARRAY_SIZE(ds1wm_resources),
 	.num_resources = ARRAY_SIZE(ds1wm_resources),
 	.resources     = ds1wm_resources,
 	.resources     = ds1wm_resources,
 };
 };
@@ -777,12 +778,61 @@ static struct mfd_cell asic3_cell_mmc = {
 	.name          = "tmio-mmc",
 	.name          = "tmio-mmc",
 	.enable        = asic3_mmc_enable,
 	.enable        = asic3_mmc_enable,
 	.disable       = asic3_mmc_disable,
 	.disable       = asic3_mmc_disable,
-	.mfd_data      = &asic3_mmc_data,
+	.platform_data = &asic3_mmc_data,
+	.pdata_size    = sizeof(asic3_mmc_data),
 	.num_resources = ARRAY_SIZE(asic3_mmc_resources),
 	.num_resources = ARRAY_SIZE(asic3_mmc_resources),
 	.resources     = asic3_mmc_resources,
 	.resources     = asic3_mmc_resources,
 };
 };
 
 
+static const int clock_ledn[ASIC3_NUM_LEDS] = {
+	[0] = ASIC3_CLOCK_LED0,
+	[1] = ASIC3_CLOCK_LED1,
+	[2] = ASIC3_CLOCK_LED2,
+};
+
+static int asic3_leds_enable(struct platform_device *pdev)
+{
+	const struct mfd_cell *cell = mfd_get_cell(pdev);
+	struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+	asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]);
+
+	return 0;
+}
+
+static int asic3_leds_disable(struct platform_device *pdev)
+{
+	const struct mfd_cell *cell = mfd_get_cell(pdev);
+	struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+	asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]);
+
+	return 0;
+}
+
+static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = {
+	[0] = {
+		.name          = "leds-asic3",
+		.id            = 0,
+		.enable        = asic3_leds_enable,
+		.disable       = asic3_leds_disable,
+	},
+	[1] = {
+		.name          = "leds-asic3",
+		.id            = 1,
+		.enable        = asic3_leds_enable,
+		.disable       = asic3_leds_disable,
+	},
+	[2] = {
+		.name          = "leds-asic3",
+		.id            = 2,
+		.enable        = asic3_leds_enable,
+		.disable       = asic3_leds_disable,
+	},
+};
+
 static int __init asic3_mfd_probe(struct platform_device *pdev,
 static int __init asic3_mfd_probe(struct platform_device *pdev,
+				  struct asic3_platform_data *pdata,
 				  struct resource *mem)
 				  struct resource *mem)
 {
 {
 	struct asic3 *asic = platform_get_drvdata(pdev);
 	struct asic3 *asic = platform_get_drvdata(pdev);
@@ -806,7 +856,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
 
 
 	/* MMC */
 	/* MMC */
 	asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
 	asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
-				 mem_sdio->start, 0x400 >> asic->bus_shift);
+				 mem_sdio->start,
+				 ASIC3_SD_CONFIG_SIZE >> asic->bus_shift);
 	if (!asic->tmio_cnf) {
 	if (!asic->tmio_cnf) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
 		dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
@@ -820,9 +871,23 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	if (mem_sdio && (irq >= 0))
+	if (mem_sdio && (irq >= 0)) {
 		ret = mfd_add_devices(&pdev->dev, pdev->id,
 		ret = mfd_add_devices(&pdev->dev, pdev->id,
 			&asic3_cell_mmc, 1, mem_sdio, irq);
 			&asic3_cell_mmc, 1, mem_sdio, irq);
+		if (ret < 0)
+			goto out;
+	}
+
+	if (pdata->leds) {
+		int i;
+
+		for (i = 0; i < ASIC3_NUM_LEDS; ++i) {
+			asic3_cell_leds[i].platform_data = &pdata->leds[i];
+			asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]);
+		}
+		ret = mfd_add_devices(&pdev->dev, 0,
+			asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0);
+	}
 
 
  out:
  out:
 	return ret;
 	return ret;
@@ -903,7 +968,7 @@ static int __init asic3_probe(struct platform_device *pdev)
 	 */
 	 */
 	memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
 	memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
 
 
-	asic3_mfd_probe(pdev, mem);
+	asic3_mfd_probe(pdev, pdata, mem);
 
 
 	dev_info(asic->dev, "ASIC3 Core driver\n");
 	dev_info(asic->dev, "ASIC3 Core driver\n");
 
 

+ 4 - 2
drivers/mfd/davinci_voicecodec.c

@@ -119,12 +119,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
 	/* Voice codec interface client */
 	/* Voice codec interface client */
 	cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
 	cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
 	cell->name = "davinci-vcif";
 	cell->name = "davinci-vcif";
-	cell->mfd_data = davinci_vc;
+	cell->platform_data = davinci_vc;
+	cell->pdata_size = sizeof(*davinci_vc);
 
 
 	/* Voice codec CQ93VC client */
 	/* Voice codec CQ93VC client */
 	cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
 	cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
 	cell->name = "cq93vc-codec";
 	cell->name = "cq93vc-codec";
-	cell->mfd_data = davinci_vc;
+	cell->platform_data = davinci_vc;
+	cell->pdata_size = sizeof(*davinci_vc);
 
 
 	ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
 	ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
 			      DAVINCI_VC_CELLS, NULL, 0);
 			      DAVINCI_VC_CELLS, NULL, 0);

+ 4 - 1
drivers/mfd/htc-pasic3.c

@@ -117,7 +117,8 @@ static struct mfd_cell ds1wm_cell __initdata = {
 	.name          = "ds1wm",
 	.name          = "ds1wm",
 	.enable        = ds1wm_enable,
 	.enable        = ds1wm_enable,
 	.disable       = ds1wm_disable,
 	.disable       = ds1wm_disable,
-	.mfd_data      = &ds1wm_pdata,
+	.platform_data = &ds1wm_pdata,
+	.pdata_size    = sizeof(ds1wm_pdata),
 	.num_resources = 2,
 	.num_resources = 2,
 	.resources     = ds1wm_resources,
 	.resources     = ds1wm_resources,
 };
 };
@@ -172,6 +173,8 @@ static int __init pasic3_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	if (pdata && pdata->led_pdata) {
 	if (pdata && pdata->led_pdata) {
+		led_cell.platform_data = pdata->led_pdata;
+		led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo);
 		ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
 		ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
 		if (ret < 0)
 		if (ret < 0)
 			dev_warn(dev, "failed to register LED device\n");
 			dev_warn(dev, "failed to register LED device\n");

+ 2 - 1
drivers/mfd/janz-cmodio.c

@@ -86,7 +86,8 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv,
 
 
 	/* Add platform data */
 	/* Add platform data */
 	pdata->modno = modno;
 	pdata->modno = modno;
-	cell->mfd_data = pdata;
+	cell->platform_data = pdata;
+	cell->pdata_size = sizeof(*pdata);
 
 
 	/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
 	/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
 	res->flags = IORESOURCE_MEM;
 	res->flags = IORESOURCE_MEM;

+ 1 - 1
drivers/mfd/max8925-core.c

@@ -627,7 +627,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
 		goto out_dev;
 		goto out_dev;
 	}
 	}
 
 
-	if (pdata && pdata->regulator[0]) {
+	if (pdata) {
 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
 				      ARRAY_SIZE(regulator_devs),
 				      ARRAY_SIZE(regulator_devs),
 				      &regulator_resources[0], 0);
 				      &regulator_resources[0], 0);

+ 7 - 5
drivers/mfd/mc13xxx-core.c

@@ -683,13 +683,14 @@ out:
 EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
 EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
 
 
 static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
 static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
-		const char *format, void *pdata)
+		const char *format, void *pdata, size_t pdata_size)
 {
 {
 	char buf[30];
 	char buf[30];
 	const char *name = mc13xxx_get_chipname(mc13xxx);
 	const char *name = mc13xxx_get_chipname(mc13xxx);
 
 
 	struct mfd_cell cell = {
 	struct mfd_cell cell = {
-		.mfd_data = pdata,
+		.platform_data = pdata,
+		.pdata_size = pdata_size,
 	};
 	};
 
 
 	/* there is no asnprintf in the kernel :-( */
 	/* there is no asnprintf in the kernel :-( */
@@ -705,7 +706,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
 
 
 static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
 static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
 {
 {
-	return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL);
+	return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
 }
 }
 
 
 static int mc13xxx_probe(struct spi_device *spi)
 static int mc13xxx_probe(struct spi_device *spi)
@@ -764,7 +765,7 @@ err_revision:
 
 
 	if (pdata->flags & MC13XXX_USE_REGULATOR) {
 	if (pdata->flags & MC13XXX_USE_REGULATOR) {
 		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
 		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
-				&pdata->regulators);
+				&pdata->regulators, sizeof(pdata->regulators));
 	}
 	}
 
 
 	if (pdata->flags & MC13XXX_USE_RTC)
 	if (pdata->flags & MC13XXX_USE_RTC)
@@ -774,7 +775,8 @@ err_revision:
 		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
 		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
 
 
 	if (pdata->flags & MC13XXX_USE_LED)
 	if (pdata->flags & MC13XXX_USE_LED)
-		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds);
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
+				pdata->leds, sizeof(*pdata->leds));
 
 
 	return 0;
 	return 0;
 }
 }

+ 7 - 0
drivers/mfd/mfd-core.c

@@ -88,6 +88,13 @@ static int mfd_add_device(struct device *parent, int id,
 
 
 	pdev->dev.parent = parent;
 	pdev->dev.parent = parent;
 
 
+	if (cell->pdata_size) {
+		ret = platform_device_add_data(pdev,
+					cell->platform_data, cell->pdata_size);
+		if (ret)
+			goto fail_res;
+	}
+
 	ret = mfd_platform_add_cell(pdev, cell);
 	ret = mfd_platform_add_cell(pdev, cell);
 	if (ret)
 	if (ret)
 		goto fail_res;
 		goto fail_res;

+ 26 - 126
drivers/mfd/omap-usb-host.c

@@ -26,6 +26,7 @@
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <plat/usb.h>
 #include <plat/usb.h>
+#include <linux/pm_runtime.h>
 
 
 #define USBHS_DRIVER_NAME	"usbhs-omap"
 #define USBHS_DRIVER_NAME	"usbhs-omap"
 #define OMAP_EHCI_DEVICE	"ehci-omap"
 #define OMAP_EHCI_DEVICE	"ehci-omap"
@@ -146,9 +147,6 @@
 
 
 
 
 struct usbhs_hcd_omap {
 struct usbhs_hcd_omap {
-	struct clk			*usbhost_ick;
-	struct clk			*usbhost_hs_fck;
-	struct clk			*usbhost_fs_fck;
 	struct clk			*xclk60mhsp1_ck;
 	struct clk			*xclk60mhsp1_ck;
 	struct clk			*xclk60mhsp2_ck;
 	struct clk			*xclk60mhsp2_ck;
 	struct clk			*utmi_p1_fck;
 	struct clk			*utmi_p1_fck;
@@ -158,8 +156,6 @@ struct usbhs_hcd_omap {
 	struct clk			*usbhost_p2_fck;
 	struct clk			*usbhost_p2_fck;
 	struct clk			*usbtll_p2_fck;
 	struct clk			*usbtll_p2_fck;
 	struct clk			*init_60m_fclk;
 	struct clk			*init_60m_fclk;
-	struct clk			*usbtll_fck;
-	struct clk			*usbtll_ick;
 
 
 	void __iomem			*uhh_base;
 	void __iomem			*uhh_base;
 	void __iomem			*tll_base;
 	void __iomem			*tll_base;
@@ -281,6 +277,7 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
 
 
 	if (!ehci) {
 	if (!ehci) {
 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
+		ret = -ENOMEM;
 		goto err_end;
 		goto err_end;
 	}
 	}
 
 
@@ -304,13 +301,14 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
 		sizeof(*ohci_data), dev);
 		sizeof(*ohci_data), dev);
 	if (!ohci) {
 	if (!ohci) {
 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
 		dev_err(dev, "omap_usbhs_alloc_child failed\n");
+		ret = -ENOMEM;
 		goto err_ehci;
 		goto err_ehci;
 	}
 	}
 
 
 	return 0;
 	return 0;
 
 
 err_ehci:
 err_ehci:
-	platform_device_put(ehci);
+	platform_device_unregister(ehci);
 
 
 err_end:
 err_end:
 	return ret;
 	return ret;
@@ -351,46 +349,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
 	omap->platdata.ehci_data = pdata->ehci_data;
 	omap->platdata.ehci_data = pdata->ehci_data;
 	omap->platdata.ohci_data = pdata->ohci_data;
 	omap->platdata.ohci_data = pdata->ohci_data;
 
 
-	omap->usbhost_ick = clk_get(dev, "usbhost_ick");
-	if (IS_ERR(omap->usbhost_ick)) {
-		ret =  PTR_ERR(omap->usbhost_ick);
-		dev_err(dev, "usbhost_ick failed error:%d\n", ret);
-		goto err_end;
-	}
-
-	omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
-	if (IS_ERR(omap->usbhost_hs_fck)) {
-		ret = PTR_ERR(omap->usbhost_hs_fck);
-		dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
-		goto err_usbhost_ick;
-	}
-
-	omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
-	if (IS_ERR(omap->usbhost_fs_fck)) {
-		ret = PTR_ERR(omap->usbhost_fs_fck);
-		dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
-		goto err_usbhost_hs_fck;
-	}
-
-	omap->usbtll_fck = clk_get(dev, "usbtll_fck");
-	if (IS_ERR(omap->usbtll_fck)) {
-		ret = PTR_ERR(omap->usbtll_fck);
-		dev_err(dev, "usbtll_fck failed error:%d\n", ret);
-		goto err_usbhost_fs_fck;
-	}
-
-	omap->usbtll_ick = clk_get(dev, "usbtll_ick");
-	if (IS_ERR(omap->usbtll_ick)) {
-		ret = PTR_ERR(omap->usbtll_ick);
-		dev_err(dev, "usbtll_ick failed error:%d\n", ret);
-		goto err_usbtll_fck;
-	}
+	pm_runtime_enable(&pdev->dev);
 
 
 	omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
 	omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
 	if (IS_ERR(omap->utmi_p1_fck)) {
 	if (IS_ERR(omap->utmi_p1_fck)) {
 		ret = PTR_ERR(omap->utmi_p1_fck);
 		ret = PTR_ERR(omap->utmi_p1_fck);
 		dev_err(dev, "utmi_p1_gfclk failed error:%d\n",	ret);
 		dev_err(dev, "utmi_p1_gfclk failed error:%d\n",	ret);
-		goto err_usbtll_ick;
+		goto err_end;
 	}
 	}
 
 
 	omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
 	omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
@@ -520,22 +485,8 @@ err_xclk60mhsp1_ck:
 err_utmi_p1_fck:
 err_utmi_p1_fck:
 	clk_put(omap->utmi_p1_fck);
 	clk_put(omap->utmi_p1_fck);
 
 
-err_usbtll_ick:
-	clk_put(omap->usbtll_ick);
-
-err_usbtll_fck:
-	clk_put(omap->usbtll_fck);
-
-err_usbhost_fs_fck:
-	clk_put(omap->usbhost_fs_fck);
-
-err_usbhost_hs_fck:
-	clk_put(omap->usbhost_hs_fck);
-
-err_usbhost_ick:
-	clk_put(omap->usbhost_ick);
-
 err_end:
 err_end:
+	pm_runtime_disable(&pdev->dev);
 	kfree(omap);
 	kfree(omap);
 
 
 end_probe:
 end_probe:
@@ -569,11 +520,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
 	clk_put(omap->utmi_p2_fck);
 	clk_put(omap->utmi_p2_fck);
 	clk_put(omap->xclk60mhsp1_ck);
 	clk_put(omap->xclk60mhsp1_ck);
 	clk_put(omap->utmi_p1_fck);
 	clk_put(omap->utmi_p1_fck);
-	clk_put(omap->usbtll_ick);
-	clk_put(omap->usbtll_fck);
-	clk_put(omap->usbhost_fs_fck);
-	clk_put(omap->usbhost_hs_fck);
-	clk_put(omap->usbhost_ick);
+	pm_runtime_disable(&pdev->dev);
 	kfree(omap);
 	kfree(omap);
 
 
 	return 0;
 	return 0;
@@ -693,7 +640,6 @@ static int usbhs_enable(struct device *dev)
 	struct usbhs_omap_platform_data	*pdata = &omap->platdata;
 	struct usbhs_omap_platform_data	*pdata = &omap->platdata;
 	unsigned long			flags = 0;
 	unsigned long			flags = 0;
 	int				ret = 0;
 	int				ret = 0;
-	unsigned long			timeout;
 	unsigned			reg;
 	unsigned			reg;
 
 
 	dev_dbg(dev, "starting TI HSUSB Controller\n");
 	dev_dbg(dev, "starting TI HSUSB Controller\n");
@@ -706,11 +652,7 @@ static int usbhs_enable(struct device *dev)
 	if (omap->count > 0)
 	if (omap->count > 0)
 		goto end_count;
 		goto end_count;
 
 
-	clk_enable(omap->usbhost_ick);
-	clk_enable(omap->usbhost_hs_fck);
-	clk_enable(omap->usbhost_fs_fck);
-	clk_enable(omap->usbtll_fck);
-	clk_enable(omap->usbtll_ick);
+	pm_runtime_get_sync(dev);
 
 
 	if (pdata->ehci_data->phy_reset) {
 	if (pdata->ehci_data->phy_reset) {
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
@@ -734,50 +676,6 @@ static int usbhs_enable(struct device *dev)
 	omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
 	omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
 	dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
 	dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
 
 
-	/* perform TLL soft reset, and wait until reset is complete */
-	usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
-			OMAP_USBTLL_SYSCONFIG_SOFTRESET);
-
-	/* Wait for TLL reset to complete */
-	timeout = jiffies + msecs_to_jiffies(1000);
-	while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
-			& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
-		cpu_relax();
-
-		if (time_after(jiffies, timeout)) {
-			dev_dbg(dev, "operation timed out\n");
-			ret = -EINVAL;
-			goto err_tll;
-		}
-	}
-
-	dev_dbg(dev, "TLL RESET DONE\n");
-
-	/* (1<<3) = no idle mode only for initial debugging */
-	usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
-			OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
-			OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
-			OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
-
-	/* Put UHH in NoIdle/NoStandby mode */
-	reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
-	if (is_omap_usbhs_rev1(omap)) {
-		reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
-				| OMAP_UHH_SYSCONFIG_SIDLEMODE
-				| OMAP_UHH_SYSCONFIG_CACTIVITY
-				| OMAP_UHH_SYSCONFIG_MIDLEMODE);
-		reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
-
-
-	} else if (is_omap_usbhs_rev2(omap)) {
-		reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
-		reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
-		reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
-		reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
-	}
-
-	usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
-
 	reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
 	reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
 	/* setup ULPI bypass and burst configurations */
 	/* setup ULPI bypass and burst configurations */
 	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
 	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
@@ -917,6 +815,8 @@ end_count:
 	return 0;
 	return 0;
 
 
 err_tll:
 err_tll:
+	pm_runtime_put_sync(dev);
+	spin_unlock_irqrestore(&omap->lock, flags);
 	if (pdata->ehci_data->phy_reset) {
 	if (pdata->ehci_data->phy_reset) {
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
 			gpio_free(pdata->ehci_data->reset_gpio_port[0]);
 			gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -924,13 +824,6 @@ err_tll:
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
 			gpio_free(pdata->ehci_data->reset_gpio_port[1]);
 			gpio_free(pdata->ehci_data->reset_gpio_port[1]);
 	}
 	}
-
-	clk_disable(omap->usbtll_ick);
-	clk_disable(omap->usbtll_fck);
-	clk_disable(omap->usbhost_fs_fck);
-	clk_disable(omap->usbhost_hs_fck);
-	clk_disable(omap->usbhost_ick);
-	spin_unlock_irqrestore(&omap->lock, flags);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -994,6 +887,20 @@ static void usbhs_disable(struct device *dev)
 			dev_dbg(dev, "operation timed out\n");
 			dev_dbg(dev, "operation timed out\n");
 	}
 	}
 
 
+	if (is_omap_usbhs_rev2(omap)) {
+		if (is_ehci_tll_mode(pdata->port_mode[0]))
+			clk_enable(omap->usbtll_p1_fck);
+		if (is_ehci_tll_mode(pdata->port_mode[1]))
+			clk_enable(omap->usbtll_p2_fck);
+		clk_disable(omap->utmi_p2_fck);
+		clk_disable(omap->utmi_p1_fck);
+	}
+
+	pm_runtime_put_sync(dev);
+
+	/* The gpio_free migh sleep; so unlock the spinlock */
+	spin_unlock_irqrestore(&omap->lock, flags);
+
 	if (pdata->ehci_data->phy_reset) {
 	if (pdata->ehci_data->phy_reset) {
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
 			gpio_free(pdata->ehci_data->reset_gpio_port[0]);
 			gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -1001,14 +908,7 @@ static void usbhs_disable(struct device *dev)
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
 		if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
 			gpio_free(pdata->ehci_data->reset_gpio_port[1]);
 			gpio_free(pdata->ehci_data->reset_gpio_port[1]);
 	}
 	}
-
-	clk_disable(omap->utmi_p2_fck);
-	clk_disable(omap->utmi_p1_fck);
-	clk_disable(omap->usbtll_ick);
-	clk_disable(omap->usbtll_fck);
-	clk_disable(omap->usbhost_fs_fck);
-	clk_disable(omap->usbhost_hs_fck);
-	clk_disable(omap->usbhost_ick);
+	return;
 
 
 end_disble:
 end_disble:
 	spin_unlock_irqrestore(&omap->lock, flags);
 	spin_unlock_irqrestore(&omap->lock, flags);

+ 212 - 0
drivers/mfd/pm8921-core.c

@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/msm_ssbi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/core.h>
+
+#define REG_HWREV		0x002  /* PMIC4 revision */
+#define REG_HWREV_2		0x0E8  /* PMIC4 revision 2 */
+
+struct pm8921 {
+	struct device			*dev;
+	struct pm_irq_chip		*irq_chip;
+};
+
+static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
+{
+	const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+	const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+	return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
+}
+
+static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
+{
+	const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+	const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+	return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
+}
+
+static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
+									int cnt)
+{
+	const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+	const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+	return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
+									int cnt)
+{
+	const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+	const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+	return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8921_read_irq_stat(const struct device *dev, int irq)
+{
+	const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+	const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+	return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
+}
+
+static struct pm8xxx_drvdata pm8921_drvdata = {
+	.pmic_readb		= pm8921_readb,
+	.pmic_writeb		= pm8921_writeb,
+	.pmic_read_buf		= pm8921_read_buf,
+	.pmic_write_buf		= pm8921_write_buf,
+	.pmic_read_irq_stat	= pm8921_read_irq_stat,
+};
+
+static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data
+					   *pdata,
+					   struct pm8921 *pmic,
+					   u32 rev)
+{
+	int ret = 0, irq_base = 0;
+	struct pm_irq_chip *irq_chip;
+
+	if (pdata->irq_pdata) {
+		pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
+		pdata->irq_pdata->irq_cdata.rev = rev;
+		irq_base = pdata->irq_pdata->irq_base;
+		irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+
+		if (IS_ERR(irq_chip)) {
+			pr_err("Failed to init interrupts ret=%ld\n",
+					PTR_ERR(irq_chip));
+			return PTR_ERR(irq_chip);
+		}
+		pmic->irq_chip = irq_chip;
+	}
+	return ret;
+}
+
+static int __devinit pm8921_probe(struct platform_device *pdev)
+{
+	const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
+	struct pm8921 *pmic;
+	int rc;
+	u8 val;
+	u32 rev;
+
+	if (!pdata) {
+		pr_err("missing platform data\n");
+		return -EINVAL;
+	}
+
+	pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
+	if (!pmic) {
+		pr_err("Cannot alloc pm8921 struct\n");
+		return -ENOMEM;
+	}
+
+	/* Read PMIC chip revision */
+	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+	if (rc) {
+		pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
+		goto err_read_rev;
+	}
+	pr_info("PMIC revision 1: %02X\n", val);
+	rev = val;
+
+	/* Read PMIC chip revision 2 */
+	rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
+	if (rc) {
+		pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
+			REG_HWREV_2, rc);
+		goto err_read_rev;
+	}
+	pr_info("PMIC revision 2: %02X\n", val);
+	rev |= val << BITS_PER_BYTE;
+
+	pmic->dev = &pdev->dev;
+	pm8921_drvdata.pm_chip_data = pmic;
+	platform_set_drvdata(pdev, &pm8921_drvdata);
+
+	rc = pm8921_add_subdevices(pdata, pmic, rev);
+	if (rc) {
+		pr_err("Cannot add subdevices rc=%d\n", rc);
+		goto err;
+	}
+
+	/* gpio might not work if no irq device is found */
+	WARN_ON(pmic->irq_chip == NULL);
+
+	return 0;
+
+err:
+	mfd_remove_devices(pmic->dev);
+	platform_set_drvdata(pdev, NULL);
+err_read_rev:
+	kfree(pmic);
+	return rc;
+}
+
+static int __devexit pm8921_remove(struct platform_device *pdev)
+{
+	struct pm8xxx_drvdata *drvdata;
+	struct pm8921 *pmic = NULL;
+
+	drvdata = platform_get_drvdata(pdev);
+	if (drvdata)
+		pmic = drvdata->pm_chip_data;
+	if (pmic)
+		mfd_remove_devices(pmic->dev);
+	if (pmic->irq_chip) {
+		pm8xxx_irq_exit(pmic->irq_chip);
+		pmic->irq_chip = NULL;
+	}
+	platform_set_drvdata(pdev, NULL);
+	kfree(pmic);
+
+	return 0;
+}
+
+static struct platform_driver pm8921_driver = {
+	.probe		= pm8921_probe,
+	.remove		= __devexit_p(pm8921_remove),
+	.driver		= {
+		.name	= "pm8921-core",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pm8921_init(void)
+{
+	return platform_driver_register(&pm8921_driver);
+}
+subsys_initcall(pm8921_init);
+
+static void __exit pm8921_exit(void)
+{
+	platform_driver_unregister(&pm8921_driver);
+}
+module_exit(pm8921_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC 8921 core driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:pm8921-core");

+ 371 - 0
drivers/mfd/pm8xxx-irq.c

@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* PMIC8xxx IRQ */
+
+#define	SSBI_REG_ADDR_IRQ_BASE		0x1BB
+
+#define	SSBI_REG_ADDR_IRQ_ROOT		(SSBI_REG_ADDR_IRQ_BASE + 0)
+#define	SSBI_REG_ADDR_IRQ_M_STATUS1	(SSBI_REG_ADDR_IRQ_BASE + 1)
+#define	SSBI_REG_ADDR_IRQ_M_STATUS2	(SSBI_REG_ADDR_IRQ_BASE + 2)
+#define	SSBI_REG_ADDR_IRQ_M_STATUS3	(SSBI_REG_ADDR_IRQ_BASE + 3)
+#define	SSBI_REG_ADDR_IRQ_M_STATUS4	(SSBI_REG_ADDR_IRQ_BASE + 4)
+#define	SSBI_REG_ADDR_IRQ_BLK_SEL	(SSBI_REG_ADDR_IRQ_BASE + 5)
+#define	SSBI_REG_ADDR_IRQ_IT_STATUS	(SSBI_REG_ADDR_IRQ_BASE + 6)
+#define	SSBI_REG_ADDR_IRQ_CONFIG	(SSBI_REG_ADDR_IRQ_BASE + 7)
+#define	SSBI_REG_ADDR_IRQ_RT_STATUS	(SSBI_REG_ADDR_IRQ_BASE + 8)
+
+#define	PM_IRQF_LVL_SEL			0x01	/* level select */
+#define	PM_IRQF_MASK_FE			0x02	/* mask falling edge */
+#define	PM_IRQF_MASK_RE			0x04	/* mask rising edge */
+#define	PM_IRQF_CLR			0x08	/* clear interrupt */
+#define	PM_IRQF_BITS_MASK		0x70
+#define	PM_IRQF_BITS_SHIFT		4
+#define	PM_IRQF_WRITE			0x80
+
+#define	PM_IRQF_MASK_ALL		(PM_IRQF_MASK_FE | \
+					PM_IRQF_MASK_RE)
+
+struct pm_irq_chip {
+	struct device		*dev;
+	spinlock_t		pm_irq_lock;
+	unsigned int		devirq;
+	unsigned int		irq_base;
+	unsigned int		num_irqs;
+	unsigned int		num_blocks;
+	unsigned int		num_masters;
+	u8			config[0];
+};
+
+static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
+{
+	return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
+}
+
+static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
+{
+	return pm8xxx_readb(chip->dev,
+			SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
+}
+
+static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
+{
+	int	rc;
+
+	spin_lock(&chip->pm_irq_lock);
+	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+	if (rc) {
+		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+		goto bail;
+	}
+
+	rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+	if (rc)
+		pr_err("Failed Reading Status rc=%d\n", rc);
+bail:
+	spin_unlock(&chip->pm_irq_lock);
+	return rc;
+}
+
+static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp)
+{
+	int	rc;
+
+	spin_lock(&chip->pm_irq_lock);
+	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+	if (rc) {
+		pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+		goto bail;
+	}
+
+	cp |= PM_IRQF_WRITE;
+	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+	if (rc)
+		pr_err("Failed Configuring IRQ rc=%d\n", rc);
+bail:
+	spin_unlock(&chip->pm_irq_lock);
+	return rc;
+}
+
+static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
+{
+	int pmirq, irq, i, ret = 0;
+	u8 bits;
+
+	ret = pm8xxx_read_block_irq(chip, block, &bits);
+	if (ret) {
+		pr_err("Failed reading %d block ret=%d", block, ret);
+		return ret;
+	}
+	if (!bits) {
+		pr_err("block bit set in master but no irqs: %d", block);
+		return 0;
+	}
+
+	/* Check IRQ bits */
+	for (i = 0; i < 8; i++) {
+		if (bits & (1 << i)) {
+			pmirq = block * 8 + i;
+			irq = pmirq + chip->irq_base;
+			generic_handle_irq(irq);
+		}
+	}
+	return 0;
+}
+
+static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
+{
+	u8 blockbits;
+	int block_number, i, ret = 0;
+
+	ret = pm8xxx_read_master_irq(chip, master, &blockbits);
+	if (ret) {
+		pr_err("Failed to read master %d ret=%d\n", master, ret);
+		return ret;
+	}
+	if (!blockbits) {
+		pr_err("master bit set in root but no blocks: %d", master);
+		return 0;
+	}
+
+	for (i = 0; i < 8; i++)
+		if (blockbits & (1 << i)) {
+			block_number = master * 8 + i;	/* block # */
+			ret |= pm8xxx_irq_block_handler(chip, block_number);
+		}
+	return ret;
+}
+
+static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
+	struct irq_chip *irq_chip = irq_desc_get_chip(desc);
+	u8	root;
+	int	i, ret, masters = 0;
+
+	ret = pm8xxx_read_root_irq(chip, &root);
+	if (ret) {
+		pr_err("Can't read root status ret=%d\n", ret);
+		return;
+	}
+
+	/* on pm8xxx series masters start from bit 1 of the root */
+	masters = root >> 1;
+
+	/* Read allowed masters for blocks. */
+	for (i = 0; i < chip->num_masters; i++)
+		if (masters & (1 << i))
+			pm8xxx_irq_master_handler(chip, i);
+
+	irq_chip->irq_ack(&desc->irq_data);
+}
+
+static void pm8xxx_irq_mask_ack(struct irq_data *d)
+{
+	struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int pmirq = d->irq - chip->irq_base;
+	int	master, irq_bit;
+	u8	block, config;
+
+	block = pmirq / 8;
+	master = block / 8;
+	irq_bit = pmirq % 8;
+
+	config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
+	pm8xxx_config_irq(chip, block, config);
+}
+
+static void pm8xxx_irq_unmask(struct irq_data *d)
+{
+	struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int pmirq = d->irq - chip->irq_base;
+	int	master, irq_bit;
+	u8	block, config;
+
+	block = pmirq / 8;
+	master = block / 8;
+	irq_bit = pmirq % 8;
+
+	config = chip->config[pmirq];
+	pm8xxx_config_irq(chip, block, config);
+}
+
+static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+	unsigned int pmirq = d->irq - chip->irq_base;
+	int master, irq_bit;
+	u8 block, config;
+
+	block = pmirq / 8;
+	master = block / 8;
+	irq_bit  = pmirq % 8;
+
+	chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
+							| PM_IRQF_MASK_ALL;
+	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		if (flow_type & IRQF_TRIGGER_RISING)
+			chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+		if (flow_type & IRQF_TRIGGER_FALLING)
+			chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+	} else {
+		chip->config[pmirq] |= PM_IRQF_LVL_SEL;
+
+		if (flow_type & IRQF_TRIGGER_HIGH)
+			chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+		else
+			chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+	}
+
+	config = chip->config[pmirq] | PM_IRQF_CLR;
+	return pm8xxx_config_irq(chip, block, config);
+}
+
+static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	return 0;
+}
+
+static struct irq_chip pm8xxx_irq_chip = {
+	.name		= "pm8xxx",
+	.irq_mask_ack	= pm8xxx_irq_mask_ack,
+	.irq_unmask	= pm8xxx_irq_unmask,
+	.irq_set_type	= pm8xxx_irq_set_type,
+	.irq_set_wake	= pm8xxx_irq_set_wake,
+	.flags		= IRQCHIP_MASK_ON_SUSPEND,
+};
+
+/**
+ * pm8xxx_get_irq_stat - get the status of the irq line
+ * @chip: pointer to identify a pmic irq controller
+ * @irq: the irq number
+ *
+ * The pm8xxx gpio and mpp rely on the interrupt block to read
+ * the values on their pins. This function is to facilitate reading
+ * the status of a gpio or an mpp line. The caller has to convert the
+ * gpio number to irq number.
+ *
+ * RETURNS:
+ * an int indicating the value read on that line
+ */
+int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+	int pmirq, rc;
+	u8  block, bits, bit;
+	unsigned long flags;
+
+	if (chip == NULL || irq < chip->irq_base ||
+			irq >= chip->irq_base + chip->num_irqs)
+		return -EINVAL;
+
+	pmirq = irq - chip->irq_base;
+
+	block = pmirq / 8;
+	bit = pmirq % 8;
+
+	spin_lock_irqsave(&chip->pm_irq_lock, flags);
+
+	rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
+	if (rc) {
+		pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
+			irq, pmirq, block, rc);
+		goto bail_out;
+	}
+
+	rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
+	if (rc) {
+		pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
+			irq, pmirq, block, rc);
+		goto bail_out;
+	}
+
+	rc = (bits & (1 << bit)) ? 1 : 0;
+
+bail_out:
+	spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat);
+
+struct pm_irq_chip *  __devinit pm8xxx_irq_init(struct device *dev,
+				const struct pm8xxx_irq_platform_data *pdata)
+{
+	struct pm_irq_chip  *chip;
+	int devirq, rc;
+	unsigned int pmirq;
+
+	if (!pdata) {
+		pr_err("No platform data\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	devirq = pdata->devirq;
+	if (devirq < 0) {
+		pr_err("missing devirq\n");
+		rc = devirq;
+		return ERR_PTR(-EINVAL);
+	}
+
+	chip = kzalloc(sizeof(struct pm_irq_chip)
+			+ sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
+	if (!chip) {
+		pr_err("Cannot alloc pm_irq_chip struct\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	chip->dev = dev;
+	chip->devirq = devirq;
+	chip->irq_base = pdata->irq_base;
+	chip->num_irqs = pdata->irq_cdata.nirqs;
+	chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
+	chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
+	spin_lock_init(&chip->pm_irq_lock);
+
+	for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
+		irq_set_chip_and_handler(chip->irq_base + pmirq,
+				&pm8xxx_irq_chip,
+				handle_level_irq);
+		irq_set_chip_data(chip->irq_base + pmirq, chip);
+#ifdef CONFIG_ARM
+		set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
+#else
+		irq_set_noprobe(chip->irq_base + pmirq);
+#endif
+	}
+
+	irq_set_irq_type(devirq, pdata->irq_trigger_flag);
+	irq_set_handler_data(devirq, chip);
+	irq_set_chained_handler(devirq, pm8xxx_irq_handler);
+	set_irq_wake(devirq, 1);
+
+	return chip;
+}
+
+int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+{
+	irq_set_chained_handler(chip->devirq, NULL);
+	kfree(chip);
+	return 0;
+}

+ 4 - 2
drivers/mfd/rdc321x-southbridge.c

@@ -61,12 +61,14 @@ static struct mfd_cell rdc321x_sb_cells[] = {
 		.name		= "rdc321x-wdt",
 		.name		= "rdc321x-wdt",
 		.resources	= rdc321x_wdt_resource,
 		.resources	= rdc321x_wdt_resource,
 		.num_resources	= ARRAY_SIZE(rdc321x_wdt_resource),
 		.num_resources	= ARRAY_SIZE(rdc321x_wdt_resource),
-		.mfd_data	= &rdc321x_wdt_pdata,
+		.platform_data	= &rdc321x_wdt_pdata,
+		.pdata_size	= sizeof(rdc321x_wdt_pdata),
 	}, {
 	}, {
 		.name		= "rdc321x-gpio",
 		.name		= "rdc321x-gpio",
 		.resources	= rdc321x_gpio_resources,
 		.resources	= rdc321x_gpio_resources,
 		.num_resources	= ARRAY_SIZE(rdc321x_gpio_resources),
 		.num_resources	= ARRAY_SIZE(rdc321x_gpio_resources),
-		.mfd_data	= &rdc321x_gpio_pdata,
+		.platform_data	= &rdc321x_gpio_pdata,
+		.pdata_size	= sizeof(rdc321x_gpio_pdata),
 	},
 	},
 };
 };
 
 

+ 4 - 2
drivers/mfd/t7l66xb.c

@@ -170,7 +170,8 @@ static struct mfd_cell t7l66xb_cells[] = {
 		.name = "tmio-mmc",
 		.name = "tmio-mmc",
 		.enable = t7l66xb_mmc_enable,
 		.enable = t7l66xb_mmc_enable,
 		.disable = t7l66xb_mmc_disable,
 		.disable = t7l66xb_mmc_disable,
-		.mfd_data = &t7166xb_mmc_data,
+		.platform_data = &t7166xb_mmc_data,
+		.pdata_size    = sizeof(t7166xb_mmc_data),
 		.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
 		.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
 		.resources = t7l66xb_mmc_resources,
 		.resources = t7l66xb_mmc_resources,
 	},
 	},
@@ -382,7 +383,8 @@ static int t7l66xb_probe(struct platform_device *dev)
 
 
 	t7l66xb_attach_irq(dev);
 	t7l66xb_attach_irq(dev);
 
 
-	t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data;
+	t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
+	t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);
 
 
 	ret = mfd_add_devices(&dev->dev, dev->id,
 	ret = mfd_add_devices(&dev->dev, dev->id,
 			      t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
 			      t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),

+ 2 - 1
drivers/mfd/tc6387xb.c

@@ -131,7 +131,8 @@ static struct mfd_cell tc6387xb_cells[] = {
 		.name = "tmio-mmc",
 		.name = "tmio-mmc",
 		.enable = tc6387xb_mmc_enable,
 		.enable = tc6387xb_mmc_enable,
 		.disable = tc6387xb_mmc_disable,
 		.disable = tc6387xb_mmc_disable,
-		.mfd_data = &tc6387xb_mmc_data,
+		.platform_data = &tc6387xb_mmc_data,
+		.pdata_size    = sizeof(tc6387xb_mmc_data),
 		.num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
 		.num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
 		.resources = tc6387xb_mmc_resources,
 		.resources = tc6387xb_mmc_resources,
 	},
 	},

+ 7 - 3
drivers/mfd/tc6393xb.c

@@ -393,7 +393,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
 		.name = "tmio-mmc",
 		.name = "tmio-mmc",
 		.enable = tc6393xb_mmc_enable,
 		.enable = tc6393xb_mmc_enable,
 		.resume = tc6393xb_mmc_resume,
 		.resume = tc6393xb_mmc_resume,
-		.mfd_data = &tc6393xb_mmc_data,
+		.platform_data = &tc6393xb_mmc_data,
+		.pdata_size    = sizeof(tc6393xb_mmc_data),
 		.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
 		.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
 		.resources = tc6393xb_mmc_resources,
 		.resources = tc6393xb_mmc_resources,
 	},
 	},
@@ -692,8 +693,11 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
 			goto err_setup;
 			goto err_setup;
 	}
 	}
 
 
-	tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data;
-	tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data;
+	tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data;
+	tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size =
+						sizeof(*tcpd->nand_data);
+	tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data;
+	tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data);
 
 
 	ret = mfd_add_devices(&dev->dev, dev->id,
 	ret = mfd_add_devices(&dev->dev, dev->id,
 			tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
 			tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),

+ 54 - 27
drivers/mfd/timberdale.c

@@ -384,7 +384,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
 		.name = "timb-dma",
 		.name = "timb-dma",
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.resources = timberdale_dma_resources,
 		.resources = timberdale_dma_resources,
-		.mfd_data = &timb_dma_platform_data,
+		.platform_data = &timb_dma_platform_data,
+		.pdata_size = sizeof(timb_dma_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-uart",
 		.name = "timb-uart",
@@ -395,37 +396,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
 		.name = "xiic-i2c",
 		.name = "xiic-i2c",
 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
 		.resources = timberdale_xiic_resources,
 		.resources = timberdale_xiic_resources,
-		.mfd_data = &timberdale_xiic_platform_data,
+		.platform_data = &timberdale_xiic_platform_data,
+		.pdata_size = sizeof(timberdale_xiic_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-gpio",
 		.name = "timb-gpio",
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.resources = timberdale_gpio_resources,
 		.resources = timberdale_gpio_resources,
-		.mfd_data = &timberdale_gpio_platform_data,
+		.platform_data = &timberdale_gpio_platform_data,
+		.pdata_size = sizeof(timberdale_gpio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-video",
 		.name = "timb-video",
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.resources = timberdale_video_resources,
 		.resources = timberdale_video_resources,
-		.mfd_data = &timberdale_video_platform_data,
+		.platform_data = &timberdale_video_platform_data,
+		.pdata_size = sizeof(timberdale_video_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-radio",
 		.name = "timb-radio",
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.resources = timberdale_radio_resources,
 		.resources = timberdale_radio_resources,
-		.mfd_data = &timberdale_radio_platform_data,
+		.platform_data = &timberdale_radio_platform_data,
+		.pdata_size = sizeof(timberdale_radio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "xilinx_spi",
 		.name = "xilinx_spi",
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.resources = timberdale_spi_resources,
 		.resources = timberdale_spi_resources,
-		.mfd_data = &timberdale_xspi_platform_data,
+		.platform_data = &timberdale_xspi_platform_data,
+		.pdata_size = sizeof(timberdale_xspi_platform_data),
 	},
 	},
 	{
 	{
 		.name = "ks8842",
 		.name = "ks8842",
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.resources = timberdale_eth_resources,
 		.resources = timberdale_eth_resources,
-		.mfd_data = &timberdale_ks8842_platform_data,
+		.platform_data = &timberdale_ks8842_platform_data,
+		.pdata_size = sizeof(timberdale_ks8842_platform_data),
 	},
 	},
 };
 };
 
 
@@ -434,7 +441,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
 		.name = "timb-dma",
 		.name = "timb-dma",
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.resources = timberdale_dma_resources,
 		.resources = timberdale_dma_resources,
-		.mfd_data = &timb_dma_platform_data,
+		.platform_data = &timb_dma_platform_data,
+		.pdata_size = sizeof(timb_dma_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-uart",
 		.name = "timb-uart",
@@ -450,13 +458,15 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
 		.name = "xiic-i2c",
 		.name = "xiic-i2c",
 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
 		.resources = timberdale_xiic_resources,
 		.resources = timberdale_xiic_resources,
-		.mfd_data = &timberdale_xiic_platform_data,
+		.platform_data = &timberdale_xiic_platform_data,
+		.pdata_size = sizeof(timberdale_xiic_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-gpio",
 		.name = "timb-gpio",
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.resources = timberdale_gpio_resources,
 		.resources = timberdale_gpio_resources,
-		.mfd_data = &timberdale_gpio_platform_data,
+		.platform_data = &timberdale_gpio_platform_data,
+		.pdata_size = sizeof(timberdale_gpio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-mlogicore",
 		.name = "timb-mlogicore",
@@ -467,25 +477,29 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
 		.name = "timb-video",
 		.name = "timb-video",
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.resources = timberdale_video_resources,
 		.resources = timberdale_video_resources,
-		.mfd_data = &timberdale_video_platform_data,
+		.platform_data = &timberdale_video_platform_data,
+		.pdata_size = sizeof(timberdale_video_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-radio",
 		.name = "timb-radio",
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.resources = timberdale_radio_resources,
 		.resources = timberdale_radio_resources,
-		.mfd_data = &timberdale_radio_platform_data,
+		.platform_data = &timberdale_radio_platform_data,
+		.pdata_size = sizeof(timberdale_radio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "xilinx_spi",
 		.name = "xilinx_spi",
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.resources = timberdale_spi_resources,
 		.resources = timberdale_spi_resources,
-		.mfd_data = &timberdale_xspi_platform_data,
+		.platform_data = &timberdale_xspi_platform_data,
+		.pdata_size = sizeof(timberdale_xspi_platform_data),
 	},
 	},
 	{
 	{
 		.name = "ks8842",
 		.name = "ks8842",
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.resources = timberdale_eth_resources,
 		.resources = timberdale_eth_resources,
-		.mfd_data = &timberdale_ks8842_platform_data,
+		.platform_data = &timberdale_ks8842_platform_data,
+		.pdata_size = sizeof(timberdale_ks8842_platform_data),
 	},
 	},
 };
 };
 
 
@@ -494,7 +508,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
 		.name = "timb-dma",
 		.name = "timb-dma",
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.resources = timberdale_dma_resources,
 		.resources = timberdale_dma_resources,
-		.mfd_data = &timb_dma_platform_data,
+		.platform_data = &timb_dma_platform_data,
+		.pdata_size = sizeof(timb_dma_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-uart",
 		.name = "timb-uart",
@@ -505,31 +520,36 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
 		.name = "xiic-i2c",
 		.name = "xiic-i2c",
 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
 		.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
 		.resources = timberdale_xiic_resources,
 		.resources = timberdale_xiic_resources,
-		.mfd_data = &timberdale_xiic_platform_data,
+		.platform_data = &timberdale_xiic_platform_data,
+		.pdata_size = sizeof(timberdale_xiic_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-gpio",
 		.name = "timb-gpio",
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.resources = timberdale_gpio_resources,
 		.resources = timberdale_gpio_resources,
-		.mfd_data = &timberdale_gpio_platform_data,
+		.platform_data = &timberdale_gpio_platform_data,
+		.pdata_size = sizeof(timberdale_gpio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-video",
 		.name = "timb-video",
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.resources = timberdale_video_resources,
 		.resources = timberdale_video_resources,
-		.mfd_data = &timberdale_video_platform_data,
+		.platform_data = &timberdale_video_platform_data,
+		.pdata_size = sizeof(timberdale_video_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-radio",
 		.name = "timb-radio",
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.resources = timberdale_radio_resources,
 		.resources = timberdale_radio_resources,
-		.mfd_data = &timberdale_radio_platform_data,
+		.platform_data = &timberdale_radio_platform_data,
+		.pdata_size = sizeof(timberdale_radio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "xilinx_spi",
 		.name = "xilinx_spi",
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.resources = timberdale_spi_resources,
 		.resources = timberdale_spi_resources,
-		.mfd_data = &timberdale_xspi_platform_data,
+		.platform_data = &timberdale_xspi_platform_data,
+		.pdata_size = sizeof(timberdale_xspi_platform_data),
 	},
 	},
 };
 };
 
 
@@ -538,7 +558,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
 		.name = "timb-dma",
 		.name = "timb-dma",
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.num_resources = ARRAY_SIZE(timberdale_dma_resources),
 		.resources = timberdale_dma_resources,
 		.resources = timberdale_dma_resources,
-		.mfd_data = &timb_dma_platform_data,
+		.platform_data = &timb_dma_platform_data,
+		.pdata_size = sizeof(timb_dma_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-uart",
 		.name = "timb-uart",
@@ -549,37 +570,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
 		.name = "ocores-i2c",
 		.name = "ocores-i2c",
 		.num_resources = ARRAY_SIZE(timberdale_ocores_resources),
 		.num_resources = ARRAY_SIZE(timberdale_ocores_resources),
 		.resources = timberdale_ocores_resources,
 		.resources = timberdale_ocores_resources,
-		.mfd_data = &timberdale_ocores_platform_data,
+		.platform_data = &timberdale_ocores_platform_data,
+		.pdata_size = sizeof(timberdale_ocores_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-gpio",
 		.name = "timb-gpio",
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
 		.resources = timberdale_gpio_resources,
 		.resources = timberdale_gpio_resources,
-		.mfd_data = &timberdale_gpio_platform_data,
+		.platform_data = &timberdale_gpio_platform_data,
+		.pdata_size = sizeof(timberdale_gpio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-video",
 		.name = "timb-video",
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.num_resources = ARRAY_SIZE(timberdale_video_resources),
 		.resources = timberdale_video_resources,
 		.resources = timberdale_video_resources,
-		.mfd_data = &timberdale_video_platform_data,
+		.platform_data = &timberdale_video_platform_data,
+		.pdata_size = sizeof(timberdale_video_platform_data),
 	},
 	},
 	{
 	{
 		.name = "timb-radio",
 		.name = "timb-radio",
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.num_resources = ARRAY_SIZE(timberdale_radio_resources),
 		.resources = timberdale_radio_resources,
 		.resources = timberdale_radio_resources,
-		.mfd_data = &timberdale_radio_platform_data,
+		.platform_data = &timberdale_radio_platform_data,
+		.pdata_size = sizeof(timberdale_radio_platform_data),
 	},
 	},
 	{
 	{
 		.name = "xilinx_spi",
 		.name = "xilinx_spi",
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.num_resources = ARRAY_SIZE(timberdale_spi_resources),
 		.resources = timberdale_spi_resources,
 		.resources = timberdale_spi_resources,
-		.mfd_data = &timberdale_xspi_platform_data,
+		.platform_data = &timberdale_xspi_platform_data,
+		.pdata_size = sizeof(timberdale_xspi_platform_data),
 	},
 	},
 	{
 	{
 		.name = "ks8842",
 		.name = "ks8842",
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.resources = timberdale_eth_resources,
 		.resources = timberdale_eth_resources,
-		.mfd_data = &timberdale_ks8842_platform_data,
+		.platform_data = &timberdale_ks8842_platform_data,
+		.pdata_size = sizeof(timberdale_ks8842_platform_data),
 	},
 	},
 };
 };
 
 

+ 2 - 1
drivers/mfd/tps6105x.c

@@ -183,7 +183,8 @@ static int __devinit tps6105x_probe(struct i2c_client *client,
 	/* Set up and register the platform devices. */
 	/* Set up and register the platform devices. */
 	for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
 	for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
 		/* One state holder for all drivers, this is simple */
 		/* One state holder for all drivers, this is simple */
-		tps6105x_cells[i].mfd_data = tps6105x;
+		tps6105x_cells[i].platform_data = tps6105x;
+		tps6105x_cells[i].pdata_size = sizeof(*tps6105x);
 	}
 	}
 
 
 	ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
 	ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,

+ 2 - 2
drivers/mfd/tps6586x.c

@@ -270,8 +270,8 @@ static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
 {
 {
 	struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
 	struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
 
 
-	__tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
-			 value << offset);
+	tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET2,
+			value << offset, 1 << offset);
 }
 }
 
 
 static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
 static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,

+ 215 - 37
drivers/mfd/twl-core.c

@@ -198,6 +198,7 @@
 #define TWL6030_BASEADD_GASGAUGE	0x00C0
 #define TWL6030_BASEADD_GASGAUGE	0x00C0
 #define TWL6030_BASEADD_PIH		0x00D0
 #define TWL6030_BASEADD_PIH		0x00D0
 #define TWL6030_BASEADD_CHARGER		0x00E0
 #define TWL6030_BASEADD_CHARGER		0x00E0
+#define TWL6025_BASEADD_CHARGER		0x00DA
 
 
 /* subchip/slave 2 0x4A - DFT */
 /* subchip/slave 2 0x4A - DFT */
 #define TWL6030_BASEADD_DIEID		0x00C0
 #define TWL6030_BASEADD_DIEID		0x00C0
@@ -229,6 +230,9 @@
 /* is driver active, bound to a chip? */
 /* is driver active, bound to a chip? */
 static bool inuse;
 static bool inuse;
 
 
+/* TWL IDCODE Register value */
+static u32 twl_idcode;
+
 static unsigned int twl_id;
 static unsigned int twl_id;
 unsigned int twl_rev(void)
 unsigned int twl_rev(void)
 {
 {
@@ -328,6 +332,7 @@ static struct twl_mapping twl6030_map[] = {
 
 
 	{ SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
 	{ SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
 	{ SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
 	{ SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
+	{ SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
 };
 };
 
 
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
@@ -487,6 +492,58 @@ EXPORT_SYMBOL(twl_i2c_read_u8);
 
 
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
+/**
+ * twl_read_idcode_register - API to read the IDCODE register.
+ *
+ * Unlocks the IDCODE register and read the 32 bit value.
+ */
+static int twl_read_idcode_register(void)
+{
+	int err;
+
+	err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK,
+						REG_UNLOCK_TEST_REG);
+	if (err) {
+		pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err);
+		goto fail;
+	}
+
+	err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
+						REG_IDCODE_7_0, 4);
+	if (err) {
+		pr_err("TWL4030: unable to read IDCODE -%d\n", err);
+		goto fail;
+	}
+
+	err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG);
+	if (err)
+		pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err);
+fail:
+	return err;
+}
+
+/**
+ * twl_get_type - API to get TWL Si type.
+ *
+ * Api to get the TWL Si type from IDCODE value.
+ */
+int twl_get_type(void)
+{
+	return TWL_SIL_TYPE(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_type);
+
+/**
+ * twl_get_version - API to get TWL Si version.
+ *
+ * Api to get the TWL Si version from IDCODE value.
+ */
+int twl_get_version(void)
+{
+	return TWL_SIL_REV(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_version);
+
 static struct device *
 static struct device *
 add_numbered_child(unsigned chip, const char *name, int num,
 add_numbered_child(unsigned chip, const char *name, int num,
 		void *pdata, unsigned pdata_len,
 		void *pdata, unsigned pdata_len,
@@ -549,7 +606,7 @@ static inline struct device *add_child(unsigned chip, const char *name,
 static struct device *
 static struct device *
 add_regulator_linked(int num, struct regulator_init_data *pdata,
 add_regulator_linked(int num, struct regulator_init_data *pdata,
 		struct regulator_consumer_supply *consumers,
 		struct regulator_consumer_supply *consumers,
-		unsigned num_consumers)
+		unsigned num_consumers, unsigned long features)
 {
 {
 	unsigned sub_chip_id;
 	unsigned sub_chip_id;
 	/* regulator framework demands init_data ... */
 	/* regulator framework demands init_data ... */
@@ -561,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
 		pdata->num_consumer_supplies = num_consumers;
 		pdata->num_consumer_supplies = num_consumers;
 	}
 	}
 
 
+	pdata->driver_data = (void *)features;
+
 	/* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
 	/* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
 	sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
 	sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
 	return add_numbered_child(sub_chip_id, "twl_reg", num,
 	return add_numbered_child(sub_chip_id, "twl_reg", num,
@@ -568,9 +627,10 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
 }
 }
 
 
 static struct device *
 static struct device *
-add_regulator(int num, struct regulator_init_data *pdata)
+add_regulator(int num, struct regulator_init_data *pdata,
+		unsigned long features)
 {
 {
-	return add_regulator_linked(num, pdata, NULL, 0);
+	return add_regulator_linked(num, pdata, NULL, 0, features);
 }
 }
 
 
 /*
 /*
@@ -650,17 +710,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 			};
 			};
 
 
 			child = add_regulator_linked(TWL4030_REG_VUSB1V5,
 			child = add_regulator_linked(TWL4030_REG_VUSB1V5,
-						      &usb_fixed, &usb1v5, 1);
+						      &usb_fixed, &usb1v5, 1,
+						      features);
 			if (IS_ERR(child))
 			if (IS_ERR(child))
 				return PTR_ERR(child);
 				return PTR_ERR(child);
 
 
 			child = add_regulator_linked(TWL4030_REG_VUSB1V8,
 			child = add_regulator_linked(TWL4030_REG_VUSB1V8,
-						      &usb_fixed, &usb1v8, 1);
+						      &usb_fixed, &usb1v8, 1,
+						      features);
 			if (IS_ERR(child))
 			if (IS_ERR(child))
 				return PTR_ERR(child);
 				return PTR_ERR(child);
 
 
 			child = add_regulator_linked(TWL4030_REG_VUSB3V1,
 			child = add_regulator_linked(TWL4030_REG_VUSB3V1,
-						      &usb_fixed, &usb3v1, 1);
+						      &usb_fixed, &usb3v1, 1,
+						      features);
 			if (IS_ERR(child))
 			if (IS_ERR(child))
 				return PTR_ERR(child);
 				return PTR_ERR(child);
 
 
@@ -685,9 +748,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 	}
 	}
 	if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
 	if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
 
 
-		static struct regulator_consumer_supply usb3v3 = {
-			.supply =	"vusb",
-		};
+		static struct regulator_consumer_supply usb3v3;
+		int regulator;
 
 
 		if (twl_has_regulator()) {
 		if (twl_has_regulator()) {
 			/* this is a template that gets copied */
 			/* this is a template that gets copied */
@@ -700,12 +762,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 					| REGULATOR_CHANGE_STATUS,
 					| REGULATOR_CHANGE_STATUS,
 			};
 			};
 
 
-			child = add_regulator_linked(TWL6030_REG_VUSB,
-						      &usb_fixed, &usb3v3, 1);
+			if (features & TWL6025_SUBCLASS) {
+				usb3v3.supply =	"ldousb";
+				regulator = TWL6025_REG_LDOUSB;
+			} else {
+				usb3v3.supply = "vusb";
+				regulator = TWL6030_REG_VUSB;
+			}
+			child = add_regulator_linked(regulator, &usb_fixed,
+							&usb3v3, 1,
+							features);
 			if (IS_ERR(child))
 			if (IS_ERR(child))
 				return PTR_ERR(child);
 				return PTR_ERR(child);
 		}
 		}
 
 
+		pdata->usb->features = features;
+
 		child = add_child(0, "twl6030_usb",
 		child = add_child(0, "twl6030_usb",
 			pdata->usb, sizeof(*pdata->usb),
 			pdata->usb, sizeof(*pdata->usb),
 			true,
 			true,
@@ -718,7 +790,16 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 		/* we need to connect regulators to this transceiver */
 		/* we need to connect regulators to this transceiver */
 		if (twl_has_regulator() && child)
 		if (twl_has_regulator() && child)
 			usb3v3.dev = child;
 			usb3v3.dev = child;
+	} else if (twl_has_regulator() && twl_class_is_6030()) {
+		if (features & TWL6025_SUBCLASS)
+			child = add_regulator(TWL6025_REG_LDOUSB,
+						pdata->ldousb, features);
+		else
+			child = add_regulator(TWL6030_REG_VUSB,
+						pdata->vusb, features);
 
 
+			if (IS_ERR(child))
+					return PTR_ERR(child);
 	}
 	}
 
 
 	if (twl_has_watchdog() && twl_class_is_4030()) {
 	if (twl_has_watchdog() && twl_class_is_4030()) {
@@ -755,46 +836,55 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
 
 	/* twl4030 regulators */
 	/* twl4030 regulators */
 	if (twl_has_regulator() && twl_class_is_4030()) {
 	if (twl_has_regulator() && twl_class_is_4030()) {
-		child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
+		child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VIO, pdata->vio);
+		child = add_regulator(TWL4030_REG_VIO, pdata->vio,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
+		child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
+		child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
+		child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
+		child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
 		child = add_regulator((features & TWL4030_VAUX2)
 		child = add_regulator((features & TWL4030_VAUX2)
 					? TWL4030_REG_VAUX2_4030
 					? TWL4030_REG_VAUX2_4030
 					: TWL4030_REG_VAUX2,
 					: TWL4030_REG_VAUX2,
-				pdata->vaux2);
+				pdata->vaux2, features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
+		child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
+		child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
+		child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
@@ -802,72 +892,152 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 	/* maybe add LDOs that are omitted on cost-reduced parts */
 	/* maybe add LDOs that are omitted on cost-reduced parts */
 	if (twl_has_regulator() && !(features & TPS_SUBSET)
 	if (twl_has_regulator() && !(features & TPS_SUBSET)
 	  && twl_class_is_4030()) {
 	  && twl_class_is_4030()) {
-		child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
+		child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
+		child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
+		child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
+		child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
+		child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
+		child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
 
 
 	/* twl6030 regulators */
 	/* twl6030 regulators */
+	if (twl_has_regulator() && twl_class_is_6030() &&
+			!(features & TWL6025_SUBCLASS)) {
+		child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_VPP, pdata->vpp,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_VDAC, pdata->vdac,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+	}
+
+	/* 6030 and 6025 share this regulator */
 	if (twl_has_regulator() && twl_class_is_6030()) {
 	if (twl_has_regulator() && twl_class_is_6030()) {
-		child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc);
+		child = add_regulator(TWL6030_REG_VANA, pdata->vana,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
+	}
 
 
-		child = add_regulator(TWL6030_REG_VPP, pdata->vpp);
+	/* twl6025 regulators */
+	if (twl_has_regulator() && twl_class_is_6030() &&
+			(features & TWL6025_SUBCLASS)) {
+		child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim);
+		child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_VANA, pdata->vana);
+		child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio);
+		child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_VDAC, pdata->vdac);
+		child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
+		child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2);
+		child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
+		child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 
 
-		child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg);
+		child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
+					features);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
+
+		child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
+		child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
+					features);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+
 	}
 	}
 
 
 	if (twl_has_bci() && pdata->bci &&
 	if (twl_has_bci() && pdata->bci &&
@@ -1014,6 +1184,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	unsigned			i;
 	unsigned			i;
 	struct twl4030_platform_data	*pdata = client->dev.platform_data;
 	struct twl4030_platform_data	*pdata = client->dev.platform_data;
 	u8 temp;
 	u8 temp;
+	int ret = 0;
 
 
 	if (!pdata) {
 	if (!pdata) {
 		dev_dbg(&client->dev, "no platform data?\n");
 		dev_dbg(&client->dev, "no platform data?\n");
@@ -1060,6 +1231,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* setup clock framework */
 	/* setup clock framework */
 	clocks_init(&client->dev, pdata->clock);
 	clocks_init(&client->dev, pdata->clock);
 
 
+	/* read TWL IDCODE Register */
+	if (twl_id == TWL4030_CLASS_ID) {
+		ret = twl_read_idcode_register();
+		WARN(ret < 0, "Error: reading twl_idcode register value\n");
+	}
+
 	/* load power event scripts */
 	/* load power event scripts */
 	if (twl_has_power() && pdata->power)
 	if (twl_has_power() && pdata->power)
 		twl4030_power_init(pdata->power);
 		twl4030_power_init(pdata->power);
@@ -1108,6 +1285,7 @@ static const struct i2c_device_id twl_ids[] = {
 	{ "tps65930", TPS_SUBSET },	/* fewer LDOs and DACs; no charger */
 	{ "tps65930", TPS_SUBSET },	/* fewer LDOs and DACs; no charger */
 	{ "tps65920", TPS_SUBSET },	/* fewer LDOs; no codec or charger */
 	{ "tps65920", TPS_SUBSET },	/* fewer LDOs; no codec or charger */
 	{ "twl6030", TWL6030_CLASS },	/* "Phoenix power chip" */
 	{ "twl6030", TWL6030_CLASS },	/* "Phoenix power chip" */
+	{ "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
 	{ /* end of list */ },
 	{ /* end of list */ },
 };
 };
 MODULE_DEVICE_TABLE(i2c, twl_ids);
 MODULE_DEVICE_TABLE(i2c, twl_ids);

+ 6 - 4
drivers/mfd/twl4030-codec.c

@@ -1,7 +1,7 @@
 /*
 /*
  * MFD driver for twl4030 codec submodule
  * MFD driver for twl4030 codec submodule
  *
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * Copyright:   (C) 2009 Nokia Corporation
  * Copyright:   (C) 2009 Nokia Corporation
  *
  *
@@ -208,13 +208,15 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 	if (pdata->audio) {
 	if (pdata->audio) {
 		cell = &codec->cells[childs];
 		cell = &codec->cells[childs];
 		cell->name = "twl4030-codec";
 		cell->name = "twl4030-codec";
-		cell->mfd_data = pdata->audio;
+		cell->platform_data = pdata->audio;
+		cell->pdata_size = sizeof(*pdata->audio);
 		childs++;
 		childs++;
 	}
 	}
 	if (pdata->vibra) {
 	if (pdata->vibra) {
 		cell = &codec->cells[childs];
 		cell = &codec->cells[childs];
 		cell->name = "twl4030-vibra";
 		cell->name = "twl4030-vibra";
-		cell->mfd_data = pdata->vibra;
+		cell->platform_data = pdata->vibra;
+		cell->pdata_size = sizeof(*pdata->vibra);
 		childs++;
 		childs++;
 	}
 	}
 
 
@@ -270,6 +272,6 @@ static void __devexit twl4030_codec_exit(void)
 }
 }
 module_exit(twl4030_codec_exit);
 module_exit(twl4030_codec_exit);
 
 
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 

+ 3 - 3
drivers/mfd/twl4030-power.c

@@ -120,7 +120,7 @@ static u8 res_config_addrs[] = {
 	[RES_HFCLKOUT]	= 0x8b,
 	[RES_HFCLKOUT]	= 0x8b,
 	[RES_32KCLKOUT]	= 0x8e,
 	[RES_32KCLKOUT]	= 0x8e,
 	[RES_RESET]	= 0x91,
 	[RES_RESET]	= 0x91,
-	[RES_Main_Ref]	= 0x94,
+	[RES_MAIN_REF]	= 0x94,
 };
 };
 
 
 static int __init twl4030_write_script_byte(u8 address, u8 byte)
 static int __init twl4030_write_script_byte(u8 address, u8 byte)
@@ -448,7 +448,7 @@ static int __init load_twl4030_script(struct twl4030_script *tscript,
 			goto out;
 			goto out;
 	}
 	}
 	if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
 	if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
-		if (order)
+		if (!order)
 			pr_warning("TWL4030: Bad order of scripts (sleep "\
 			pr_warning("TWL4030: Bad order of scripts (sleep "\
 					"script before wakeup) Leads to boot"\
 					"script before wakeup) Leads to boot"\
 					"failure on some boards\n");
 					"failure on some boards\n");
@@ -485,9 +485,9 @@ int twl4030_remove_script(u8 flags)
 			return err;
 			return err;
 	}
 	}
 	if (flags & TWL4030_WAKEUP12_SCRIPT) {
 	if (flags & TWL4030_WAKEUP12_SCRIPT) {
-		if (err)
 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
 		err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
 				R_SEQ_ADD_S2A12);
 				R_SEQ_ADD_S2A12);
+		if (err)
 			return err;
 			return err;
 	}
 	}
 	if (flags & TWL4030_WAKEUP3_SCRIPT) {
 	if (flags & TWL4030_WAKEUP3_SCRIPT) {

+ 2 - 2
drivers/mfd/twl6030-irq.c

@@ -76,8 +76,8 @@ static int twl6030_interrupt_mapping[24] = {
 	USBOTG_INTR_OFFSET,	/* Bit 18	ID			*/
 	USBOTG_INTR_OFFSET,	/* Bit 18	ID			*/
 	USB_PRES_INTR_OFFSET,	/* Bit 19	VBUS			*/
 	USB_PRES_INTR_OFFSET,	/* Bit 19	VBUS			*/
 	CHARGER_INTR_OFFSET,	/* Bit 20	CHRG_CTRL		*/
 	CHARGER_INTR_OFFSET,	/* Bit 20	CHRG_CTRL		*/
-	CHARGER_INTR_OFFSET,	/* Bit 21	EXT_CHRG		*/
-	CHARGER_INTR_OFFSET,	/* Bit 22	INT_CHRG		*/
+	CHARGERFAULT_INTR_OFFSET,	/* Bit 21	EXT_CHRG	*/
+	CHARGERFAULT_INTR_OFFSET,	/* Bit 22	INT_CHRG	*/
 	RSV_INTR_OFFSET,	/* Bit 23	Reserved		*/
 	RSV_INTR_OFFSET,	/* Bit 23	Reserved		*/
 };
 };
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/

+ 4 - 3
drivers/mfd/wl1273-core.c

@@ -153,7 +153,6 @@ out:
  */
  */
 static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
 static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
 {
 {
-	u16 val;
 	int r;
 	int r;
 
 
 	if (volume > WL1273_MAX_VOLUME)
 	if (volume > WL1273_MAX_VOLUME)
@@ -217,7 +216,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
 
 
 	cell = &core->cells[children];
 	cell = &core->cells[children];
 	cell->name = "wl1273_fm_radio";
 	cell->name = "wl1273_fm_radio";
-	cell->mfd_data = &core;
+	cell->platform_data = &core;
+	cell->pdata_size = sizeof(core);
 	children++;
 	children++;
 
 
 	core->read = wl1273_fm_read_reg;
 	core->read = wl1273_fm_read_reg;
@@ -231,7 +231,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
 
 
 		dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
 		dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
 		cell->name = "wl1273-codec";
 		cell->name = "wl1273-codec";
-		cell->mfd_data = &core;
+		cell->platform_data = &core;
+		cell->pdata_size = sizeof(core);
 		children++;
 		children++;
 	}
 	}
 
 

+ 12 - 1
drivers/mfd/wm831x-core.c

@@ -1442,7 +1442,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
 	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
 	int rev;
 	int rev;
 	enum wm831x_parent parent;
 	enum wm831x_parent parent;
-	int ret;
+	int ret, i;
 
 
 	mutex_init(&wm831x->io_lock);
 	mutex_init(&wm831x->io_lock);
 	mutex_init(&wm831x->key_lock);
 	mutex_init(&wm831x->key_lock);
@@ -1581,6 +1581,17 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 		}
 		}
 	}
 	}
 
 
+	if (pdata) {
+		for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
+			if (!pdata->gpio_defaults[i])
+				continue;
+
+			wm831x_reg_write(wm831x,
+					 WM831X_GPIO1_CONTROL + i,
+					 pdata->gpio_defaults[i] & 0xffff);
+		}
+	}
+
 	ret = wm831x_irq_init(wm831x, irq);
 	ret = wm831x_irq_init(wm831x, irq);
 	if (ret != 0)
 	if (ret != 0)
 		goto err;
 		goto err;

+ 14 - 13
drivers/mfd/wm831x-irq.c

@@ -515,12 +515,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
 				 0xffff);
 				 0xffff);
 	}
 	}
 
 
-	if (!irq) {
-		dev_warn(wm831x->dev,
-			 "No interrupt specified - functionality limited\n");
-		return 0;
-	}
-
 	if (!pdata || !pdata->irq_base) {
 	if (!pdata || !pdata->irq_base) {
 		dev_err(wm831x->dev,
 		dev_err(wm831x->dev,
 			"No interrupt base specified, no interrupts\n");
 			"No interrupt base specified, no interrupts\n");
@@ -567,15 +561,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
 #endif
 #endif
 	}
 	}
 
 
-	ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
-				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-				   "wm831x", wm831x);
-	if (ret != 0) {
-		dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
-			irq, ret);
-		return ret;
+	if (irq) {
+		ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
+					   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					   "wm831x", wm831x);
+		if (ret != 0) {
+			dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
+				irq, ret);
+			return ret;
+		}
+	} else {
+		dev_warn(wm831x->dev,
+			 "No interrupt specified - functionality limited\n");
 	}
 	}
 
 
+
+
 	/* Enable top level interrupts, we mask at secondary level */
 	/* Enable top level interrupts, we mask at secondary level */
 	wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
 	wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
 
 

+ 2 - 1
drivers/mfd/wm8400-core.c

@@ -245,7 +245,8 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
 {
 {
 	struct mfd_cell cell = {
 	struct mfd_cell cell = {
 		.name = "wm8400-codec",
 		.name = "wm8400-codec",
-		.mfd_data = wm8400,
+		.platform_data = wm8400,
+		.pdata_size = sizeof(*wm8400),
 	};
 	};
 
 
 	return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
 	return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);

+ 1 - 1
drivers/mmc/host/tmio_mmc.c

@@ -69,7 +69,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
 	if (pdev->num_resources != 2)
 	if (pdev->num_resources != 2)
 		goto out;
 		goto out;
 
 
-	pdata = mfd_get_data(pdev);
+	pdata = pdev->dev.platform_data;
 	if (!pdata || !pdata->hclk)
 	if (!pdata || !pdata->hclk)
 		goto out;
 		goto out;
 
 

+ 1 - 1
drivers/mtd/nand/tmio_nand.c

@@ -372,7 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
 
 
 static int tmio_probe(struct platform_device *dev)
 static int tmio_probe(struct platform_device *dev)
 {
 {
-	struct tmio_nand_data *data = mfd_get_data(dev);
+	struct tmio_nand_data *data = dev->dev.platform_data;
 	struct resource *fcr = platform_get_resource(dev,
 	struct resource *fcr = platform_get_resource(dev,
 			IORESOURCE_MEM, 0);
 			IORESOURCE_MEM, 0);
 	struct resource *ccr = platform_get_resource(dev,
 	struct resource *ccr = platform_get_resource(dev,

+ 1 - 2
drivers/net/can/janz-ican3.c

@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 
 
 #include <linux/netdevice.h>
 #include <linux/netdevice.h>
 #include <linux/can.h>
 #include <linux/can.h>
@@ -1644,7 +1643,7 @@ static int __devinit ican3_probe(struct platform_device *pdev)
 	struct device *dev;
 	struct device *dev;
 	int ret;
 	int ret;
 
 
-	pdata = mfd_get_data(pdev);
+	pdata = pdev->dev.platform_data;
 	if (!pdata)
 	if (!pdata)
 		return -ENXIO;
 		return -ENXIO;
 
 

+ 1 - 2
drivers/net/ks8842.c

@@ -26,7 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/netdevice.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/ethtool.h>
@@ -1146,7 +1145,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
 	struct resource *iomem;
 	struct resource *iomem;
 	struct net_device *netdev;
 	struct net_device *netdev;
 	struct ks8842_adapter *adapter;
 	struct ks8842_adapter *adapter;
-	struct ks8842_platform_data *pdata = mfd_get_data(pdev);
+	struct ks8842_platform_data *pdata = pdev->dev.platform_data;
 	u16 id;
 	u16 id;
 	unsigned i;
 	unsigned i;
 
 

+ 2 - 8
drivers/power/max8925_power.c

@@ -425,16 +425,11 @@ static __devexit int max8925_deinit_charger(struct max8925_power_info *info)
 static __devinit int max8925_power_probe(struct platform_device *pdev)
 static __devinit int max8925_power_probe(struct platform_device *pdev)
 {
 {
 	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
-	struct max8925_platform_data *max8925_pdata;
 	struct max8925_power_pdata *pdata = NULL;
 	struct max8925_power_pdata *pdata = NULL;
 	struct max8925_power_info *info;
 	struct max8925_power_info *info;
 	int ret;
 	int ret;
 
 
-	if (pdev->dev.parent->platform_data) {
-		max8925_pdata = pdev->dev.parent->platform_data;
-		pdata = max8925_pdata->power;
-	}
-
+	pdata = pdev->dev.platform_data;
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(&pdev->dev, "platform data isn't assigned to "
 		dev_err(&pdev->dev, "platform data isn't assigned to "
 			"power supply\n");
 			"power supply\n");
@@ -447,6 +442,7 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
 	info->chip = chip;
 	info->chip = chip;
 	info->gpm = chip->i2c;
 	info->gpm = chip->i2c;
 	info->adc = chip->adc;
 	info->adc = chip->adc;
+	platform_set_drvdata(pdev, info);
 
 
 	info->ac.name = "max8925-ac";
 	info->ac.name = "max8925-ac";
 	info->ac.type = POWER_SUPPLY_TYPE_MAINS;
 	info->ac.type = POWER_SUPPLY_TYPE_MAINS;
@@ -482,8 +478,6 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
 	info->topoff_threshold = pdata->topoff_threshold;
 	info->topoff_threshold = pdata->topoff_threshold;
 	info->fast_charge = pdata->fast_charge;
 	info->fast_charge = pdata->fast_charge;
 	info->set_charger = pdata->set_charger;
 	info->set_charger = pdata->set_charger;
-	dev_set_drvdata(&pdev->dev, info);
-	platform_set_drvdata(pdev, info);
 
 
 	max8925_init_charger(chip, info);
 	max8925_init_charger(chip, info);
 	return 0;
 	return 0;

+ 13 - 17
drivers/regulator/88pm8607.c

@@ -15,7 +15,6 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
-#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/mfd/88pm860x.h>
 
 
 struct pm8607_regulator_info {
 struct pm8607_regulator_info {
@@ -399,36 +398,33 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
 {
 {
 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct pm8607_regulator_info *info = NULL;
 	struct pm8607_regulator_info *info = NULL;
-	struct regulator_init_data *pdata;
-	struct mfd_cell *cell;
+	struct regulator_init_data *pdata = pdev->dev.platform_data;
+	struct resource *res;
 	int i;
 	int i;
 
 
-	cell = pdev->dev.platform_data;
-	if (cell == NULL)
-		return -ENODEV;
-	pdata = cell->mfd_data;
-	if (pdata == NULL)
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource!\n");
 		return -EINVAL;
 		return -EINVAL;
-
+	}
 	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
 	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
 		info = &pm8607_regulator_info[i];
 		info = &pm8607_regulator_info[i];
-		if (!strcmp(info->desc.name, pdata->constraints.name))
+		if (info->desc.id == res->start)
 			break;
 			break;
 	}
 	}
-	if (i > ARRAY_SIZE(pm8607_regulator_info)) {
-		dev_err(&pdev->dev, "Failed to find regulator %s\n",
-			pdata->constraints.name);
+	if ((i < 0) || (i > PM8607_ID_RG_MAX)) {
+		dev_err(&pdev->dev, "Failed to find regulator %llu\n",
+			(unsigned long long)res->start);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-
 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
 	info->chip = chip;
 	info->chip = chip;
 
 
 	/* check DVC ramp slope double */
 	/* check DVC ramp slope double */
-	if (!strcmp(info->desc.name, "BUCK3"))
-		if (info->chip->buck3_double)
-			info->slope_double = 1;
+	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
+		info->slope_double = 1;
 
 
+	/* replace driver_data with info */
 	info->regulator = regulator_register(&info->desc, &pdev->dev,
 	info->regulator = regulator_register(&info->desc, &pdev->dev,
 					     pdata, info);
 					     pdata, info);
 	if (IS_ERR(info->regulator)) {
 	if (IS_ERR(info->regulator)) {

+ 1 - 2
drivers/regulator/ab3100.c

@@ -17,7 +17,6 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/driver.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/core.h>
 
 
 /* LDO registers and some handy masking definitions for AB3100 */
 /* LDO registers and some handy masking definitions for AB3100 */
 #define AB3100_LDO_A		0x40
 #define AB3100_LDO_A		0x40
@@ -582,7 +581,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 
 
 static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
 static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
 {
 {
-	struct ab3100_platform_data *plfdata = mfd_get_data(pdev);
+	struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
 	int err = 0;
 	int err = 0;
 	u8 data;
 	u8 data;
 	int i;
 	int i;

+ 2 - 2
drivers/regulator/db8500-prcmu.c

@@ -13,7 +13,6 @@
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/mfd/db8500-prcmu.h>
 #include <linux/mfd/db8500-prcmu.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
@@ -471,7 +470,8 @@ static struct db8500_regulator_info
 
 
 static int __devinit db8500_regulator_probe(struct platform_device *pdev)
 static int __devinit db8500_regulator_probe(struct platform_device *pdev)
 {
 {
-	struct regulator_init_data *db8500_init_data = mfd_get_data(pdev);
+	struct regulator_init_data *db8500_init_data =
+					dev_get_platdata(&pdev->dev);
 	int i, err;
 	int i, err;
 
 
 	/* register all regulators */
 	/* register all regulators */

+ 8 - 3
drivers/regulator/max8925-regulator.c

@@ -23,6 +23,10 @@
 #define SD1_DVM_SHIFT		5		/* SDCTL1 bit5 */
 #define SD1_DVM_SHIFT		5		/* SDCTL1 bit5 */
 #define SD1_DVM_EN		6		/* SDV1 bit 6 */
 #define SD1_DVM_EN		6		/* SDV1 bit 6 */
 
 
+/* bit definitions in SD & LDO control registers */
+#define OUT_ENABLE   		0x1f		/* Power U/D sequence as I2C */
+#define OUT_DISABLE		0x1e		/* Power U/D sequence as I2C */
+
 struct max8925_regulator_info {
 struct max8925_regulator_info {
 	struct regulator_desc	desc;
 	struct regulator_desc	desc;
 	struct regulator_dev	*regulator;
 	struct regulator_dev	*regulator;
@@ -93,8 +97,8 @@ static int max8925_enable(struct regulator_dev *rdev)
 	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 
 
 	return max8925_set_bits(info->i2c, info->enable_reg,
 	return max8925_set_bits(info->i2c, info->enable_reg,
-				1 << info->enable_bit,
-				1 << info->enable_bit);
+				OUT_ENABLE << info->enable_bit,
+				OUT_ENABLE << info->enable_bit);
 }
 }
 
 
 static int max8925_disable(struct regulator_dev *rdev)
 static int max8925_disable(struct regulator_dev *rdev)
@@ -102,7 +106,8 @@ static int max8925_disable(struct regulator_dev *rdev)
 	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
 
 
 	return max8925_set_bits(info->i2c, info->enable_reg,
 	return max8925_set_bits(info->i2c, info->enable_reg,
-				1 << info->enable_bit, 0);
+				OUT_ENABLE << info->enable_bit,
+				OUT_DISABLE << info->enable_bit);
 }
 }
 
 
 static int max8925_is_enabled(struct regulator_dev *rdev)
 static int max8925_is_enabled(struct regulator_dev *rdev)

+ 4 - 3
drivers/regulator/mc13783-regulator.c

@@ -15,7 +15,6 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/driver.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/err.h>
@@ -337,7 +336,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
 {
 {
 	struct mc13xxx_regulator_priv *priv;
 	struct mc13xxx_regulator_priv *priv;
 	struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
 	struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
-	struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
+	struct mc13783_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
 	struct mc13783_regulator_init_data *init_data;
 	struct mc13783_regulator_init_data *init_data;
 	int i, ret;
 	int i, ret;
 
 
@@ -381,7 +381,8 @@ err:
 static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
 static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
 {
 {
 	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
 	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
-	struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
+	struct mc13783_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
 	int i;
 	int i;
 
 
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);

+ 4 - 3
drivers/regulator/mc13892-regulator.c

@@ -15,7 +15,6 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/driver.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
-#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/err.h>
@@ -521,7 +520,8 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
 {
 {
 	struct mc13xxx_regulator_priv *priv;
 	struct mc13xxx_regulator_priv *priv;
 	struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
 	struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
-	struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
+	struct mc13xxx_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
 	struct mc13xxx_regulator_init_data *init_data;
 	struct mc13xxx_regulator_init_data *init_data;
 	int i, ret;
 	int i, ret;
 	u32 val;
 	u32 val;
@@ -595,7 +595,8 @@ err_free:
 static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
 static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
 {
 {
 	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
 	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
-	struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
+	struct mc13xxx_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
 	int i;
 	int i;
 
 
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);

+ 2 - 2
drivers/regulator/tps6105x-regulator.c

@@ -137,7 +137,7 @@ static struct regulator_desc tps6105x_regulator_desc = {
  */
  */
 static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
 static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
 {
 {
-	struct tps6105x *tps6105x = mfd_get_data(pdev);
+	struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
 	struct tps6105x_platform_data *pdata = tps6105x->pdata;
 	struct tps6105x_platform_data *pdata = tps6105x->pdata;
 	int ret;
 	int ret;
 
 
@@ -164,7 +164,7 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
 
 
 static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
 static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
 {
 {
-	struct tps6105x *tps6105x = platform_get_drvdata(pdev);
+	struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
 	regulator_unregister(tps6105x->regulator);
 	regulator_unregister(tps6105x->regulator);
 	return 0;
 	return 0;
 }
 }

+ 10 - 0
drivers/rtc/Kconfig

@@ -125,6 +125,16 @@ comment "I2C RTC drivers"
 
 
 if I2C
 if I2C
 
 
+config RTC_DRV_88PM860X
+	tristate "Marvell 88PM860x"
+	depends on RTC_CLASS && I2C && MFD_88PM860X
+	help
+	  If you say yes here you get support for RTC function in Marvell
+	  88PM860x chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-88pm860x.
+
 config RTC_DRV_DS1307
 config RTC_DRV_DS1307
 	tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
 	tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
 	help
 	help

+ 1 - 0
drivers/rtc/Makefile

@@ -15,6 +15,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 
 
 # Keep the list ordered.
 # Keep the list ordered.
 
 
+obj-$(CONFIG_RTC_DRV_88PM860X)  += rtc-88pm860x.o
 obj-$(CONFIG_RTC_DRV_AB3100)	+= rtc-ab3100.o
 obj-$(CONFIG_RTC_DRV_AB3100)	+= rtc-ab3100.o
 obj-$(CONFIG_RTC_DRV_AB8500)	+= rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_AB8500)	+= rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o

+ 427 - 0
drivers/rtc/rtc-88pm860x.c

@@ -0,0 +1,427 @@
+/*
+ * Real Time Clock driver for Marvell 88PM860x PMIC
+ *
+ * Copyright (c) 2010 Marvell International Ltd.
+ * Author:	Haojian Zhuang <haojian.zhuang@marvell.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm860x.h>
+
+#define VRTC_CALIBRATION
+
+struct pm860x_rtc_info {
+	struct pm860x_chip	*chip;
+	struct i2c_client	*i2c;
+	struct rtc_device	*rtc_dev;
+	struct device		*dev;
+	struct delayed_work	calib_work;
+
+	int			irq;
+	int			vrtc;
+	int			(*sync)(unsigned int ticks);
+};
+
+#define REG_VRTC_MEAS1		0x7D
+
+#define REG0_ADDR		0xB0
+#define REG1_ADDR		0xB2
+#define REG2_ADDR		0xB4
+#define REG3_ADDR		0xB6
+
+#define REG0_DATA		0xB1
+#define REG1_DATA		0xB3
+#define REG2_DATA		0xB5
+#define REG3_DATA		0xB7
+
+/* bit definitions of Measurement Enable Register 2 (0x51) */
+#define MEAS2_VRTC		(1 << 0)
+
+/* bit definitions of RTC Register 1 (0xA0) */
+#define ALARM_EN		(1 << 3)
+#define ALARM_WAKEUP		(1 << 4)
+#define ALARM			(1 << 5)
+#define RTC1_USE_XO		(1 << 7)
+
+#define VRTC_CALIB_INTERVAL	(HZ * 60 * 10)		/* 10 minutes */
+
+static irqreturn_t rtc_update_handler(int irq, void *data)
+{
+	struct pm860x_rtc_info *info = (struct pm860x_rtc_info *)data;
+	int mask;
+
+	mask = ALARM | ALARM_WAKEUP;
+	pm860x_set_bits(info->i2c, PM8607_RTC1, mask | ALARM_EN, mask);
+	rtc_update_irq(info->rtc_dev, 1, RTC_AF);
+	return IRQ_HANDLED;
+}
+
+static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+
+	if (enabled)
+		pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM);
+	else
+		pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0);
+	return 0;
+}
+
+/*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+ */
+static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
+				struct rtc_time *alrm)
+{
+	unsigned long next_time;
+	unsigned long now_time;
+
+	next->tm_year = now->tm_year;
+	next->tm_mon = now->tm_mon;
+	next->tm_mday = now->tm_mday;
+	next->tm_hour = alrm->tm_hour;
+	next->tm_min = alrm->tm_min;
+	next->tm_sec = alrm->tm_sec;
+
+	rtc_tm_to_time(now, &now_time);
+	rtc_tm_to_time(next, &next_time);
+
+	if (next_time < now_time) {
+		/* Advance one day */
+		next_time += 60 * 60 * 24;
+		rtc_time_to_tm(next_time, next);
+	}
+}
+
+static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+	unsigned char buf[8];
+	unsigned long ticks, base, data;
+
+	pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+	dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+		buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+	base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+	/* load 32-bit read-only counter */
+	pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	ticks = base + data;
+	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+		base, data, ticks);
+
+	rtc_time_to_tm(ticks, tm);
+
+	return 0;
+}
+
+static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+	unsigned char buf[4];
+	unsigned long ticks, base, data;
+
+	if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
+		dev_dbg(info->dev, "Set time %d out of range. "
+			"Please set time between 1970 to 2038.\n",
+			1900 + tm->tm_year);
+		return -EINVAL;
+	}
+	rtc_tm_to_time(tm, &ticks);
+
+	/* load 32-bit read-only counter */
+	pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	base = ticks - data;
+	dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+		base, data, ticks);
+
+	pm860x_page_reg_write(info->i2c, REG0_DATA, (base >> 24) & 0xFF);
+	pm860x_page_reg_write(info->i2c, REG1_DATA, (base >> 16) & 0xFF);
+	pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF);
+	pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF);
+
+	if (info->sync)
+		info->sync(ticks);
+	return 0;
+}
+
+static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+	unsigned char buf[8];
+	unsigned long ticks, base, data;
+	int ret;
+
+	pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+	dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+		buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+	base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+	pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
+	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	ticks = base + data;
+	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+		base, data, ticks);
+
+	rtc_time_to_tm(ticks, &alrm->time);
+	ret = pm860x_reg_read(info->i2c, PM8607_RTC1);
+	alrm->enabled = (ret & ALARM_EN) ? 1 : 0;
+	alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0;
+	return 0;
+}
+
+static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+	struct rtc_time now_tm, alarm_tm;
+	unsigned long ticks, base, data;
+	unsigned char buf[8];
+	int mask;
+
+	pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0);
+
+	pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+	dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+		buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+	base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+	/* load 32-bit read-only counter */
+	pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+	ticks = base + data;
+	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+		base, data, ticks);
+
+	rtc_time_to_tm(ticks, &now_tm);
+	rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
+	/* get new ticks for alarm in 24 hours */
+	rtc_tm_to_time(&alarm_tm, &ticks);
+	data = ticks - base;
+
+	buf[0] = data & 0xff;
+	buf[1] = (data >> 8) & 0xff;
+	buf[2] = (data >> 16) & 0xff;
+	buf[3] = (data >> 24) & 0xff;
+	pm860x_bulk_write(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
+	if (alrm->enabled) {
+		mask = ALARM | ALARM_WAKEUP | ALARM_EN;
+		pm860x_set_bits(info->i2c, PM8607_RTC1, mask, mask);
+	} else {
+		mask = ALARM | ALARM_WAKEUP | ALARM_EN;
+		pm860x_set_bits(info->i2c, PM8607_RTC1, mask,
+				ALARM | ALARM_WAKEUP);
+	}
+	return 0;
+}
+
+static const struct rtc_class_ops pm860x_rtc_ops = {
+	.read_time	= pm860x_rtc_read_time,
+	.set_time	= pm860x_rtc_set_time,
+	.read_alarm	= pm860x_rtc_read_alarm,
+	.set_alarm	= pm860x_rtc_set_alarm,
+	.alarm_irq_enable = pm860x_rtc_alarm_irq_enable,
+};
+
+#ifdef VRTC_CALIBRATION
+static void calibrate_vrtc_work(struct work_struct *work)
+{
+	struct pm860x_rtc_info *info = container_of(work,
+		struct pm860x_rtc_info, calib_work.work);
+	unsigned char buf[2];
+	unsigned int sum, data, mean, vrtc_set;
+	int i;
+
+	for (i = 0, sum = 0; i < 16; i++) {
+		msleep(100);
+		pm860x_bulk_read(info->i2c, REG_VRTC_MEAS1, 2, buf);
+		data = (buf[0] << 4) | buf[1];
+		data = (data * 5400) >> 12;	/* convert to mv */
+		sum += data;
+	}
+	mean = sum >> 4;
+	vrtc_set = 2700 + (info->vrtc & 0x3) * 200;
+	dev_dbg(info->dev, "mean:%d, vrtc_set:%d\n", mean, vrtc_set);
+
+	sum = pm860x_reg_read(info->i2c, PM8607_RTC_MISC1);
+	data = sum & 0x3;
+	if ((mean + 200) < vrtc_set) {
+		/* try higher voltage */
+		if (++data == 4)
+			goto out;
+		data = (sum & 0xf8) | (data & 0x3);
+		pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
+	} else if ((mean - 200) > vrtc_set) {
+		/* try lower voltage */
+		if (data-- == 0)
+			goto out;
+		data = (sum & 0xf8) | (data & 0x3);
+		pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
+	} else
+		goto out;
+	dev_dbg(info->dev, "set 0x%x to RTC_MISC1\n", data);
+	/* trigger next calibration since VRTC is updated */
+	schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
+	return;
+out:
+	/* disable measurement */
+	pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
+	dev_dbg(info->dev, "finish VRTC calibration\n");
+	return;
+}
+#endif
+
+static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
+{
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm860x_rtc_pdata *pdata = NULL;
+	struct pm860x_rtc_info *info;
+	struct rtc_time tm;
+	unsigned long ticks = 0;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (pdata == NULL)
+		dev_warn(&pdev->dev, "No platform data!\n");
+
+	info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	info->irq = platform_get_irq(pdev, 0);
+	if (info->irq < 0) {
+		dev_err(&pdev->dev, "No IRQ resource!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	info->chip = chip;
+	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+	info->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, info);
+
+	ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
+				   IRQF_ONESHOT, "rtc", info);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+			info->irq, ret);
+		goto out;
+	}
+
+	/* set addresses of 32-bit base value for RTC time */
+	pm860x_page_reg_write(info->i2c, REG0_ADDR, REG0_DATA);
+	pm860x_page_reg_write(info->i2c, REG1_ADDR, REG1_DATA);
+	pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA);
+	pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA);
+
+	ret = pm860x_rtc_read_time(&pdev->dev, &tm);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to read initial time.\n");
+		goto out_rtc;
+	}
+	if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
+		tm.tm_year = 70;
+		tm.tm_mon = 0;
+		tm.tm_mday = 1;
+		tm.tm_hour = 0;
+		tm.tm_min = 0;
+		tm.tm_sec = 0;
+		ret = pm860x_rtc_set_time(&pdev->dev, &tm);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Failed to set initial time.\n");
+			goto out_rtc;
+		}
+	}
+	rtc_tm_to_time(&tm, &ticks);
+	if (pdata && pdata->sync) {
+		pdata->sync(ticks);
+		info->sync = pdata->sync;
+	}
+
+	info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev,
+					    &pm860x_rtc_ops, THIS_MODULE);
+	ret = PTR_ERR(info->rtc_dev);
+	if (IS_ERR(info->rtc_dev)) {
+		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+		goto out_rtc;
+	}
+
+	/*
+	 * enable internal XO instead of internal 3.25MHz clock since it can
+	 * free running in PMIC power-down state.
+	 */
+	pm860x_set_bits(info->i2c, PM8607_RTC1, RTC1_USE_XO, RTC1_USE_XO);
+
+#ifdef VRTC_CALIBRATION
+	/* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */
+	if (pdata && pdata->vrtc)
+		info->vrtc = pdata->vrtc & 0x3;
+	else
+		info->vrtc = 1;
+	pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC);
+
+	/* calibrate VRTC */
+	INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
+	schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
+#endif	/* VRTC_CALIBRATION */
+	return 0;
+out_rtc:
+	free_irq(info->irq, info);
+out:
+	kfree(info);
+	return ret;
+}
+
+static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
+{
+	struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
+
+#ifdef VRTC_CALIBRATION
+	flush_scheduled_work();
+	/* disable measurement */
+	pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
+#endif	/* VRTC_CALIBRATION */
+
+	platform_set_drvdata(pdev, NULL);
+	rtc_device_unregister(info->rtc_dev);
+	free_irq(info->irq, info);
+	kfree(info);
+	return 0;
+}
+
+static struct platform_driver pm860x_rtc_driver = {
+	.driver		= {
+		.name	= "88pm860x-rtc",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pm860x_rtc_probe,
+	.remove		= __devexit_p(pm860x_rtc_remove),
+};
+
+static int __init pm860x_rtc_init(void)
+{
+	return platform_driver_register(&pm860x_rtc_driver);
+}
+module_init(pm860x_rtc_init);
+
+static void __exit pm860x_rtc_exit(void)
+{
+	platform_driver_unregister(&pm860x_rtc_driver);
+}
+module_exit(pm860x_rtc_exit);
+
+MODULE_DESCRIPTION("Marvell 88PM860x RTC driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");

+ 1 - 2
drivers/spi/xilinx_spi.c

@@ -18,7 +18,6 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/spi/xilinx_spi.h>
 #include <linux/spi/xilinx_spi.h>
@@ -471,7 +470,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev)
 	struct spi_master *master;
 	struct spi_master *master;
 	u8 i;
 	u8 i;
 
 
-	pdata = mfd_get_data(dev);
+	pdata = dev->dev.platform_data;
 	if (pdata) {
 	if (pdata) {
 		num_cs = pdata->num_chipselect;
 		num_cs = pdata->num_chipselect;
 		little_endian = pdata->little_endian;
 		little_endian = pdata->little_endian;

+ 1 - 6
drivers/video/backlight/88pm860x_bl.c

@@ -16,7 +16,6 @@
 #include <linux/fb.h>
 #include <linux/fb.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/backlight.h>
 #include <linux/backlight.h>
-#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/mfd/88pm860x.h>
 
 
 #define MAX_BRIGHTNESS		(0xFF)
 #define MAX_BRIGHTNESS		(0xFF)
@@ -168,7 +167,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 	struct pm860x_backlight_pdata *pdata = NULL;
 	struct pm860x_backlight_pdata *pdata = NULL;
 	struct pm860x_backlight_data *data;
 	struct pm860x_backlight_data *data;
 	struct backlight_device *bl;
 	struct backlight_device *bl;
-	struct mfd_cell *cell;
 	struct resource *res;
 	struct resource *res;
 	struct backlight_properties props;
 	struct backlight_properties props;
 	unsigned char value;
 	unsigned char value;
@@ -181,10 +179,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	cell = pdev->dev.platform_data;
-	if (cell == NULL)
-		return -ENODEV;
-	pdata = cell->mfd_data;
+	pdata = pdev->dev.platform_data;
 	if (pdata == NULL) {
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "platform data isn't assigned to "
 		dev_err(&pdev->dev, "platform data isn't assigned to "
 			"backlight\n");
 			"backlight\n");

+ 5 - 7
drivers/video/tmiofb.c

@@ -250,7 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
  */
  */
 static int tmiofb_hw_stop(struct platform_device *dev)
 static int tmiofb_hw_stop(struct platform_device *dev)
 {
 {
-	struct tmio_fb_data *data = mfd_get_data(dev);
+	struct tmio_fb_data *data = dev->dev.platform_data;
 	struct fb_info *info = platform_get_drvdata(dev);
 	struct fb_info *info = platform_get_drvdata(dev);
 	struct tmiofb_par *par = info->par;
 	struct tmiofb_par *par = info->par;
 
 
@@ -311,7 +311,7 @@ static int tmiofb_hw_init(struct platform_device *dev)
  */
  */
 static void tmiofb_hw_mode(struct platform_device *dev)
 static void tmiofb_hw_mode(struct platform_device *dev)
 {
 {
-	struct tmio_fb_data *data = mfd_get_data(dev);
+	struct tmio_fb_data *data = dev->dev.platform_data;
 	struct fb_info *info = platform_get_drvdata(dev);
 	struct fb_info *info = platform_get_drvdata(dev);
 	struct fb_videomode *mode = info->mode;
 	struct fb_videomode *mode = info->mode;
 	struct tmiofb_par *par = info->par;
 	struct tmiofb_par *par = info->par;
@@ -557,8 +557,7 @@ static int tmiofb_ioctl(struct fb_info *fbi,
 static struct fb_videomode *
 static struct fb_videomode *
 tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
 tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
 {
 {
-	struct tmio_fb_data *data =
-			mfd_get_data(to_platform_device(info->device));
+	struct tmio_fb_data *data = info->device->platform_data;
 	struct fb_videomode *best = NULL;
 	struct fb_videomode *best = NULL;
 	int i;
 	int i;
 
 
@@ -578,8 +577,7 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 {
 
 
 	struct fb_videomode *mode;
 	struct fb_videomode *mode;
-	struct tmio_fb_data *data =
-			mfd_get_data(to_platform_device(info->device));
+	struct tmio_fb_data *data = info->device->platform_data;
 
 
 	mode = tmiofb_find_mode(info, var);
 	mode = tmiofb_find_mode(info, var);
 	if (!mode || var->bits_per_pixel > 16)
 	if (!mode || var->bits_per_pixel > 16)
@@ -680,7 +678,7 @@ static struct fb_ops tmiofb_ops = {
 static int __devinit tmiofb_probe(struct platform_device *dev)
 static int __devinit tmiofb_probe(struct platform_device *dev)
 {
 {
 	const struct mfd_cell *cell = mfd_get_cell(dev);
 	const struct mfd_cell *cell = mfd_get_cell(dev);
-	struct tmio_fb_data *data = mfd_get_data(dev);
+	struct tmio_fb_data *data = dev->dev.platform_data;
 	struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1);
 	struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1);
 	struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2);
 	struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2);

+ 10 - 2
drivers/w1/masters/ds1wm.c

@@ -216,7 +216,7 @@ static int ds1wm_find_divisor(int gclk)
 static void ds1wm_up(struct ds1wm_data *ds1wm_data)
 static void ds1wm_up(struct ds1wm_data *ds1wm_data)
 {
 {
 	int divisor;
 	int divisor;
-	struct ds1wm_driver_data *plat = mfd_get_data(ds1wm_data->pdev);
+	struct ds1wm_driver_data *plat = ds1wm_data->pdev->dev.platform_data;
 
 
 	if (ds1wm_data->cell->enable)
 	if (ds1wm_data->cell->enable)
 		ds1wm_data->cell->enable(ds1wm_data->pdev);
 		ds1wm_data->cell->enable(ds1wm_data->pdev);
@@ -351,13 +351,21 @@ static int ds1wm_probe(struct platform_device *pdev)
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err0;
 		goto err0;
 	}
 	}
-	plat = mfd_get_data(pdev);
 
 
 	/* calculate bus shift from mem resource */
 	/* calculate bus shift from mem resource */
 	ds1wm_data->bus_shift = resource_size(res) >> 3;
 	ds1wm_data->bus_shift = resource_size(res) >> 3;
 
 
 	ds1wm_data->pdev = pdev;
 	ds1wm_data->pdev = pdev;
 	ds1wm_data->cell = mfd_get_cell(pdev);
 	ds1wm_data->cell = mfd_get_cell(pdev);
+	if (!ds1wm_data->cell) {
+		ret = -ENODEV;
+		goto err1;
+	}
+	plat = pdev->dev.platform_data;
+	if (!plat) {
+		ret = -ENODEV;
+		goto err1;
+	}
 
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 	if (!res) {

+ 1 - 2
drivers/watchdog/rdc321x_wdt.c

@@ -37,7 +37,6 @@
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 #include <linux/mfd/rdc321x.h>
 #include <linux/mfd/rdc321x.h>
-#include <linux/mfd/core.h>
 
 
 #define RDC_WDT_MASK	0x80000000 /* Mask */
 #define RDC_WDT_MASK	0x80000000 /* Mask */
 #define RDC_WDT_EN	0x00800000 /* Enable bit */
 #define RDC_WDT_EN	0x00800000 /* Enable bit */
@@ -232,7 +231,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
 	struct resource *r;
 	struct resource *r;
 	struct rdc321x_wdt_pdata *pdata;
 	struct rdc321x_wdt_pdata *pdata;
 
 
-	pdata = mfd_get_data(pdev);
+	pdata = pdev->dev.platform_data;
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		return -ENODEV;
 		return -ENODEV;

+ 52 - 2
include/linux/i2c/twl.h

@@ -91,6 +91,7 @@
 #define BCI_INTR_OFFSET		2
 #define BCI_INTR_OFFSET		2
 #define MADC_INTR_OFFSET	3
 #define MADC_INTR_OFFSET	3
 #define USB_INTR_OFFSET		4
 #define USB_INTR_OFFSET		4
+#define CHARGERFAULT_INTR_OFFSET 5
 #define BCI_PRES_INTR_OFFSET	9
 #define BCI_PRES_INTR_OFFSET	9
 #define USB_PRES_INTR_OFFSET	10
 #define USB_PRES_INTR_OFFSET	10
 #define RTC_INTR_OFFSET		11
 #define RTC_INTR_OFFSET		11
@@ -150,7 +151,12 @@
 #define MMC_PU				(0x1 << 3)
 #define MMC_PU				(0x1 << 3)
 #define MMC_PD				(0x1 << 2)
 #define MMC_PD				(0x1 << 2)
 
 
-
+#define TWL_SIL_TYPE(rev)		((rev) & 0x00FFFFFF)
+#define TWL_SIL_REV(rev)		((rev) >> 24)
+#define TWL_SIL_5030			0x09002F
+#define TWL5030_REV_1_0			0x00
+#define TWL5030_REV_1_1			0x10
+#define TWL5030_REV_1_2			0x30
 
 
 #define TWL4030_CLASS_ID 		0x4030
 #define TWL4030_CLASS_ID 		0x4030
 #define TWL6030_CLASS_ID 		0x6030
 #define TWL6030_CLASS_ID 		0x6030
@@ -165,6 +171,8 @@ static inline int twl_class_is_ ##class(void)	\
 TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
 TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
 TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
 TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
 
 
+#define TWL6025_SUBCLASS	BIT(4)  /* TWL6025 has changed registers */
+
 /*
 /*
  * Read and write single 8-bit registers
  * Read and write single 8-bit registers
  */
  */
@@ -180,6 +188,9 @@ int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
 int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 
 
+int twl_get_type(void);
+int twl_get_version(void);
+
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
 int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
 int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
 
 
@@ -279,7 +290,12 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
  *(Use TWL_4030_MODULE_INTBR)
  *(Use TWL_4030_MODULE_INTBR)
  */
  */
 
 
+#define REG_IDCODE_7_0			0x00
+#define REG_IDCODE_15_8			0x01
+#define REG_IDCODE_16_23		0x02
+#define REG_IDCODE_31_24		0x03
 #define REG_GPPUPDCTR1			0x0F
 #define REG_GPPUPDCTR1			0x0F
+#define REG_UNLOCK_TEST_REG		0x12
 
 
 /*I2C1 and I2C4(SR) SDA/SCL pull-up control bits */
 /*I2C1 and I2C4(SR) SDA/SCL pull-up control bits */
 
 
@@ -288,6 +304,8 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
 #define SR_I2C_SCL_CTRL_PU		BIT(4)
 #define SR_I2C_SCL_CTRL_PU		BIT(4)
 #define SR_I2C_SDA_CTRL_PU		BIT(6)
 #define SR_I2C_SDA_CTRL_PU		BIT(6)
 
 
+#define TWL_EEPROM_R_UNLOCK		0x49
+
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
 /*
 /*
@@ -501,7 +519,7 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
 #define RES_32KCLKOUT           26
 #define RES_32KCLKOUT           26
 #define RES_RESET               27
 #define RES_RESET               27
 /* Power Reference */
 /* Power Reference */
-#define RES_Main_Ref            28
+#define RES_MAIN_REF            28
 
 
 #define TOTAL_RESOURCES		28
 #define TOTAL_RESOURCES		28
 /*
 /*
@@ -593,6 +611,7 @@ enum twl4030_usb_mode {
 
 
 struct twl4030_usb_data {
 struct twl4030_usb_data {
 	enum twl4030_usb_mode	usb_mode;
 	enum twl4030_usb_mode	usb_mode;
+	unsigned long		features;
 
 
 	int		(*phy_init)(struct device *dev);
 	int		(*phy_init)(struct device *dev);
 	int		(*phy_exit)(struct device *dev);
 	int		(*phy_exit)(struct device *dev);
@@ -699,6 +718,20 @@ struct twl4030_platform_data {
 	struct regulator_init_data              *vcxio;
 	struct regulator_init_data              *vcxio;
 	struct regulator_init_data              *vusb;
 	struct regulator_init_data              *vusb;
 	struct regulator_init_data		*clk32kg;
 	struct regulator_init_data		*clk32kg;
+	/* TWL6025 LDO regulators */
+	struct regulator_init_data		*ldo1;
+	struct regulator_init_data		*ldo2;
+	struct regulator_init_data		*ldo3;
+	struct regulator_init_data		*ldo4;
+	struct regulator_init_data		*ldo5;
+	struct regulator_init_data		*ldo6;
+	struct regulator_init_data		*ldo7;
+	struct regulator_init_data		*ldoln;
+	struct regulator_init_data		*ldousb;
+	/* TWL6025 DCDC regulators */
+	struct regulator_init_data		*smps3;
+	struct regulator_init_data		*smps4;
+	struct regulator_init_data		*vio6025;
 };
 };
 
 
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
@@ -780,4 +813,21 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
 #define TWL6030_REG_VRTC	47
 #define TWL6030_REG_VRTC	47
 #define TWL6030_REG_CLK32KG	48
 #define TWL6030_REG_CLK32KG	48
 
 
+/* LDOs on 6025 have different names */
+#define TWL6025_REG_LDO2	49
+#define TWL6025_REG_LDO4	50
+#define TWL6025_REG_LDO3	51
+#define TWL6025_REG_LDO5	52
+#define TWL6025_REG_LDO1	53
+#define TWL6025_REG_LDO7	54
+#define TWL6025_REG_LDO6	55
+#define TWL6025_REG_LDOLN	56
+#define TWL6025_REG_LDOUSB	57
+
+/* 6025 DCDC supplies */
+#define TWL6025_REG_SMPS3	58
+#define TWL6025_REG_SMPS4	59
+#define TWL6025_REG_VIO		60
+
+
 #endif /* End of __TWL4030_H */
 #endif /* End of __TWL4030_H */

+ 52 - 0
include/linux/input/pmic8xxx-keypad.h

@@ -0,0 +1,52 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#ifndef __PMIC8XXX_KEYPAD_H__
+#define __PMIC8XXX_KEYPAD_H__
+
+#include <linux/input/matrix_keypad.h>
+
+#define PM8XXX_KEYPAD_DEV_NAME     "pm8xxx-keypad"
+
+/**
+ * struct pm8xxx_keypad_platform_data - platform data for keypad
+ * @keymap_data - matrix keymap data
+ * @input_name - input device name
+ * @input_phys_device - input device name
+ * @num_cols - number of columns of keypad
+ * @num_rows - number of row of keypad
+ * @debounce_ms - debounce period in milliseconds
+ * @scan_delay_ms - scan delay in milliseconds
+ * @row_hold_ns - row hold period in nanoseconds
+ * @wakeup - configure keypad as wakeup
+ * @rep - enable or disable key repeat bit
+ */
+struct pm8xxx_keypad_platform_data {
+	const struct matrix_keymap_data *keymap_data;
+
+	const char *input_name;
+	const char *input_phys_device;
+
+	unsigned int num_cols;
+	unsigned int num_rows;
+	unsigned int rows_gpio_start;
+	unsigned int cols_gpio_start;
+
+	unsigned int debounce_ms;
+	unsigned int scan_delay_ms;
+	unsigned int row_hold_ns;
+
+	bool wakeup;
+	bool rep;
+};
+
+#endif /*__PMIC8XXX_KEYPAD_H__ */

+ 31 - 0
include/linux/input/pmic8xxx-pwrkey.h

@@ -0,0 +1,31 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#ifndef __PMIC8XXX_PWRKEY_H__
+#define __PMIC8XXX_PWRKEY_H__
+
+#define PM8XXX_PWRKEY_DEV_NAME "pm8xxx-pwrkey"
+
+/**
+ * struct pm8xxx_pwrkey_platform_data - platform data for pwrkey driver
+ * @pull up:  power on register control for pull up/down configuration
+ * @kpd_trigger_delay_us: time delay for power key state change interrupt
+ *                  trigger.
+ * @wakeup: configure power key as wakeup source
+ */
+struct pm8xxx_pwrkey_platform_data  {
+	bool pull_up;
+	u32  kpd_trigger_delay_us;
+	u32  wakeup;
+};
+
+#endif /* __PMIC8XXX_PWRKEY_H__ */

+ 6 - 0
include/linux/mfd/88pm860x.h

@@ -330,6 +330,11 @@ struct pm860x_led_pdata {
 	unsigned long	flags;
 	unsigned long	flags;
 };
 };
 
 
+struct pm860x_rtc_pdata {
+	int		(*sync)(unsigned int ticks);
+	int		vrtc;
+};
+
 struct pm860x_touch_pdata {
 struct pm860x_touch_pdata {
 	int		gpadc_prebias;
 	int		gpadc_prebias;
 	int		slot_cycle;
 	int		slot_cycle;
@@ -349,6 +354,7 @@ struct pm860x_power_pdata {
 struct pm860x_platform_data {
 struct pm860x_platform_data {
 	struct pm860x_backlight_pdata	*backlight;
 	struct pm860x_backlight_pdata	*backlight;
 	struct pm860x_led_pdata		*led;
 	struct pm860x_led_pdata		*led;
+	struct pm860x_rtc_pdata		*rtc;
 	struct pm860x_touch_pdata	*touch;
 	struct pm860x_touch_pdata	*touch;
 	struct pm860x_power_pdata	*power;
 	struct pm860x_power_pdata	*power;
 	struct regulator_init_data	*regulator;
 	struct regulator_init_data	*regulator;

+ 8 - 0
include/linux/mfd/abx500.h

@@ -34,6 +34,13 @@
 #define AB5500_2_0	0x21
 #define AB5500_2_0	0x21
 #define AB5500_2_1	0x22
 #define AB5500_2_1	0x22
 
 
+/* AB8500 CIDs*/
+#define AB8500_CUTEARLY	0x00
+#define AB8500_CUT1P0	0x10
+#define AB8500_CUT1P1	0x11
+#define AB8500_CUT2P0	0x20
+#define AB8500_CUT3P0	0x30
+
 /*
 /*
  * AB3100, EVENTA1, A2 and A3 event register flags
  * AB3100, EVENTA1, A2 and A3 event register flags
  * these are catenated into a single 32-bit flag in the code
  * these are catenated into a single 32-bit flag in the code
@@ -186,6 +193,7 @@ struct abx500_init_settings {
 struct ab3550_platform_data {
 struct ab3550_platform_data {
 	struct {unsigned int base; unsigned int count; } irq;
 	struct {unsigned int base; unsigned int count; } irq;
 	void *dev_data[AB3550_NUM_DEVICES];
 	void *dev_data[AB3550_NUM_DEVICES];
+	size_t dev_data_sz[AB3550_NUM_DEVICES];
 	struct abx500_init_settings *init_settings;
 	struct abx500_init_settings *init_settings;
 	unsigned int init_settings_sz;
 	unsigned int init_settings_sz;
 };
 };

+ 20 - 3
include/linux/mfd/asic3.h

@@ -16,6 +16,13 @@
 
 
 #include <linux/types.h>
 #include <linux/types.h>
 
 
+struct led_classdev;
+struct asic3_led {
+	const char	*name;
+	const char	*default_trigger;
+	struct led_classdev *cdev;
+};
+
 struct asic3_platform_data {
 struct asic3_platform_data {
 	u16 *gpio_config;
 	u16 *gpio_config;
 	unsigned int gpio_config_num;
 	unsigned int gpio_config_num;
@@ -23,6 +30,8 @@ struct asic3_platform_data {
 	unsigned int irq_base;
 	unsigned int irq_base;
 
 
 	unsigned int gpio_base;
 	unsigned int gpio_base;
+
+	struct asic3_led *leds;
 };
 };
 
 
 #define ASIC3_NUM_GPIO_BANKS	4
 #define ASIC3_NUM_GPIO_BANKS	4
@@ -111,9 +120,9 @@ struct asic3_platform_data {
 #define ASIC3_GPIOA11_PWM0		ASIC3_CONFIG_GPIO(11, 1, 1, 0)
 #define ASIC3_GPIOA11_PWM0		ASIC3_CONFIG_GPIO(11, 1, 1, 0)
 #define ASIC3_GPIOA12_PWM1		ASIC3_CONFIG_GPIO(12, 1, 1, 0)
 #define ASIC3_GPIOA12_PWM1		ASIC3_CONFIG_GPIO(12, 1, 1, 0)
 #define ASIC3_GPIOA15_CONTROL_CX	ASIC3_CONFIG_GPIO(15, 1, 1, 0)
 #define ASIC3_GPIOA15_CONTROL_CX	ASIC3_CONFIG_GPIO(15, 1, 1, 0)
-#define ASIC3_GPIOC0_LED0		ASIC3_CONFIG_GPIO(32, 1, 1, 0)
-#define ASIC3_GPIOC1_LED1		ASIC3_CONFIG_GPIO(33, 1, 1, 0)
-#define ASIC3_GPIOC2_LED2		ASIC3_CONFIG_GPIO(34, 1, 1, 0)
+#define ASIC3_GPIOC0_LED0		ASIC3_CONFIG_GPIO(32, 1, 0, 0)
+#define ASIC3_GPIOC1_LED1		ASIC3_CONFIG_GPIO(33, 1, 0, 0)
+#define ASIC3_GPIOC2_LED2		ASIC3_CONFIG_GPIO(34, 1, 0, 0)
 #define ASIC3_GPIOC3_SPI_RXD		ASIC3_CONFIG_GPIO(35, 1, 0, 0)
 #define ASIC3_GPIOC3_SPI_RXD		ASIC3_CONFIG_GPIO(35, 1, 0, 0)
 #define ASIC3_GPIOC4_CF_nCD		ASIC3_CONFIG_GPIO(36, 1, 0, 0)
 #define ASIC3_GPIOC4_CF_nCD		ASIC3_CONFIG_GPIO(36, 1, 0, 0)
 #define ASIC3_GPIOC4_SPI_TXD		ASIC3_CONFIG_GPIO(36, 1, 1, 0)
 #define ASIC3_GPIOC4_SPI_TXD		ASIC3_CONFIG_GPIO(36, 1, 1, 0)
@@ -152,6 +161,7 @@ struct asic3_platform_data {
 #define PWM_TIMEBASE_VALUE(x)    ((x)&0xf)   /* Low 4 bits sets time base */
 #define PWM_TIMEBASE_VALUE(x)    ((x)&0xf)   /* Low 4 bits sets time base */
 #define PWM_TIMEBASE_ENABLE     (1 << 4)   /* Enable clock */
 #define PWM_TIMEBASE_ENABLE     (1 << 4)   /* Enable clock */
 
 
+#define ASIC3_NUM_LEDS                  3
 #define ASIC3_LED_0_Base                0x0700
 #define ASIC3_LED_0_Base                0x0700
 #define ASIC3_LED_1_Base                0x0800
 #define ASIC3_LED_1_Base                0x0800
 #define ASIC3_LED_2_Base 		      0x0900
 #define ASIC3_LED_2_Base 		      0x0900
@@ -287,10 +297,17 @@ struct asic3_platform_data {
  *
  *
  *****************************************************************************/
  *****************************************************************************/
 #define ASIC3_SD_CONFIG_BASE	0x0400 /* Assumes 32 bit addressing */
 #define ASIC3_SD_CONFIG_BASE	0x0400 /* Assumes 32 bit addressing */
+#define ASIC3_SD_CONFIG_SIZE	0x0200 /* Assumes 32 bit addressing */
 #define ASIC3_SD_CTRL_BASE	0x1000
 #define ASIC3_SD_CTRL_BASE	0x1000
 #define ASIC3_SDIO_CTRL_BASE	0x1200
 #define ASIC3_SDIO_CTRL_BASE	0x1200
 
 
 #define ASIC3_MAP_SIZE_32BIT	0x2000
 #define ASIC3_MAP_SIZE_32BIT	0x2000
 #define ASIC3_MAP_SIZE_16BIT	0x1000
 #define ASIC3_MAP_SIZE_16BIT	0x1000
 
 
+/* Functions needed by leds-asic3 */
+
+struct asic3;
+extern void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 val);
+extern u32 asic3_read_register(struct asic3 *asic, unsigned int reg);
+
 #endif /* __ASIC3_H__ */
 #endif /* __ASIC3_H__ */

+ 3 - 20
include/linux/mfd/core.h

@@ -33,8 +33,9 @@ struct mfd_cell {
 	int			(*suspend)(struct platform_device *dev);
 	int			(*suspend)(struct platform_device *dev);
 	int			(*resume)(struct platform_device *dev);
 	int			(*resume)(struct platform_device *dev);
 
 
-	/* mfd_data can be used to pass data to client drivers */
-	void			*mfd_data;
+	/* platform data passed to the sub devices drivers */
+	void			*platform_data;
+	size_t			pdata_size;
 
 
 	/*
 	/*
 	 * These resources can be specified relative to the parent device.
 	 * These resources can be specified relative to the parent device.
@@ -89,24 +90,6 @@ static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev)
 	return pdev->mfd_cell;
 	return pdev->mfd_cell;
 }
 }
 
 
-/*
- * Given a platform device that's been created by mfd_add_devices(), fetch
- * the .mfd_data entry from the mfd_cell that created it.
- * Otherwise just return the platform_data pointer.
- * This maintains compatibility with platform drivers whose devices aren't
- * created by the mfd layer, and expect platform_data to contain what would've
- * otherwise been in mfd_data.
- */
-static inline void *mfd_get_data(struct platform_device *pdev)
-{
-	const struct mfd_cell *cell = mfd_get_cell(pdev);
-
-	if (cell)
-		return cell->mfd_data;
-	else
-		return pdev->dev.platform_data;
-}
-
 extern int mfd_add_devices(struct device *parent, int id,
 extern int mfd_add_devices(struct device *parent, int id,
 			   struct mfd_cell *cells, int n_devs,
 			   struct mfd_cell *cells, int n_devs,
 			   struct resource *mem_base,
 			   struct resource *mem_base,

+ 81 - 0
include/linux/mfd/pm8xxx/core.h

@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+/*
+ * Qualcomm PMIC 8xxx driver header file
+ *
+ */
+
+#ifndef __MFD_PM8XXX_CORE_H
+#define __MFD_PM8XXX_CORE_H
+
+#include <linux/mfd/core.h>
+
+struct pm8xxx_drvdata {
+	int	(*pmic_readb) (const struct device *dev, u16 addr, u8 *val);
+	int	(*pmic_writeb) (const struct device *dev, u16 addr, u8 val);
+	int	(*pmic_read_buf) (const struct device *dev, u16 addr, u8 *buf,
+									int n);
+	int	(*pmic_write_buf) (const struct device *dev, u16 addr, u8 *buf,
+									int n);
+	int	(*pmic_read_irq_stat) (const struct device *dev, int irq);
+	void	*pm_chip_data;
+};
+
+static inline int pm8xxx_readb(const struct device *dev, u16 addr, u8 *val)
+{
+	struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+	if (!dd)
+		return -EINVAL;
+	return dd->pmic_readb(dev, addr, val);
+}
+
+static inline int pm8xxx_writeb(const struct device *dev, u16 addr, u8 val)
+{
+	struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+	if (!dd)
+		return -EINVAL;
+	return dd->pmic_writeb(dev, addr, val);
+}
+
+static inline int pm8xxx_read_buf(const struct device *dev, u16 addr, u8 *buf,
+									int n)
+{
+	struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+	if (!dd)
+		return -EINVAL;
+	return dd->pmic_read_buf(dev, addr, buf, n);
+}
+
+static inline int pm8xxx_write_buf(const struct device *dev, u16 addr, u8 *buf,
+									int n)
+{
+	struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+	if (!dd)
+		return -EINVAL;
+	return dd->pmic_write_buf(dev, addr, buf, n);
+}
+
+static inline int pm8xxx_read_irq_stat(const struct device *dev, int irq)
+{
+	struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+	if (!dd)
+		return -EINVAL;
+	return dd->pmic_read_irq_stat(dev, irq);
+}
+
+#endif

+ 59 - 0
include/linux/mfd/pm8xxx/irq.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+/*
+ * Qualcomm PMIC irq 8xxx driver header file
+ *
+ */
+
+#ifndef __MFD_PM8XXX_IRQ_H
+#define __MFD_PM8XXX_IRQ_H
+
+#include <linux/errno.h>
+#include <linux/err.h>
+
+struct pm8xxx_irq_core_data {
+	u32		rev;
+	int		nirqs;
+};
+
+struct pm8xxx_irq_platform_data {
+	int				irq_base;
+	struct pm8xxx_irq_core_data	irq_cdata;
+	int				devirq;
+	int				irq_trigger_flag;
+};
+
+struct pm_irq_chip;
+
+#ifdef CONFIG_MFD_PM8XXX_IRQ
+int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq);
+struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
+				const struct pm8xxx_irq_platform_data *pdata);
+int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip);
+#else
+static inline int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+	return -ENXIO;
+}
+static inline struct pm_irq_chip * __devinit pm8xxx_irq_init(
+				const struct device *dev,
+				const struct pm8xxx_irq_platform_data *pdata)
+{
+	return ERR_PTR(-ENXIO);
+}
+static inline int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+{
+	return -ENXIO;
+}
+#endif /* CONFIG_MFD_PM8XXX_IRQ */
+#endif /* __MFD_PM8XXX_IRQ_H */

+ 31 - 0
include/linux/mfd/pm8xxx/pm8921.h

@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+/*
+ * Qualcomm PMIC 8921 driver header file
+ *
+ */
+
+#ifndef __MFD_PM8921_H
+#define __MFD_PM8921_H
+
+#include <linux/device.h>
+#include <linux/mfd/pm8xxx/irq.h>
+
+#define PM8921_NR_IRQS		256
+
+struct pm8921_platform_data {
+	int					irq_base;
+	struct pm8xxx_irq_platform_data		*irq_pdata;
+};
+
+#endif

+ 1 - 1
include/linux/mfd/twl4030-codec.h

@@ -1,7 +1,7 @@
 /*
 /*
  * MFD driver for twl4030 codec submodule
  * MFD driver for twl4030 codec submodule
  *
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * Copyright:   (C) 2009 Nokia Corporation
  * Copyright:   (C) 2009 Nokia Corporation
  *
  *

+ 0 - 26
include/linux/mfd/wm831x/core.h

@@ -301,30 +301,4 @@ int wm831x_device_suspend(struct wm831x *wm831x);
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 void wm831x_irq_exit(struct wm831x *wm831x);
 void wm831x_irq_exit(struct wm831x *wm831x);
 
 
-static inline int __must_check wm831x_request_irq(struct wm831x *wm831x,
-						  unsigned int irq,
-						  irq_handler_t handler,
-						  unsigned long flags,
-						  const char *name,
-						  void *dev)
-{
-	return request_threaded_irq(irq, NULL, handler, flags, name, dev);
-}
-
-static inline void wm831x_free_irq(struct wm831x *wm831x,
-				   unsigned int irq, void *dev)
-{
-	free_irq(irq, dev);
-}
-
-static inline void wm831x_disable_irq(struct wm831x *wm831x, int irq)
-{
-	disable_irq(irq);
-}
-
-static inline void wm831x_enable_irq(struct wm831x *wm831x, int irq)
-{
-	enable_irq(irq);
-}
-
 #endif
 #endif

+ 4 - 0
include/linux/mfd/wm831x/pdata.h

@@ -105,6 +105,9 @@ struct wm831x_watchdog_pdata {
 #define WM831X_MAX_LDO    11
 #define WM831X_MAX_LDO    11
 #define WM831X_MAX_ISINK  2
 #define WM831X_MAX_ISINK  2
 
 
+#define WM831X_GPIO_CONFIGURE 0x10000
+#define WM831X_GPIO_NUM 16
+
 struct wm831x_pdata {
 struct wm831x_pdata {
 	/** Used to distinguish multiple WM831x chips */
 	/** Used to distinguish multiple WM831x chips */
 	int wm831x_num;
 	int wm831x_num;
@@ -119,6 +122,7 @@ struct wm831x_pdata {
 
 
 	int irq_base;
 	int irq_base;
 	int gpio_base;
 	int gpio_base;
+	int gpio_defaults[WM831X_GPIO_NUM];
 	struct wm831x_backlight_pdata *backlight;
 	struct wm831x_backlight_pdata *backlight;
 	struct wm831x_backup_pdata *backup;
 	struct wm831x_backup_pdata *backup;
 	struct wm831x_battery_pdata *battery;
 	struct wm831x_battery_pdata *battery;

+ 1 - 2
sound/soc/codecs/cq93vc.c

@@ -153,8 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec)
 
 
 static int cq93vc_probe(struct snd_soc_codec *codec)
 static int cq93vc_probe(struct snd_soc_codec *codec)
 {
 {
-	struct davinci_vc *davinci_vc =
-			mfd_get_data(to_platform_device(codec->dev));
+	struct davinci_vc *davinci_vc = codec->dev->platform_data;
 
 
 	davinci_vc->cq93vc.codec = codec;
 	davinci_vc->cq93vc.codec = codec;
 	codec->control_data = davinci_vc;
 	codec->control_data = davinci_vc;

+ 2 - 4
sound/soc/codecs/twl4030.c

@@ -26,7 +26,6 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/core.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/core.h>
@@ -733,8 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
 
 
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
 {
-	struct twl4030_codec_audio_data *pdata =
-			mfd_get_data(to_platform_device(codec->dev));
+	struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
 	unsigned char hs_gain, hs_pop;
 	unsigned char hs_gain, hs_pop;
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 	/* Base values for ramp delay calculation: 2^19 - 2^26 */
 	/* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -2299,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 
 
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
 {
-	struct twl4030_codec_audio_data *pdata = mfd_get_data(pdev);
+	struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
 
 
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(&pdev->dev, "platform_data is missing\n");
 		dev_err(&pdev->dev, "platform_data is missing\n");

+ 1 - 2
sound/soc/codecs/wl1273.c

@@ -441,8 +441,7 @@ EXPORT_SYMBOL_GPL(wl1273_get_format);
 
 
 static int wl1273_probe(struct snd_soc_codec *codec)
 static int wl1273_probe(struct snd_soc_codec *codec)
 {
 {
-	struct wl1273_core **core =
-			mfd_get_data(to_platform_device(codec->dev));
+	struct wl1273_core **core = codec->dev->platform_data;
 	struct wl1273_priv *wl1273;
 	struct wl1273_priv *wl1273;
 	int r;
 	int r;
 
 

+ 1 - 1
sound/soc/codecs/wm8400.c

@@ -1378,7 +1378,7 @@ static void wm8400_probe_deferred(struct work_struct *work)
 
 
 static int wm8400_codec_probe(struct snd_soc_codec *codec)
 static int wm8400_codec_probe(struct snd_soc_codec *codec)
 {
 {
-	struct wm8400 *wm8400 = mfd_get_data(to_platform_device(codec->dev));
+	struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
 	struct wm8400_priv *priv;
 	struct wm8400_priv *priv;
 	int ret;
 	int ret;
 	u16 reg;
 	u16 reg;

+ 1 - 1
sound/soc/davinci/davinci-vcif.c

@@ -205,7 +205,7 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
 
 
 static int davinci_vcif_probe(struct platform_device *pdev)
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
 {
-	struct davinci_vc *davinci_vc = mfd_get_data(pdev);
+	struct davinci_vc *davinci_vc = pdev->dev.platform_data;
 	struct davinci_vcif_dev *davinci_vcif_dev;
 	struct davinci_vcif_dev *davinci_vcif_dev;
 	int ret;
 	int ret;