Просмотр исходного кода

Merge tag 'mfd_3.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6

Pull MFD changes from Samuel Ortiz:
 - 4 new drivers: Freescale i.MX on-chip Anatop, Ricoh's RC5T583 and
   TI's TPS65090 and TPS65217.
 - New variants support (8420, 8520 ab9540), cleanups and bug fixes for
   the abx500 and db8500 ST-E chipsets.
 - Some minor fixes and update for the wm8994 from Mark.
 - The beginning of a long term TWL cleanup effort coming from the TI
   folks.
 - Various fixes and cleanups for the s5m, TPS659xx, pm860x, and MAX8997
   drivers.

Fix up trivial conflicts due to duplicate patches and header file
cleanups (<linux/device.h> removal etc).

* tag 'mfd_3.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (97 commits)
  gpio/twl: Add DT support to gpio-twl4030 driver
  gpio/twl: Allocate irq_desc dynamically for SPARSE_IRQ support
  mfd: Detach twl6040 from the pmic mfd driver
  mfd: Replace twl-* pr_ macros by the dev_ equivalent and do various cleanups
  mfd: Micro-optimization on twl4030 IRQ handler
  mfd: Make twl4030 SIH SPARSE_IRQ capable
  mfd: Move twl-core IRQ allocation into twl[4030|6030]-irq files
  mfd: Remove references already defineid in header file from twl-core
  mfd: Remove unneeded header from twl-core
  mfd: Make twl-core not depend on pdata->irq_base/end
  ARM: OMAP2+: board-omap4-*: Do not use anymore TWL6030_IRQ_BASE in board files
  mfd: Return twl6030_mmc_card_detect IRQ for board setup
  Revert "mfd: Add platform data for MAX8997 haptic driver"
  mfd: Add support for TPS65090
  mfd: Add some da9052-i2c section annotations
  mfd: Build rtc5t583 only if I2C config is selected to y.
  mfd: Add anatop mfd driver
  mfd: Fix compilation error in tps65910.h
  mfd: Add 8420 variant to db8500-prcmu
  mfd: Add 8520 PRCMU variant to db8500-prcmu
  ...
Linus Torvalds 13 лет назад
Родитель
Сommit
30304e5a79
69 измененных файлов с 5211 добавлено и 1126 удалено
  1. 23 0
      Documentation/devicetree/bindings/gpio/gpio-twl4030.txt
  2. 7 6
      arch/arm/mach-omap2/board-4430sdp.c
  3. 8 7
      arch/arm/mach-omap2/board-omap4panda.c
  4. 12 2
      arch/arm/mach-s3c64xx/mach-crag6410-module.c
  5. 1 1
      arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
  6. 5 8
      drivers/cpufreq/db8500-cpufreq.c
  7. 25 16
      drivers/gpio/gpio-stmpe.c
  8. 67 44
      drivers/gpio/gpio-twl4030.c
  9. 1 1
      drivers/hwmon/mc13783-adc.c
  10. 26 0
      drivers/input/misc/88pm860x_onkey.c
  11. 10 1
      drivers/input/touchscreen/mc13783_ts.c
  12. 23 0
      drivers/leds/leds-88pm860x.c
  13. 106 4
      drivers/mfd/88pm860x-core.c
  14. 25 0
      drivers/mfd/88pm860x-i2c.c
  15. 52 2
      drivers/mfd/Kconfig
  16. 4 0
      drivers/mfd/Makefile
  17. 285 90
      drivers/mfd/ab8500-core.c
  18. 27 3
      drivers/mfd/ab8500-i2c.c
  19. 137 0
      drivers/mfd/anatop-mfd.c
  20. 6 0
      drivers/mfd/asic3.c
  21. 0 3
      drivers/mfd/da9052-core.c
  22. 7 4
      drivers/mfd/da9052-i2c.c
  23. 6 3
      drivers/mfd/da9052-spi.c
  24. 886 334
      drivers/mfd/db8500-prcmu.c
  25. 88 42
      drivers/mfd/dbx500-prcmu-regs.h
  26. 9 2
      drivers/mfd/mc13xxx-core.c
  27. 1 1
      drivers/mfd/mfd-core.c
  28. 3 4
      drivers/mfd/omap-usb-host.c
  29. 1 7
      drivers/mfd/pcf50633-core.c
  30. 1 26
      drivers/mfd/pcf50633-gpio.c
  31. 1 6
      drivers/mfd/pcf50633-irq.c
  32. 408 0
      drivers/mfd/rc5t583-irq.c
  33. 386 0
      drivers/mfd/rc5t583.c
  34. 45 13
      drivers/mfd/s5m-core.c
  35. 11 3
      drivers/mfd/s5m-irq.c
  36. 1 9
      drivers/mfd/sm501.c
  37. 96 38
      drivers/mfd/stmpe.c
  38. 387 0
      drivers/mfd/tps65090.c
  39. 242 0
      drivers/mfd/tps65217.c
  40. 11 0
      drivers/mfd/tps65910-irq.c
  41. 46 77
      drivers/mfd/tps65910.c
  42. 69 84
      drivers/mfd/twl-core.c
  43. 2 2
      drivers/mfd/twl-core.h
  44. 60 47
      drivers/mfd/twl4030-irq.c
  45. 54 32
      drivers/mfd/twl6030-irq.c
  46. 1 1
      drivers/mfd/wm831x-spi.c
  47. 1 2
      drivers/mfd/wm8400-core.c
  48. 1 1
      drivers/mfd/wm8994-core.c
  49. 2 18
      drivers/mfd/wm8994-regmap.c
  50. 27 0
      drivers/rtc/rtc-88pm860x.c
  51. 28 21
      drivers/video/backlight/88pm860x_bl.c
  52. 1 1
      include/linux/i2c/twl.h
  53. 23 0
      include/linux/mfd/88pm860x.h
  54. 0 7
      include/linux/mfd/abx500.h
  55. 3 1
      include/linux/mfd/abx500/ab8500-gpio.h
  56. 43 0
      include/linux/mfd/abx500/ab8500-sysctrl.h
  57. 166 42
      include/linux/mfd/abx500/ab8500.h
  58. 40 0
      include/linux/mfd/anatop.h
  59. 0 2
      include/linux/mfd/da9052/da9052.h
  60. 102 81
      include/linux/mfd/db8500-prcmu.h
  61. 390 24
      include/linux/mfd/dbx500-prcmu.h
  62. 15 1
      include/linux/mfd/mc13xxx.h
  63. 295 0
      include/linux/mfd/rc5t583.h
  64. 1 0
      include/linux/mfd/stmpe.h
  65. 46 0
      include/linux/mfd/tps65090.h
  66. 283 0
      include/linux/mfd/tps65217.h
  67. 3 0
      include/linux/mfd/tps65910.h
  68. 0 1
      include/linux/mfd/wm8994/pdata.h
  69. 69 1
      include/linux/regulator/ab8500.h

+ 23 - 0
Documentation/devicetree/bindings/gpio/gpio-twl4030.txt

@@ -0,0 +1,23 @@
+twl4030 GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,twl4030-gpio" for twl4030 GPIO controller
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+  The first cell is the GPIO number.
+  The second cell is not used.
+
+Example:
+
+twl_gpio: gpio {
+    compatible = "ti,twl4030-gpio";
+    #gpio-cells = <2>;
+    gpio-controller;
+    #interrupt-cells = <2>;
+    interrupt-controller;
+};

+ 7 - 6
arch/arm/mach-omap2/board-4430sdp.c

@@ -490,21 +490,22 @@ static struct platform_device omap_vwlan_device = {
 
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
 {
-	int ret = 0;
+	int irq = 0;
 	struct platform_device *pdev = container_of(dev,
 	struct platform_device *pdev = container_of(dev,
 				struct platform_device, dev);
 				struct platform_device, dev);
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
 
 
 	/* Setting MMC1 Card detect Irq */
 	/* Setting MMC1 Card detect Irq */
 	if (pdev->id == 0) {
 	if (pdev->id == 0) {
-		ret = twl6030_mmc_card_detect_config();
-		if (ret)
+		irq = twl6030_mmc_card_detect_config();
+		if (irq < 0) {
 			pr_err("Failed configuring MMC1 card detect\n");
 			pr_err("Failed configuring MMC1 card detect\n");
-		pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
-						MMCDETECT_INTR_OFFSET;
+			return irq;
+		}
+		pdata->slots[0].card_detect_irq = irq;
 		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
 		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
 	}
 	}
-	return ret;
+	return 0;
 }
 }
 
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)

+ 8 - 7
arch/arm/mach-omap2/board-omap4panda.c

@@ -238,7 +238,7 @@ struct wl12xx_platform_data omap_panda_wlan_data  __initdata = {
 
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
 {
-	int ret = 0;
+	int irq = 0;
 	struct platform_device *pdev = container_of(dev,
 	struct platform_device *pdev = container_of(dev,
 				struct platform_device, dev);
 				struct platform_device, dev);
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
@@ -249,14 +249,15 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 	}
 	}
 	/* Setting MMC1 Card detect Irq */
 	/* Setting MMC1 Card detect Irq */
 	if (pdev->id == 0) {
 	if (pdev->id == 0) {
-		ret = twl6030_mmc_card_detect_config();
-		 if (ret)
+		irq = twl6030_mmc_card_detect_config();
+		if (irq < 0) {
 			dev_err(dev, "%s: Error card detect config(%d)\n",
 			dev_err(dev, "%s: Error card detect config(%d)\n",
-				__func__, ret);
-		 else
-			pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+				__func__, irq);
+			return irq;
+		}
+		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
 	}
 	}
-	return ret;
+	return 0;
 }
 }
 
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)

+ 12 - 2
arch/arm/mach-s3c64xx/mach-crag6410-module.c

@@ -17,6 +17,8 @@
 #include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm8994/pdata.h>
 #include <linux/mfd/wm8994/pdata.h>
 
 
+#include <linux/regulator/machine.h>
+
 #include <sound/wm5100.h>
 #include <sound/wm5100.h>
 #include <sound/wm8996.h>
 #include <sound/wm8996.h>
 #include <sound/wm8962.h>
 #include <sound/wm8962.h>
@@ -153,6 +155,14 @@ static const struct i2c_board_info wm1259_devs[] = {
 	},
 	},
 };
 };
 
 
+static struct regulator_init_data wm8994_ldo1 = {
+	.supply_regulator = "WALLVDD",
+};
+
+static struct regulator_init_data wm8994_ldo2 = {
+	.supply_regulator = "WALLVDD",
+};
+
 static struct wm8994_pdata wm8994_pdata = {
 static struct wm8994_pdata wm8994_pdata = {
 	.gpio_base = CODEC_GPIO_BASE,
 	.gpio_base = CODEC_GPIO_BASE,
 	.gpio_defaults = {
 	.gpio_defaults = {
@@ -160,8 +170,8 @@ static struct wm8994_pdata wm8994_pdata = {
 	},
 	},
 	.irq_base = CODEC_IRQ_BASE,
 	.irq_base = CODEC_IRQ_BASE,
 	.ldo = {
 	.ldo = {
-		{ .supply = "WALLVDD" },
-		{ .supply = "WALLVDD" },
+		 { .init_data = &wm8994_ldo1, },
+		 { .init_data = &wm8994_ldo2, },
 	},
 	},
 };
 };
 
 

+ 1 - 1
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h

@@ -13,7 +13,7 @@
 
 
 #define MOP500_AB8500_IRQ_BASE		IRQ_BOARD_START
 #define MOP500_AB8500_IRQ_BASE		IRQ_BOARD_START
 #define MOP500_AB8500_IRQ_END		(MOP500_AB8500_IRQ_BASE \
 #define MOP500_AB8500_IRQ_END		(MOP500_AB8500_IRQ_BASE \
-					 + AB8500_NR_IRQS)
+					 + AB8500_MAX_NR_IRQS)
 
 
 /* TC35892 */
 /* TC35892 */
 #define TC35892_NR_INTERNAL_IRQS	8
 #define TC35892_NR_INTERNAL_IRQS	8

+ 5 - 8
drivers/cpufreq/db8500-cpufreq.c

@@ -22,11 +22,11 @@ static struct cpufreq_frequency_table freq_table[] = {
 	},
 	},
 	[1] = {
 	[1] = {
 		.index = 1,
 		.index = 1,
-		.frequency = 300000,
+		.frequency = 400000,
 	},
 	},
 	[2] = {
 	[2] = {
 		.index = 2,
 		.index = 2,
-		.frequency = 600000,
+		.frequency = 800000,
 	},
 	},
 	[3] = {
 	[3] = {
 		/* Used for MAX_OPP, if available */
 		/* Used for MAX_OPP, if available */
@@ -113,12 +113,9 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
 
 
 	BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
 	BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
 
 
-	if (!prcmu_is_u8400()) {
-		freq_table[1].frequency = 400000;
-		freq_table[2].frequency = 800000;
-		if (prcmu_has_arm_maxopp())
-			freq_table[3].frequency = 1000000;
-	}
+	if (prcmu_has_arm_maxopp())
+		freq_table[3].frequency = 1000000;
+
 	pr_info("db8500-cpufreq : Available frequencies:\n");
 	pr_info("db8500-cpufreq : Available frequencies:\n");
 	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
 	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
 		pr_info("  %d Mhz\n", freq_table[i].frequency/1000);
 		pr_info("  %d Mhz\n", freq_table[i].frequency/1000);

+ 25 - 16
drivers/gpio/gpio-stmpe.c

@@ -307,13 +307,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
 	struct stmpe_gpio_platform_data *pdata;
 	struct stmpe_gpio_platform_data *pdata;
 	struct stmpe_gpio *stmpe_gpio;
 	struct stmpe_gpio *stmpe_gpio;
 	int ret;
 	int ret;
-	int irq;
+	int irq = 0;
 
 
 	pdata = stmpe->pdata->gpio;
 	pdata = stmpe->pdata->gpio;
 
 
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
 
 
 	stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
 	stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
 	if (!stmpe_gpio)
 	if (!stmpe_gpio)
@@ -330,21 +328,28 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
 	stmpe_gpio->chip.dev = &pdev->dev;
 	stmpe_gpio->chip.dev = &pdev->dev;
 	stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
 	stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
 
 
-	stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+	if (irq >= 0)
+		stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+	else
+		dev_info(&pdev->dev,
+			"device configured in no-irq mode; "
+			"irqs are not available\n");
 
 
 	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
 	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
 	if (ret)
 	if (ret)
 		goto out_free;
 		goto out_free;
 
 
-	ret = stmpe_gpio_irq_init(stmpe_gpio);
-	if (ret)
-		goto out_disable;
+	if (irq >= 0) {
+		ret = stmpe_gpio_irq_init(stmpe_gpio);
+		if (ret)
+			goto out_disable;
 
 
-	ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
-				   "stmpe-gpio", stmpe_gpio);
-	if (ret) {
-		dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
-		goto out_removeirq;
+		ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
+				IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
+		if (ret) {
+			dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+			goto out_removeirq;
+		}
 	}
 	}
 
 
 	ret = gpiochip_add(&stmpe_gpio->chip);
 	ret = gpiochip_add(&stmpe_gpio->chip);
@@ -361,9 +366,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 
 
 out_freeirq:
 out_freeirq:
-	free_irq(irq, stmpe_gpio);
+	if (irq >= 0)
+		free_irq(irq, stmpe_gpio);
 out_removeirq:
 out_removeirq:
-	stmpe_gpio_irq_remove(stmpe_gpio);
+	if (irq >= 0)
+		stmpe_gpio_irq_remove(stmpe_gpio);
 out_disable:
 out_disable:
 	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 out_free:
 out_free:
@@ -391,8 +398,10 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
 
 
 	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 
 
-	free_irq(irq, stmpe_gpio);
-	stmpe_gpio_irq_remove(stmpe_gpio);
+	if (irq >= 0) {
+		free_irq(irq, stmpe_gpio);
+		stmpe_gpio_irq_remove(stmpe_gpio);
+	}
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);
 	kfree(stmpe_gpio);
 	kfree(stmpe_gpio);
 
 

+ 67 - 44
drivers/gpio/gpio-twl4030.c

@@ -32,6 +32,8 @@
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 
 
@@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
 		 * and vMMC2 power supplies based on card presence.
 		 * and vMMC2 power supplies based on card presence.
 		 */
 		 */
 		pdata = chip->dev->platform_data;
 		pdata = chip->dev->platform_data;
-		value |= pdata->mmc_cd & 0x03;
+		if (pdata)
+			value |= pdata->mmc_cd & 0x03;
 
 
 		status = gpio_twl4030_write(REG_GPIO_CTRL, value);
 		status = gpio_twl4030_write(REG_GPIO_CTRL, value);
 	}
 	}
@@ -395,59 +398,70 @@ static int gpio_twl4030_remove(struct platform_device *pdev);
 static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
 static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
 {
 {
 	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
 	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
-	int ret;
+	struct device_node *node = pdev->dev.of_node;
+	int ret, irq_base;
 
 
 	/* maybe setup IRQs */
 	/* maybe setup IRQs */
-	if (pdata->irq_base) {
-		if (is_module()) {
-			dev_err(&pdev->dev,
-				"can't dispatch IRQs from modules\n");
-			goto no_irqs;
-		}
-		ret = twl4030_sih_setup(TWL4030_MODULE_GPIO);
-		if (ret < 0)
-			return ret;
-		WARN_ON(ret != pdata->irq_base);
-		twl4030_gpio_irq_base = ret;
+	if (is_module()) {
+		dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
+		goto no_irqs;
+	}
+
+	irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0);
+	if (irq_base < 0) {
+		dev_err(&pdev->dev, "Failed to alloc irq_descs\n");
+		return irq_base;
 	}
 	}
 
 
+	irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0,
+			      &irq_domain_simple_ops, NULL);
+
+	ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base);
+	if (ret < 0)
+		return ret;
+
+	twl4030_gpio_irq_base = irq_base;
+
 no_irqs:
 no_irqs:
-	/*
-	 * NOTE:  boards may waste power if they don't set pullups
-	 * and pulldowns correctly ... default for non-ULPI pins is
-	 * pulldown, and some other pins may have external pullups
-	 * or pulldowns.  Careful!
-	 */
-	ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
-	if (ret)
-		dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
-				pdata->pullups, pdata->pulldowns,
-				ret);
-
-	ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
-	if (ret)
-		dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
-				pdata->debounce, pdata->mmc_cd,
-				ret);
-
-	twl_gpiochip.base = pdata->gpio_base;
+	twl_gpiochip.base = -1;
 	twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
 	twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
 	twl_gpiochip.dev = &pdev->dev;
 	twl_gpiochip.dev = &pdev->dev;
 
 
-	/* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
-	 * is (still) clear if use_leds is set.
-	 */
-	if (pdata->use_leds)
-		twl_gpiochip.ngpio += 2;
+	if (pdata) {
+		twl_gpiochip.base = pdata->gpio_base;
+
+		/*
+		 * NOTE:  boards may waste power if they don't set pullups
+		 * and pulldowns correctly ... default for non-ULPI pins is
+		 * pulldown, and some other pins may have external pullups
+		 * or pulldowns.  Careful!
+		 */
+		ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+		if (ret)
+			dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+					pdata->pullups, pdata->pulldowns,
+					ret);
+
+		ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
+		if (ret)
+			dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
+					pdata->debounce, pdata->mmc_cd,
+					ret);
+
+		/*
+		 * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
+		 * is (still) clear if use_leds is set.
+		 */
+		if (pdata->use_leds)
+			twl_gpiochip.ngpio += 2;
+	}
 
 
 	ret = gpiochip_add(&twl_gpiochip);
 	ret = gpiochip_add(&twl_gpiochip);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&pdev->dev,
-				"could not register gpiochip, %d\n",
-				ret);
+		dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
 		twl_gpiochip.ngpio = 0;
 		twl_gpiochip.ngpio = 0;
 		gpio_twl4030_remove(pdev);
 		gpio_twl4030_remove(pdev);
-	} else if (pdata->setup) {
+	} else if (pdata && pdata->setup) {
 		int status;
 		int status;
 
 
 		status = pdata->setup(&pdev->dev,
 		status = pdata->setup(&pdev->dev,
@@ -465,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
 	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
 	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
 	int status;
 	int status;
 
 
-	if (pdata->teardown) {
+	if (pdata && pdata->teardown) {
 		status = pdata->teardown(&pdev->dev,
 		status = pdata->teardown(&pdev->dev,
 				pdata->gpio_base, TWL4030_GPIO_MAX);
 				pdata->gpio_base, TWL4030_GPIO_MAX);
 		if (status) {
 		if (status) {
@@ -486,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
 	return -EIO;
 	return -EIO;
 }
 }
 
 
+static const struct of_device_id twl_gpio_match[] = {
+	{ .compatible = "ti,twl4030-gpio", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, twl_gpio_match);
+
 /* Note:  this hardware lives inside an I2C-based multi-function device. */
 /* Note:  this hardware lives inside an I2C-based multi-function device. */
 MODULE_ALIAS("platform:twl4030_gpio");
 MODULE_ALIAS("platform:twl4030_gpio");
 
 
 static struct platform_driver gpio_twl4030_driver = {
 static struct platform_driver gpio_twl4030_driver = {
-	.driver.name	= "twl4030_gpio",
-	.driver.owner	= THIS_MODULE,
+	.driver = {
+		.name	= "twl4030_gpio",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(twl_gpio_match),
+	},
 	.probe		= gpio_twl4030_probe,
 	.probe		= gpio_twl4030_probe,
 	.remove		= gpio_twl4030_remove,
 	.remove		= gpio_twl4030_remove,
 };
 };

+ 1 - 1
drivers/hwmon/mc13783-adc.c

@@ -59,7 +59,7 @@ static int mc13783_adc_read(struct device *dev,
 
 
 	ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
 	ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
 			MC13XXX_ADC_MODE_MULT_CHAN,
 			MC13XXX_ADC_MODE_MULT_CHAN,
-			channel, sample);
+			channel, 0, 0, sample);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 

+ 26 - 0
drivers/input/misc/88pm860x_onkey.c

@@ -105,6 +105,8 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	platform_set_drvdata(pdev, info);
 	platform_set_drvdata(pdev, info);
+	device_init_wakeup(&pdev->dev, 1);
+
 	return 0;
 	return 0;
 
 
 out_irq:
 out_irq:
@@ -129,10 +131,34 @@ static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_onkey_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
+	return 0;
+}
+static int pm860x_onkey_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+
 static struct platform_driver pm860x_onkey_driver = {
 static struct platform_driver pm860x_onkey_driver = {
 	.driver		= {
 	.driver		= {
 		.name	= "88pm860x-onkey",
 		.name	= "88pm860x-onkey",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
+		.pm	= &pm860x_onkey_pm_ops,
 	},
 	},
 	.probe		= pm860x_onkey_probe,
 	.probe		= pm860x_onkey_probe,
 	.remove		= __devexit_p(pm860x_onkey_remove),
 	.remove		= __devexit_p(pm860x_onkey_remove),

+ 10 - 1
drivers/input/touchscreen/mc13783_ts.c

@@ -39,6 +39,7 @@ struct mc13783_ts_priv {
 	struct delayed_work work;
 	struct delayed_work work;
 	struct workqueue_struct *workq;
 	struct workqueue_struct *workq;
 	unsigned int sample[4];
 	unsigned int sample[4];
+	struct mc13xxx_ts_platform_data *touch;
 };
 };
 
 
 static irqreturn_t mc13783_ts_handler(int irq, void *data)
 static irqreturn_t mc13783_ts_handler(int irq, void *data)
@@ -125,7 +126,9 @@ static void mc13783_ts_work(struct work_struct *work)
 	unsigned int channel = 12;
 	unsigned int channel = 12;
 
 
 	if (mc13xxx_adc_do_conversion(priv->mc13xxx,
 	if (mc13xxx_adc_do_conversion(priv->mc13xxx,
-				mode, channel, priv->sample) == 0)
+				mode, channel,
+				priv->touch->ato, priv->touch->atox,
+				priv->sample) == 0)
 		mc13783_ts_report_sample(priv);
 		mc13783_ts_report_sample(priv);
 }
 }
 
 
@@ -179,6 +182,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
 	INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
 	INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
 	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
 	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
 	priv->idev = idev;
 	priv->idev = idev;
+	priv->touch = dev_get_platdata(&pdev->dev);
+	if (!priv->touch) {
+		dev_err(&pdev->dev, "missing platform data\n");
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
 
 
 	/*
 	/*
 	 * We need separate workqueue because mc13783_adc_do_conversion
 	 * We need separate workqueue because mc13783_adc_do_conversion

+ 23 - 0
drivers/leds/leds-88pm860x.c

@@ -114,6 +114,27 @@ static inline int __blink_ctl_mask(int port)
 	return ret;
 	return ret;
 }
 }
 
 
+static int led_power_set(struct pm860x_chip *chip, int port, int on)
+{
+	int ret = -EINVAL;
+
+	switch (port) {
+	case PM8606_LED1_RED:
+	case PM8606_LED1_GREEN:
+	case PM8606_LED1_BLUE:
+		ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) :
+			pm8606_osc_disable(chip, RGB1_ENABLE);
+		break;
+	case PM8606_LED2_RED:
+	case PM8606_LED2_GREEN:
+	case PM8606_LED2_BLUE:
+		ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) :
+			pm8606_osc_disable(chip, RGB2_ENABLE);
+		break;
+	}
+	return ret;
+}
+
 static void pm860x_led_work(struct work_struct *work)
 static void pm860x_led_work(struct work_struct *work)
 {
 {
 
 
@@ -126,6 +147,7 @@ static void pm860x_led_work(struct work_struct *work)
 	chip = led->chip;
 	chip = led->chip;
 	mutex_lock(&led->lock);
 	mutex_lock(&led->lock);
 	if ((led->current_brightness == 0) && led->brightness) {
 	if ((led->current_brightness == 0) && led->brightness) {
+		led_power_set(chip, led->port, 1);
 		if (led->iset) {
 		if (led->iset) {
 			pm860x_set_bits(led->i2c, __led_off(led->port),
 			pm860x_set_bits(led->i2c, __led_off(led->port),
 					LED_CURRENT_MASK, led->iset);
 					LED_CURRENT_MASK, led->iset);
@@ -149,6 +171,7 @@ static void pm860x_led_work(struct work_struct *work)
 					LED_CURRENT_MASK, 0);
 					LED_CURRENT_MASK, 0);
 			mask = __blink_ctl_mask(led->port);
 			mask = __blink_ctl_mask(led->port);
 			pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
 			pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
+			led_power_set(chip, led->port, 0);
 		}
 		}
 	}
 	}
 	led->current_brightness = led->brightness;
 	led->current_brightness = led->brightness;

+ 106 - 4
drivers/mfd/88pm860x-core.c

@@ -503,6 +503,101 @@ static void device_irq_exit(struct pm860x_chip *chip)
 		free_irq(chip->core_irq, chip);
 		free_irq(chip->core_irq, chip);
 }
 }
 
 
+int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
+{
+	int ret = -EIO;
+	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+		chip->client : chip->companion;
+
+	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status);
+
+	mutex_lock(&chip->osc_lock);
+	/* Update voting status */
+	chip->osc_vote |= client;
+	/* If reference group is off - turn on*/
+	if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
+		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+		/* Enable Reference group Vsys */
+		if (pm860x_set_bits(i2c, PM8606_VSYS,
+				PM8606_VSYS_EN, PM8606_VSYS_EN))
+			goto out;
+
+		/*Enable Internal Oscillator */
+		if (pm860x_set_bits(i2c, PM8606_MISC,
+				PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
+			goto out;
+		/* Update status (only if writes succeed) */
+		chip->osc_status = PM8606_REF_GP_OSC_ON;
+	}
+	mutex_unlock(&chip->osc_lock);
+
+	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status, ret);
+	return 0;
+out:
+	mutex_unlock(&chip->osc_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_enable);
+
+int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
+{
+	int ret = -EIO;
+	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+		chip->client : chip->companion;
+
+	dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status);
+
+	mutex_lock(&chip->osc_lock);
+	/*Update voting status */
+	chip->osc_vote &= ~(client);
+	/* If reference group is off and this is the last client to release
+	 * - turn off */
+	if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
+			(chip->osc_vote == REF_GP_NO_CLIENTS)) {
+		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+		/* Disable Reference group Vsys */
+		if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
+			goto out;
+		/* Disable Internal Oscillator */
+		if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
+			goto out;
+		chip->osc_status = PM8606_REF_GP_OSC_OFF;
+	}
+	mutex_unlock(&chip->osc_lock);
+
+	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+			__func__, chip->osc_vote,
+			chip->osc_status, ret);
+	return 0;
+out:
+	mutex_unlock(&chip->osc_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_disable);
+
+static void __devinit device_osc_init(struct i2c_client *i2c)
+{
+	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+
+	mutex_init(&chip->osc_lock);
+	/* init portofino reference group voting and status */
+	/* Disable Reference group Vsys */
+	pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
+	/* Disable Internal Oscillator */
+	pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
+
+	chip->osc_vote = REF_GP_NO_CLIENTS;
+	chip->osc_status = PM8606_REF_GP_OSC_OFF;
+}
+
 static void __devinit device_bk_init(struct pm860x_chip *chip,
 static void __devinit device_bk_init(struct pm860x_chip *chip,
 				     struct pm860x_platform_data *pdata)
 				     struct pm860x_platform_data *pdata)
 {
 {
@@ -767,6 +862,15 @@ out:
 	return;
 	return;
 }
 }
 
 
+static void __devinit device_8606_init(struct pm860x_chip *chip,
+				       struct i2c_client *i2c,
+				       struct pm860x_platform_data *pdata)
+{
+	device_osc_init(i2c);
+	device_bk_init(chip, pdata);
+	device_led_init(chip, pdata);
+}
+
 int __devinit pm860x_device_init(struct pm860x_chip *chip,
 int __devinit pm860x_device_init(struct pm860x_chip *chip,
 		       struct pm860x_platform_data *pdata)
 		       struct pm860x_platform_data *pdata)
 {
 {
@@ -774,8 +878,7 @@ 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, pdata);
-		device_led_init(chip, pdata);
+		device_8606_init(chip, chip->client, pdata);
 		break;
 		break;
 	case CHIP_PM8607:
 	case CHIP_PM8607:
 		device_8607_init(chip, chip->client, pdata);
 		device_8607_init(chip, chip->client, pdata);
@@ -785,8 +888,7 @@ 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, pdata);
-			device_led_init(chip, pdata);
+			device_8606_init(chip, chip->companion, pdata);
 			break;
 			break;
 		case CHIP_PM8606:
 		case CHIP_PM8606:
 			device_8607_init(chip, chip->companion, pdata);
 			device_8607_init(chip, chip->companion, pdata);

+ 25 - 0
drivers/mfd/88pm860x-i2c.c

@@ -334,10 +334,35 @@ static int __devexit pm860x_remove(struct i2c_client *client)
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_suspend(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(dev) && chip->wakeup_flag)
+		enable_irq_wake(chip->core_irq);
+	return 0;
+}
+
+static int pm860x_resume(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(dev) && chip->wakeup_flag)
+		disable_irq_wake(chip->core_irq);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
+
 static struct i2c_driver pm860x_driver = {
 static struct i2c_driver pm860x_driver = {
 	.driver	= {
 	.driver	= {
 		.name	= "88PM860x",
 		.name	= "88PM860x",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
+		.pm     = &pm860x_pm_ops,
 	},
 	},
 	.probe		= pm860x_probe,
 	.probe		= pm860x_probe,
 	.remove		= __devexit_p(pm860x_remove),
 	.remove		= __devexit_p(pm860x_remove),

+ 52 - 2
drivers/mfd/Kconfig

@@ -143,6 +143,21 @@ 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_TPS65217
+	tristate "TPS65217 Power Management / White LED chips"
+	depends on I2C
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the TPS65217 series of
+	  Power Management / White LED chips.
+	  These include voltage regulators, lithium ion/polymer battery
+	  charger, wled and other features that are often used in portable
+	  devices.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tps65217.
+
 config MFD_TPS6586X
 config MFD_TPS6586X
 	bool "TPS6586x Power Management chips"
 	bool "TPS6586x Power Management chips"
 	depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
 	depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
@@ -162,6 +177,7 @@ config MFD_TPS65910
 	depends on I2C=y && GPIOLIB
 	depends on I2C=y && GPIOLIB
 	select MFD_CORE
 	select MFD_CORE
 	select GPIO_TPS65910
 	select GPIO_TPS65910
+	select REGMAP_I2C
 	help
 	help
 	  if you say yes here you get support for the TPS65910 series of
 	  if you say yes here you get support for the TPS65910 series of
 	  Power Management chips.
 	  Power Management chips.
@@ -171,7 +187,7 @@ config MFD_TPS65912
 	depends on GPIOLIB
 	depends on GPIOLIB
 
 
 config MFD_TPS65912_I2C
 config MFD_TPS65912_I2C
-	bool "TPS95612 Power Management chip with I2C"
+	bool "TPS65912 Power Management chip with I2C"
 	select MFD_CORE
 	select MFD_CORE
 	select MFD_TPS65912
 	select MFD_TPS65912
 	depends on I2C=y && GPIOLIB
 	depends on I2C=y && GPIOLIB
@@ -400,7 +416,7 @@ config MFD_MAX8997
 	depends on I2C=y && GENERIC_HARDIRQS
 	depends on I2C=y && GENERIC_HARDIRQS
 	select MFD_CORE
 	select MFD_CORE
 	help
 	help
-	  Say yes here to support for Maxim Semiconductor MAX8998/8966.
+	  Say yes here to support for Maxim Semiconductor MAX8997/8966.
 	  This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
 	  This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
 	  MUIC controls on chip.
 	  MUIC controls on chip.
 	  This driver provides common support for accessing the device;
 	  This driver provides common support for accessing the device;
@@ -812,6 +828,18 @@ config MFD_PM8XXX_IRQ
 config TPS65911_COMPARATOR
 config TPS65911_COMPARATOR
 	tristate
 	tristate
 
 
+config MFD_TPS65090
+	bool "TPS65090 Power Management chips"
+	depends on I2C=y && GENERIC_HARDIRQS
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the TPS65090 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.
+
 config MFD_AAT2870_CORE
 config MFD_AAT2870_CORE
 	bool "Support for the AnalogicTech AAT2870"
 	bool "Support for the AnalogicTech AAT2870"
 	select MFD_CORE
 	select MFD_CORE
@@ -831,6 +859,28 @@ config MFD_INTEL_MSIC
 	  Passage) chip. This chip embeds audio, battery, GPIO, etc.
 	  Passage) chip. This chip embeds audio, battery, GPIO, etc.
 	  devices used in Intel Medfield platforms.
 	  devices used in Intel Medfield platforms.
 
 
+config MFD_RC5T583
+	bool "Ricoh RC5T583 Power Management system device"
+	depends on I2C=y && GENERIC_HARDIRQS
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  Select this option to get support for the RICOH583 Power
+	  Management system device.
+	  This driver provides common support for accessing the device
+	  through i2c interface. The device supports multiple sub-devices
+	  like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey.
+	  Additional drivers must be enabled in order to use the
+	  different functionality of the device.
+
+config MFD_ANATOP
+	bool "Support for Freescale i.MX on-chip ANATOP controller"
+	depends on SOC_IMX6Q
+	help
+	  Select this option to enable Freescale i.MX on-chip ANATOP
+	  MFD controller. This controller embeds regulator and
+	  thermal devices for Freescale i.MX platforms.
+
 endmenu
 endmenu
 endif
 endif
 
 

+ 4 - 0
drivers/mfd/Makefile

@@ -38,6 +38,7 @@ obj-$(CONFIG_MFD_WM8994)	+= wm8994-core.o wm8994-irq.o wm8994-regmap.o
 obj-$(CONFIG_TPS6105X)		+= tps6105x.o
 obj-$(CONFIG_TPS6105X)		+= tps6105x.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
 obj-$(CONFIG_TPS6507X)		+= tps6507x.o
 obj-$(CONFIG_TPS6507X)		+= tps6507x.o
+obj-$(CONFIG_MFD_TPS65217)	+= tps65217.o
 obj-$(CONFIG_MFD_TPS65910)	+= tps65910.o tps65910-irq.o
 obj-$(CONFIG_MFD_TPS65910)	+= tps65910.o tps65910-irq.o
 tps65912-objs                   := tps65912-core.o tps65912-irq.o
 tps65912-objs                   := tps65912-core.o tps65912-irq.o
 obj-$(CONFIG_MFD_TPS65912)	+= tps65912.o
 obj-$(CONFIG_MFD_TPS65912)	+= tps65912.o
@@ -109,6 +110,9 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST)	+= omap-usb-host.o
 obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o
 obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)	+= tps65911-comparator.o
 obj-$(CONFIG_TPS65911_COMPARATOR)	+= tps65911-comparator.o
+obj-$(CONFIG_MFD_TPS65090)	+= tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
 obj-$(CONFIG_MFD_INTEL_MSIC)	+= intel_msic.o
 obj-$(CONFIG_MFD_INTEL_MSIC)	+= intel_msic.o
+obj-$(CONFIG_MFD_RC5T583)	+= rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_S5M_CORE)	+= s5m-core.o s5m-irq.o
 obj-$(CONFIG_MFD_S5M_CORE)	+= s5m-core.o s5m-irq.o
+obj-$(CONFIG_MFD_ANATOP)	+= anatop-mfd.o

+ 285 - 90
drivers/mfd/ab8500-core.c

@@ -32,6 +32,7 @@
 #define AB8500_IT_SOURCE6_REG		0x05
 #define AB8500_IT_SOURCE6_REG		0x05
 #define AB8500_IT_SOURCE7_REG		0x06
 #define AB8500_IT_SOURCE7_REG		0x06
 #define AB8500_IT_SOURCE8_REG		0x07
 #define AB8500_IT_SOURCE8_REG		0x07
+#define AB9540_IT_SOURCE13_REG		0x0C
 #define AB8500_IT_SOURCE19_REG		0x12
 #define AB8500_IT_SOURCE19_REG		0x12
 #define AB8500_IT_SOURCE20_REG		0x13
 #define AB8500_IT_SOURCE20_REG		0x13
 #define AB8500_IT_SOURCE21_REG		0x14
 #define AB8500_IT_SOURCE21_REG		0x14
@@ -53,6 +54,7 @@
 #define AB8500_IT_LATCH9_REG		0x28
 #define AB8500_IT_LATCH9_REG		0x28
 #define AB8500_IT_LATCH10_REG		0x29
 #define AB8500_IT_LATCH10_REG		0x29
 #define AB8500_IT_LATCH12_REG		0x2B
 #define AB8500_IT_LATCH12_REG		0x2B
+#define AB9540_IT_LATCH13_REG		0x2C
 #define AB8500_IT_LATCH19_REG		0x32
 #define AB8500_IT_LATCH19_REG		0x32
 #define AB8500_IT_LATCH20_REG		0x33
 #define AB8500_IT_LATCH20_REG		0x33
 #define AB8500_IT_LATCH21_REG		0x34
 #define AB8500_IT_LATCH21_REG		0x34
@@ -90,21 +92,39 @@
 #define AB8500_IT_MASK24_REG		0x57
 #define AB8500_IT_MASK24_REG		0x57
 
 
 #define AB8500_REV_REG			0x80
 #define AB8500_REV_REG			0x80
+#define AB8500_IC_NAME_REG		0x82
 #define AB8500_SWITCH_OFF_STATUS	0x00
 #define AB8500_SWITCH_OFF_STATUS	0x00
 
 
 #define AB8500_TURN_ON_STATUS		0x00
 #define AB8500_TURN_ON_STATUS		0x00
 
 
+#define AB9540_MODEM_CTRL2_REG			0x23
+#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2)
+
 /*
 /*
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
- * numbers are indexed into this array with (num / 8).
+ * numbers are indexed into this array with (num / 8). The interupts are
+ * defined in linux/mfd/ab8500.h
  *
  *
  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
  * offset 0.
  * offset 0.
  */
  */
+/* AB8500 support */
 static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
 static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
 };
 };
 
 
+/* AB9540 support */
+static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
+	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
+};
+
+static const char ab8500_version_str[][7] = {
+	[AB8500_VERSION_AB8500] = "AB8500",
+	[AB8500_VERSION_AB8505] = "AB8505",
+	[AB8500_VERSION_AB9540] = "AB9540",
+	[AB8500_VERSION_AB8540] = "AB8540",
+};
+
 static int ab8500_get_chip_id(struct device *dev)
 static int ab8500_get_chip_id(struct device *dev)
 {
 {
 	struct ab8500 *ab8500;
 	struct ab8500 *ab8500;
@@ -127,9 +147,7 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
 
 
 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
 
 
-	ret = mutex_lock_interruptible(&ab8500->lock);
-	if (ret)
-		return ret;
+	mutex_lock(&ab8500->lock);
 
 
 	ret = ab8500->write(ab8500, addr, data);
 	ret = ab8500->write(ab8500, addr, data);
 	if (ret < 0)
 	if (ret < 0)
@@ -156,9 +174,7 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
 	 * bank on higher 8 bits and reg in lower */
 	 * bank on higher 8 bits and reg in lower */
 	u16 addr = ((u16)bank) << 8 | reg;
 	u16 addr = ((u16)bank) << 8 | reg;
 
 
-	ret = mutex_lock_interruptible(&ab8500->lock);
-	if (ret)
-		return ret;
+	mutex_lock(&ab8500->lock);
 
 
 	ret = ab8500->read(ab8500, addr);
 	ret = ab8500->read(ab8500, addr);
 	if (ret < 0)
 	if (ret < 0)
@@ -185,31 +201,38 @@ static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
 	u8 reg, u8 bitmask, u8 bitvalues)
 	u8 reg, u8 bitmask, u8 bitvalues)
 {
 {
 	int ret;
 	int ret;
-	u8 data;
 	/* put the u8 bank and u8 reg together into a an u16.
 	/* put the u8 bank and u8 reg together into a an u16.
 	 * bank on higher 8 bits and reg in lower */
 	 * bank on higher 8 bits and reg in lower */
 	u16 addr = ((u16)bank) << 8 | reg;
 	u16 addr = ((u16)bank) << 8 | reg;
 
 
-	ret = mutex_lock_interruptible(&ab8500->lock);
-	if (ret)
-		return ret;
+	mutex_lock(&ab8500->lock);
 
 
-	ret = ab8500->read(ab8500, addr);
-	if (ret < 0) {
-		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
-			addr, ret);
-		goto out;
-	}
+	if (ab8500->write_masked == NULL) {
+		u8 data;
 
 
-	data = (u8)ret;
-	data = (~bitmask & data) | (bitmask & bitvalues);
+		ret = ab8500->read(ab8500, addr);
+		if (ret < 0) {
+			dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
+				addr, ret);
+			goto out;
+		}
 
 
-	ret = ab8500->write(ab8500, addr, data);
-	if (ret < 0)
-		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
-			addr, ret);
+		data = (u8)ret;
+		data = (~bitmask & data) | (bitmask & bitvalues);
+
+		ret = ab8500->write(ab8500, addr, data);
+		if (ret < 0)
+			dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
+				addr, ret);
 
 
-	dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
+		dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
+			data);
+		goto out;
+	}
+	ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
+	if (ret < 0)
+		dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
+			ret);
 out:
 out:
 	mutex_unlock(&ab8500->lock);
 	mutex_unlock(&ab8500->lock);
 	return ret;
 	return ret;
@@ -248,7 +271,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
 	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
 	int i;
 	int i;
 
 
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+	for (i = 0; i < ab8500->mask_size; i++) {
 		u8 old = ab8500->oldmask[i];
 		u8 old = ab8500->oldmask[i];
 		u8 new = ab8500->mask[i];
 		u8 new = ab8500->mask[i];
 		int reg;
 		int reg;
@@ -256,14 +279,17 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
 		if (new == old)
 		if (new == old)
 			continue;
 			continue;
 
 
-		/* Interrupt register 12 doesn't exist prior to version 2.0 */
-		if (ab8500_irq_regoffset[i] == 11 &&
-			ab8500->chip_id < AB8500_CUT2P0)
+		/*
+		 * Interrupt register 12 doesn't exist prior to AB8500 version
+		 * 2.0
+		 */
+		if (ab8500->irq_reg_offset[i] == 11 &&
+			is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 			continue;
 
 
 		ab8500->oldmask[i] = new;
 		ab8500->oldmask[i] = new;
 
 
-		reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
+		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
 	}
 	}
 
 
@@ -306,13 +332,16 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
 
 
 	dev_vdbg(ab8500->dev, "interrupt\n");
 	dev_vdbg(ab8500->dev, "interrupt\n");
 
 
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-		int regoffset = ab8500_irq_regoffset[i];
+	for (i = 0; i < ab8500->mask_size; i++) {
+		int regoffset = ab8500->irq_reg_offset[i];
 		int status;
 		int status;
 		u8 value;
 		u8 value;
 
 
-		/* Interrupt register 12 doesn't exist prior to version 2.0 */
-		if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
+		/*
+		 * Interrupt register 12 doesn't exist prior to AB8500 version
+		 * 2.0
+		 */
+		if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 			continue;
 
 
 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -336,8 +365,16 @@ static int ab8500_irq_init(struct ab8500 *ab8500)
 {
 {
 	int base = ab8500->irq_base;
 	int base = ab8500->irq_base;
 	int irq;
 	int irq;
+	int num_irqs;
+
+	if (is_ab9540(ab8500))
+		num_irqs = AB9540_NR_IRQS;
+	else if (is_ab8505(ab8500))
+		num_irqs = AB8505_NR_IRQS;
+	else
+		num_irqs = AB8500_NR_IRQS;
 
 
-	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+	for (irq = base; irq < base + num_irqs; irq++) {
 		irq_set_chip_data(irq, ab8500);
 		irq_set_chip_data(irq, ab8500);
 		irq_set_chip_and_handler(irq, &ab8500_irq_chip,
 		irq_set_chip_and_handler(irq, &ab8500_irq_chip,
 					 handle_simple_irq);
 					 handle_simple_irq);
@@ -356,8 +393,16 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
 {
 {
 	int base = ab8500->irq_base;
 	int base = ab8500->irq_base;
 	int irq;
 	int irq;
+	int num_irqs;
 
 
-	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+	if (is_ab9540(ab8500))
+		num_irqs = AB9540_NR_IRQS;
+	else if (is_ab8505(ab8500))
+		num_irqs = AB8505_NR_IRQS;
+	else
+		num_irqs = AB8500_NR_IRQS;
+
+	for (irq = base; irq < base + num_irqs; irq++) {
 #ifdef CONFIG_ARM
 #ifdef CONFIG_ARM
 		set_irq_flags(irq, 0);
 		set_irq_flags(irq, 0);
 #endif
 #endif
@@ -366,6 +411,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
 	}
 	}
 }
 }
 
 
+/* AB8500 GPIO Resources */
 static struct resource __devinitdata ab8500_gpio_resources[] = {
 static struct resource __devinitdata ab8500_gpio_resources[] = {
 	{
 	{
 		.name	= "GPIO_INT6",
 		.name	= "GPIO_INT6",
@@ -375,6 +421,28 @@ static struct resource __devinitdata ab8500_gpio_resources[] = {
 	}
 	}
 };
 };
 
 
+/* AB9540 GPIO Resources */
+static struct resource __devinitdata ab9540_gpio_resources[] = {
+	{
+		.name	= "GPIO_INT6",
+		.start	= AB8500_INT_GPIO6R,
+		.end	= AB8500_INT_GPIO41F,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "GPIO_INT14",
+		.start	= AB9540_INT_GPIO50R,
+		.end	= AB9540_INT_GPIO54R,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "GPIO_INT15",
+		.start	= AB9540_INT_GPIO50F,
+		.end	= AB9540_INT_GPIO54F,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
 static struct resource __devinitdata ab8500_gpadc_resources[] = {
 static struct resource __devinitdata ab8500_gpadc_resources[] = {
 	{
 	{
 		.name	= "HW_CONV_END",
 		.name	= "HW_CONV_END",
@@ -490,12 +558,6 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
 		.end = AB8500_INT_USB_LINK_STATUS,
 		.end = AB8500_INT_USB_LINK_STATUS,
 		.flags = IORESOURCE_IRQ,
 		.flags = IORESOURCE_IRQ,
 	},
 	},
-	{
-		.name = "USB_CHARGE_DET_DONE",
-		.start = AB8500_INT_USB_CHG_DET_DONE,
-		.end = AB8500_INT_USB_CHG_DET_DONE,
-		.flags = IORESOURCE_IRQ,
-	},
 	{
 	{
 		.name = "VBUS_OVV",
 		.name = "VBUS_OVV",
 		.start = AB8500_INT_VBUS_OVV,
 		.start = AB8500_INT_VBUS_OVV,
@@ -534,14 +596,8 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
 	},
 	},
 	{
 	{
 		.name = "USB_CHARGER_NOT_OKR",
 		.name = "USB_CHARGER_NOT_OKR",
-		.start = AB8500_INT_USB_CHARGER_NOT_OK,
-		.end = AB8500_INT_USB_CHARGER_NOT_OK,
-		.flags = IORESOURCE_IRQ,
-	},
-	{
-		.name = "USB_CHARGER_NOT_OKF",
-		.start = AB8500_INT_USB_CHARGER_NOT_OKF,
-		.end = AB8500_INT_USB_CHARGER_NOT_OKF,
+		.start = AB8500_INT_USB_CHARGER_NOT_OKR,
+		.end = AB8500_INT_USB_CHARGER_NOT_OKR,
 		.flags = IORESOURCE_IRQ,
 		.flags = IORESOURCE_IRQ,
 	},
 	},
 	{
 	{
@@ -616,6 +672,12 @@ static struct resource __devinitdata ab8500_fg_resources[] = {
 		.end = AB8500_INT_CC_INT_CALIB,
 		.end = AB8500_INT_CC_INT_CALIB,
 		.flags = IORESOURCE_IRQ,
 		.flags = IORESOURCE_IRQ,
 	},
 	},
+	{
+		.name = "CCEOC",
+		.start = AB8500_INT_CCEOC,
+		.end = AB8500_INT_CCEOC,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 };
 
 
 static struct resource __devinitdata ab8500_chargalg_resources[] = {};
 static struct resource __devinitdata ab8500_chargalg_resources[] = {};
@@ -630,8 +692,8 @@ static struct resource __devinitdata ab8500_debug_resources[] = {
 	},
 	},
 	{
 	{
 		.name	= "IRQ_LAST",
 		.name	= "IRQ_LAST",
-		.start	= AB8500_INT_USB_CHARGER_NOT_OKF,
-		.end	= AB8500_INT_USB_CHARGER_NOT_OKF,
+		.start	= AB8500_INT_XTAL32K_KO,
+		.end	= AB8500_INT_XTAL32K_KO,
 		.flags	= IORESOURCE_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 	},
 };
 };
@@ -691,7 +753,7 @@ static struct resource __devinitdata ab8500_temp_resources[] = {
 	},
 	},
 };
 };
 
 
-static struct mfd_cell __devinitdata ab8500_devs[] = {
+static struct mfd_cell __devinitdata abx500_common_devs[] = {
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS
 	{
 	{
 		.name = "ab8500-debug",
 		.name = "ab8500-debug",
@@ -705,11 +767,6 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
 	{
 	{
 		.name = "ab8500-regulator",
 		.name = "ab8500-regulator",
 	},
 	},
-	{
-		.name = "ab8500-gpio",
-		.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
-		.resources = ab8500_gpio_resources,
-	},
 	{
 	{
 		.name = "ab8500-gpadc",
 		.name = "ab8500-gpadc",
 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
@@ -748,11 +805,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
 	{
 	{
 		.name = "ab8500-codec",
 		.name = "ab8500-codec",
 	},
 	},
-	{
-		.name = "ab8500-usb",
-		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
-		.resources = ab8500_usb_resources,
-	},
+
 	{
 	{
 		.name = "ab8500-poweron-key",
 		.name = "ab8500-poweron-key",
 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
@@ -781,6 +834,32 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
 	},
 	},
 };
 };
 
 
+static struct mfd_cell __devinitdata ab8500_devs[] = {
+	{
+		.name = "ab8500-gpio",
+		.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
+		.resources = ab8500_gpio_resources,
+	},
+	{
+		.name = "ab8500-usb",
+		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
+		.resources = ab8500_usb_resources,
+	},
+};
+
+static struct mfd_cell __devinitdata ab9540_devs[] = {
+	{
+		.name = "ab8500-gpio",
+		.num_resources = ARRAY_SIZE(ab9540_gpio_resources),
+		.resources = ab9540_gpio_resources,
+	},
+	{
+		.name = "ab9540-usb",
+		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
+		.resources = ab8500_usb_resources,
+	},
+};
+
 static ssize_t show_chip_id(struct device *dev,
 static ssize_t show_chip_id(struct device *dev,
 				struct device_attribute *attr, char *buf)
 				struct device_attribute *attr, char *buf)
 {
 {
@@ -842,9 +921,64 @@ static ssize_t show_turn_on_status(struct device *dev,
 	return sprintf(buf, "%#x\n", value);
 	return sprintf(buf, "%#x\n", value);
 }
 }
 
 
+static ssize_t show_ab9540_dbbrstn(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ab8500 *ab8500;
+	int ret;
+	u8 value;
+
+	ab8500 = dev_get_drvdata(dev);
+
+	ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
+		AB9540_MODEM_CTRL2_REG, &value);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n",
+			(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
+}
+
+static ssize_t store_ab9540_dbbrstn(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct ab8500 *ab8500;
+	int ret = count;
+	int err;
+	u8 bitvalues;
+
+	ab8500 = dev_get_drvdata(dev);
+
+	if (count > 0) {
+		switch (buf[0]) {
+		case '0':
+			bitvalues = 0;
+			break;
+		case '1':
+			bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
+			break;
+		default:
+			goto exit;
+		}
+
+		err = mask_and_set_register_interruptible(ab8500,
+			AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
+			AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
+		if (err)
+			dev_info(ab8500->dev,
+				"Failed to set DBBRSTN %c, err %#x\n",
+				buf[0], err);
+	}
+
+exit:
+	return ret;
+}
+
 static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
 static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
 static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
 static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
 static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
 static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
+			show_ab9540_dbbrstn, store_ab9540_dbbrstn);
 
 
 static struct attribute *ab8500_sysfs_entries[] = {
 static struct attribute *ab8500_sysfs_entries[] = {
 	&dev_attr_chip_id.attr,
 	&dev_attr_chip_id.attr,
@@ -853,11 +987,23 @@ static struct attribute *ab8500_sysfs_entries[] = {
 	NULL,
 	NULL,
 };
 };
 
 
+static struct attribute *ab9540_sysfs_entries[] = {
+	&dev_attr_chip_id.attr,
+	&dev_attr_switch_off_status.attr,
+	&dev_attr_turn_on_status.attr,
+	&dev_attr_dbbrstn.attr,
+	NULL,
+};
+
 static struct attribute_group ab8500_attr_group = {
 static struct attribute_group ab8500_attr_group = {
 	.attrs	= ab8500_sysfs_entries,
 	.attrs	= ab8500_sysfs_entries,
 };
 };
 
 
-int __devinit ab8500_init(struct ab8500 *ab8500)
+static struct attribute_group ab9540_attr_group = {
+	.attrs	= ab9540_sysfs_entries,
+};
+
+int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
 {
 {
 	struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
 	struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
 	int ret;
 	int ret;
@@ -870,25 +1016,45 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 	mutex_init(&ab8500->lock);
 	mutex_init(&ab8500->lock);
 	mutex_init(&ab8500->irq_lock);
 	mutex_init(&ab8500->irq_lock);
 
 
+	if (version != AB8500_VERSION_UNDEFINED)
+		ab8500->version = version;
+	else {
+		ret = get_register_interruptible(ab8500, AB8500_MISC,
+			AB8500_IC_NAME_REG, &value);
+		if (ret < 0)
+			return ret;
+
+		ab8500->version = value;
+	}
+
 	ret = get_register_interruptible(ab8500, AB8500_MISC,
 	ret = get_register_interruptible(ab8500, AB8500_MISC,
 		AB8500_REV_REG, &value);
 		AB8500_REV_REG, &value);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	switch (value) {
-	case AB8500_CUT1P0:
-	case AB8500_CUT1P1:
-	case AB8500_CUT2P0:
-	case AB8500_CUT3P0:
-	case AB8500_CUT3P3:
-		dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
-		break;
-	default:
-		dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
-		return -EINVAL;
-	}
 	ab8500->chip_id = value;
 	ab8500->chip_id = value;
 
 
+	dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
+			ab8500_version_str[ab8500->version],
+			ab8500->chip_id >> 4,
+			ab8500->chip_id & 0x0F);
+
+	/* Configure AB8500 or AB9540 IRQ */
+	if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
+		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
+		ab8500->irq_reg_offset = ab9540_irq_regoffset;
+	} else {
+		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
+		ab8500->irq_reg_offset = ab8500_irq_regoffset;
+	}
+	ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+	if (!ab8500->mask)
+		return -ENOMEM;
+	ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+	if (!ab8500->oldmask) {
+		ret = -ENOMEM;
+		goto out_freemask;
+	}
 	/*
 	/*
 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
 	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
 	 * 0x01 Swoff bit programming
 	 * 0x01 Swoff bit programming
@@ -911,30 +1077,33 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 		plat->init(ab8500);
 		plat->init(ab8500);
 
 
 	/* Clear and mask all interrupts */
 	/* Clear and mask all interrupts */
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-		/* Interrupt register 12 doesn't exist prior to version 2.0 */
-		if (ab8500_irq_regoffset[i] == 11 &&
-			ab8500->chip_id < AB8500_CUT2P0)
+	for (i = 0; i < ab8500->mask_size; i++) {
+		/*
+		 * Interrupt register 12 doesn't exist prior to AB8500 version
+		 * 2.0
+		 */
+		if (ab8500->irq_reg_offset[i] == 11 &&
+				is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 			continue;
 
 
 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
-			AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
 			&value);
 			&value);
 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
-			AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
+			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
 	}
 	}
 
 
 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
 	if (ret)
 	if (ret)
-		return ret;
+		goto out_freeoldmask;
 
 
-	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
+	for (i = 0; i < ab8500->mask_size; i++)
 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
 
 
 	if (ab8500->irq_base) {
 	if (ab8500->irq_base) {
 		ret = ab8500_irq_init(ab8500);
 		ret = ab8500_irq_init(ab8500);
 		if (ret)
 		if (ret)
-			return ret;
+			goto out_freeoldmask;
 
 
 		ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
 		ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
 					   IRQF_ONESHOT | IRQF_NO_SUSPEND,
 					   IRQF_ONESHOT | IRQF_NO_SUSPEND,
@@ -943,17 +1112,34 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 			goto out_removeirq;
 			goto out_removeirq;
 	}
 	}
 
 
-	ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
-			      ARRAY_SIZE(ab8500_devs), NULL,
+	ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
+			      ARRAY_SIZE(abx500_common_devs), NULL,
 			      ab8500->irq_base);
 			      ab8500->irq_base);
+
 	if (ret)
 	if (ret)
 		goto out_freeirq;
 		goto out_freeirq;
 
 
-	ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+	if (is_ab9540(ab8500))
+		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
+			      ARRAY_SIZE(ab9540_devs), NULL,
+			      ab8500->irq_base);
+	else
+		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
+			      ARRAY_SIZE(ab9540_devs), NULL,
+			      ab8500->irq_base);
 	if (ret)
 	if (ret)
-		dev_err(ab8500->dev, "error creating sysfs entries\n");
+		goto out_freeirq;
 
 
-	return ret;
+	if (is_ab9540(ab8500))
+		ret = sysfs_create_group(&ab8500->dev->kobj,
+					&ab9540_attr_group);
+	else
+		ret = sysfs_create_group(&ab8500->dev->kobj,
+					&ab8500_attr_group);
+	if (ret)
+		dev_err(ab8500->dev, "error creating sysfs entries\n");
+	else
+		return ret;
 
 
 out_freeirq:
 out_freeirq:
 	if (ab8500->irq_base)
 	if (ab8500->irq_base)
@@ -961,18 +1147,27 @@ out_freeirq:
 out_removeirq:
 out_removeirq:
 	if (ab8500->irq_base)
 	if (ab8500->irq_base)
 		ab8500_irq_remove(ab8500);
 		ab8500_irq_remove(ab8500);
+out_freeoldmask:
+	kfree(ab8500->oldmask);
+out_freemask:
+	kfree(ab8500->mask);
 
 
 	return ret;
 	return ret;
 }
 }
 
 
 int __devexit ab8500_exit(struct ab8500 *ab8500)
 int __devexit ab8500_exit(struct ab8500 *ab8500)
 {
 {
-	sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
+	if (is_ab9540(ab8500))
+		sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
+	else
+		sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
 	mfd_remove_devices(ab8500->dev);
 	mfd_remove_devices(ab8500->dev);
 	if (ab8500->irq_base) {
 	if (ab8500->irq_base) {
 		free_irq(ab8500->irq, ab8500);
 		free_irq(ab8500->irq, ab8500);
 		ab8500_irq_remove(ab8500);
 		ab8500_irq_remove(ab8500);
 	}
 	}
+	kfree(ab8500->oldmask);
+	kfree(ab8500->mask);
 
 
 	return 0;
 	return 0;
 }
 }

+ 27 - 3
drivers/mfd/ab8500-i2c.c

@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/dbx500-prcmu.h>
 
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 {
 {
@@ -23,6 +23,18 @@ static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 	return ret;
 	return ret;
 }
 }
 
 
+static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
+	u8 data)
+{
+	int ret;
+
+	ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
+		&mask, 1);
+	if (ret < 0)
+		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+	return ret;
+}
+
 static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 {
 {
 	int ret;
 	int ret;
@@ -38,6 +50,7 @@ static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 
 
 static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 {
 {
+	const struct platform_device_id *platid = platform_get_device_id(plf);
 	struct ab8500 *ab8500;
 	struct ab8500 *ab8500;
 	struct resource *resource;
 	struct resource *resource;
 	int ret;
 	int ret;
@@ -58,13 +71,15 @@ static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 
 
 	ab8500->read = ab8500_i2c_read;
 	ab8500->read = ab8500_i2c_read;
 	ab8500->write = ab8500_i2c_write;
 	ab8500->write = ab8500_i2c_write;
+	ab8500->write_masked = ab8500_i2c_write_masked;
 
 
 	platform_set_drvdata(plf, ab8500);
 	platform_set_drvdata(plf, ab8500);
 
 
-	ret = ab8500_init(ab8500);
+	ret = ab8500_init(ab8500, platid->driver_data);
 	if (ret)
 	if (ret)
 		kfree(ab8500);
 		kfree(ab8500);
 
 
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -78,13 +93,22 @@ static int __devexit ab8500_i2c_remove(struct platform_device *plf)
 	return 0;
 	return 0;
 }
 }
 
 
+static const struct platform_device_id ab8500_id[] = {
+	{ "ab8500-i2c", AB8500_VERSION_AB8500 },
+	{ "ab8505-i2c", AB8500_VERSION_AB8505 },
+	{ "ab9540-i2c", AB8500_VERSION_AB9540 },
+	{ "ab8540-i2c", AB8500_VERSION_AB8540 },
+	{ }
+};
+
 static struct platform_driver ab8500_i2c_driver = {
 static struct platform_driver ab8500_i2c_driver = {
 	.driver = {
 	.driver = {
 		.name = "ab8500-i2c",
 		.name = "ab8500-i2c",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe	= ab8500_i2c_probe,
 	.probe	= ab8500_i2c_probe,
-	.remove	= __devexit_p(ab8500_i2c_remove)
+	.remove	= __devexit_p(ab8500_i2c_remove),
+	.id_table = ab8500_id,
 };
 };
 
 
 static int __init ab8500_i2c_init(void)
 static int __init ab8500_i2c_init(void)

+ 137 - 0
drivers/mfd/anatop-mfd.c

@@ -0,0 +1,137 @@
+/*
+ * Anatop MFD driver
+ *
+ * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ * Copyright (C) 2012 Linaro
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/mfd/anatop.h>
+
+u32 anatop_get_bits(struct anatop *adata, u32 addr, int bit_shift,
+		    int bit_width)
+{
+	u32 val, mask;
+
+	if (bit_width == 32)
+		mask = ~0;
+	else
+		mask = (1 << bit_width) - 1;
+
+	val = readl(adata->ioreg + addr);
+	val = (val >> bit_shift) & mask;
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(anatop_get_bits);
+
+void anatop_set_bits(struct anatop *adata, u32 addr, int bit_shift,
+		     int bit_width, u32 data)
+{
+	u32 val, mask;
+
+	if (bit_width == 32)
+		mask = ~0;
+	else
+		mask = (1 << bit_width) - 1;
+
+	spin_lock(&adata->reglock);
+	val = readl(adata->ioreg + addr) & ~(mask << bit_shift);
+	writel((data << bit_shift) | val, adata->ioreg + addr);
+	spin_unlock(&adata->reglock);
+}
+EXPORT_SYMBOL_GPL(anatop_set_bits);
+
+static const struct of_device_id of_anatop_match[] = {
+	{ .compatible = "fsl,imx6q-anatop", },
+	{ },
+};
+
+static int __devinit of_anatop_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	void *ioreg;
+	struct anatop *drvdata;
+
+	ioreg = of_iomap(np, 0);
+	if (!ioreg)
+		return -EADDRNOTAVAIL;
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->ioreg = ioreg;
+	spin_lock_init(&drvdata->reglock);
+	platform_set_drvdata(pdev, drvdata);
+	of_platform_populate(np, of_anatop_match, NULL, dev);
+
+	return 0;
+}
+
+static int __devexit of_anatop_remove(struct platform_device *pdev)
+{
+	struct anatop *drvdata;
+	drvdata = platform_get_drvdata(pdev);
+	iounmap(drvdata->ioreg);
+
+	return 0;
+}
+
+static struct platform_driver anatop_of_driver = {
+	.driver = {
+		.name = "anatop-mfd",
+		.owner = THIS_MODULE,
+		.of_match_table = of_anatop_match,
+	},
+	.probe		= of_anatop_probe,
+	.remove		= of_anatop_remove,
+};
+
+static int __init anatop_init(void)
+{
+	return platform_driver_register(&anatop_of_driver);
+}
+postcore_initcall(anatop_init);
+
+static void __exit anatop_exit(void)
+{
+	platform_driver_unregister(&anatop_of_driver);
+}
+module_exit(anatop_exit);
+
+MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_DESCRIPTION("ANATOP MFD driver");
+MODULE_LICENSE("GPL v2");

+ 6 - 0
drivers/mfd/asic3.c

@@ -525,6 +525,11 @@ static void asic3_gpio_set(struct gpio_chip *chip,
 	return;
 	return;
 }
 }
 
 
+static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	return (offset < ASIC3_NUM_GPIOS) ? IRQ_BOARD_START + offset : -ENXIO;
+}
+
 static __init int asic3_gpio_probe(struct platform_device *pdev,
 static __init int asic3_gpio_probe(struct platform_device *pdev,
 				   u16 *gpio_config, int num)
 				   u16 *gpio_config, int num)
 {
 {
@@ -976,6 +981,7 @@ static int __init asic3_probe(struct platform_device *pdev)
 	asic->gpio.set = asic3_gpio_set;
 	asic->gpio.set = asic3_gpio_set;
 	asic->gpio.direction_input = asic3_gpio_direction_input;
 	asic->gpio.direction_input = asic3_gpio_direction_input;
 	asic->gpio.direction_output = asic3_gpio_direction_output;
 	asic->gpio.direction_output = asic3_gpio_direction_output;
+	asic->gpio.to_irq = asic3_gpio_to_irq;
 
 
 	ret = asic3_gpio_probe(pdev,
 	ret = asic3_gpio_probe(pdev,
 			       pdata->gpio_config,
 			       pdata->gpio_config,

+ 0 - 3
drivers/mfd/da9052-core.c

@@ -16,7 +16,6 @@
 #include <linux/input.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
-#include <linux/mutex.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/module.h>
@@ -647,8 +646,6 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
 	struct irq_desc *desc;
 	struct irq_desc *desc;
 	int ret;
 	int ret;
 
 
-	mutex_init(&da9052->io_lock);
-
 	if (pdata && pdata->init != NULL)
 	if (pdata && pdata->init != NULL)
 		pdata->init(da9052);
 		pdata->init(da9052);
 
 

+ 7 - 4
drivers/mfd/da9052-i2c.c

@@ -74,24 +74,27 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
 
 
 	ret = da9052_i2c_enable_multiwrite(da9052);
 	ret = da9052_i2c_enable_multiwrite(da9052);
 	if (ret < 0)
 	if (ret < 0)
-		goto err;
+		goto err_regmap;
 
 
 	ret = da9052_device_init(da9052, id->driver_data);
 	ret = da9052_device_init(da9052, id->driver_data);
 	if (ret != 0)
 	if (ret != 0)
-		goto err;
+		goto err_regmap;
 
 
 	return 0;
 	return 0;
 
 
+err_regmap:
+	regmap_exit(da9052->regmap);
 err:
 err:
 	kfree(da9052);
 	kfree(da9052);
 	return ret;
 	return ret;
 }
 }
 
 
-static int da9052_i2c_remove(struct i2c_client *client)
+static int __devexit da9052_i2c_remove(struct i2c_client *client)
 {
 {
 	struct da9052 *da9052 = i2c_get_clientdata(client);
 	struct da9052 *da9052 = i2c_get_clientdata(client);
 
 
 	da9052_device_exit(da9052);
 	da9052_device_exit(da9052);
+	regmap_exit(da9052->regmap);
 	kfree(da9052);
 	kfree(da9052);
 
 
 	return 0;
 	return 0;
@@ -107,7 +110,7 @@ static struct i2c_device_id da9052_i2c_id[] = {
 
 
 static struct i2c_driver da9052_i2c_driver = {
 static struct i2c_driver da9052_i2c_driver = {
 	.probe = da9052_i2c_probe,
 	.probe = da9052_i2c_probe,
-	.remove = da9052_i2c_remove,
+	.remove = __devexit_p(da9052_i2c_remove),
 	.id_table = da9052_i2c_id,
 	.id_table = da9052_i2c_id,
 	.driver = {
 	.driver = {
 		.name = "da9052",
 		.name = "da9052",

+ 6 - 3
drivers/mfd/da9052-spi.c

@@ -21,7 +21,7 @@
 
 
 #include <linux/mfd/da9052/da9052.h>
 #include <linux/mfd/da9052/da9052.h>
 
 
-static int da9052_spi_probe(struct spi_device *spi)
+static int __devinit da9052_spi_probe(struct spi_device *spi)
 {
 {
 	int ret;
 	int ret;
 	const struct spi_device_id *id = spi_get_device_id(spi);
 	const struct spi_device_id *id = spi_get_device_id(spi);
@@ -52,20 +52,23 @@ static int da9052_spi_probe(struct spi_device *spi)
 
 
 	ret = da9052_device_init(da9052, id->driver_data);
 	ret = da9052_device_init(da9052, id->driver_data);
 	if (ret != 0)
 	if (ret != 0)
-		goto err;
+		goto err_regmap;
 
 
 	return 0;
 	return 0;
 
 
+err_regmap:
+	regmap_exit(da9052->regmap);
 err:
 err:
 	kfree(da9052);
 	kfree(da9052);
 	return ret;
 	return ret;
 }
 }
 
 
-static int da9052_spi_remove(struct spi_device *spi)
+static int __devexit da9052_spi_remove(struct spi_device *spi)
 {
 {
 	struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
 	struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
 
 
 	da9052_device_exit(da9052);
 	da9052_device_exit(da9052);
+	regmap_exit(da9052->regmap);
 	kfree(da9052);
 	kfree(da9052);
 
 
 	return 0;
 	return 0;

+ 886 - 334
drivers/mfd/db8500-prcmu.c

@@ -30,6 +30,7 @@
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
+#include <asm/hardware/gic.h>
 #include <mach/hardware.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/irqs.h>
 #include <mach/db8500-regs.h>
 #include <mach/db8500-regs.h>
@@ -39,11 +40,6 @@
 /* Offset for the firmware version within the TCPM */
 /* Offset for the firmware version within the TCPM */
 #define PRCMU_FW_VERSION_OFFSET 0xA4
 #define PRCMU_FW_VERSION_OFFSET 0xA4
 
 
-/* PRCMU project numbers, defined by PRCMU FW */
-#define PRCMU_PROJECT_ID_8500V1_0 1
-#define PRCMU_PROJECT_ID_8500V2_0 2
-#define PRCMU_PROJECT_ID_8400V2_0 3
-
 /* Index of different voltages to be used when accessing AVSData */
 /* Index of different voltages to be used when accessing AVSData */
 #define PRCM_AVS_BASE		0x2FC
 #define PRCM_AVS_BASE		0x2FC
 #define PRCM_AVS_VBB_RET	(PRCM_AVS_BASE + 0x0)
 #define PRCM_AVS_VBB_RET	(PRCM_AVS_BASE + 0x0)
@@ -137,6 +133,8 @@
 #define PRCM_REQ_MB1_ARM_OPP			(PRCM_REQ_MB1 + 0x0)
 #define PRCM_REQ_MB1_ARM_OPP			(PRCM_REQ_MB1 + 0x0)
 #define PRCM_REQ_MB1_APE_OPP			(PRCM_REQ_MB1 + 0x1)
 #define PRCM_REQ_MB1_APE_OPP			(PRCM_REQ_MB1 + 0x1)
 #define PRCM_REQ_MB1_PLL_ON_OFF			(PRCM_REQ_MB1 + 0x4)
 #define PRCM_REQ_MB1_PLL_ON_OFF			(PRCM_REQ_MB1 + 0x4)
+#define PLL_SOC0_OFF	0x1
+#define PLL_SOC0_ON	0x2
 #define PLL_SOC1_OFF	0x4
 #define PLL_SOC1_OFF	0x4
 #define PLL_SOC1_ON	0x8
 #define PLL_SOC1_ON	0x8
 
 
@@ -266,6 +264,11 @@
 #define WAKEUP_BIT_GPIO7 BIT(30)
 #define WAKEUP_BIT_GPIO7 BIT(30)
 #define WAKEUP_BIT_GPIO8 BIT(31)
 #define WAKEUP_BIT_GPIO8 BIT(31)
 
 
+static struct {
+	bool valid;
+	struct prcmu_fw_version version;
+} fw_info;
+
 /*
 /*
  * This vector maps irq numbers to the bits in the bit field used in
  * This vector maps irq numbers to the bits in the bit field used in
  * communication with the PRCMU firmware.
  * communication with the PRCMU firmware.
@@ -341,11 +344,13 @@ static struct {
  * mb1_transfer - state needed for mailbox 1 communication.
  * mb1_transfer - state needed for mailbox 1 communication.
  * @lock:	The transaction lock.
  * @lock:	The transaction lock.
  * @work:	The transaction completion structure.
  * @work:	The transaction completion structure.
+ * @ape_opp:	The current APE OPP.
  * @ack:	Reply ("acknowledge") data.
  * @ack:	Reply ("acknowledge") data.
  */
  */
 static struct {
 static struct {
 	struct mutex lock;
 	struct mutex lock;
 	struct completion work;
 	struct completion work;
+	u8 ape_opp;
 	struct {
 	struct {
 		u8 header;
 		u8 header;
 		u8 arm_opp;
 		u8 arm_opp;
@@ -413,79 +418,102 @@ static struct {
 static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
 static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
 
 
 /* Spinlocks */
 /* Spinlocks */
+static DEFINE_SPINLOCK(prcmu_lock);
 static DEFINE_SPINLOCK(clkout_lock);
 static DEFINE_SPINLOCK(clkout_lock);
-static DEFINE_SPINLOCK(gpiocr_lock);
 
 
 /* Global var to runtime determine TCDM base for v2 or v1 */
 /* Global var to runtime determine TCDM base for v2 or v1 */
 static __iomem void *tcdm_base;
 static __iomem void *tcdm_base;
 
 
 struct clk_mgt {
 struct clk_mgt {
-	unsigned int offset;
+	void __iomem *reg;
 	u32 pllsw;
 	u32 pllsw;
+	int branch;
+	bool clk38div;
+};
+
+enum {
+	PLL_RAW,
+	PLL_FIX,
+	PLL_DIV
 };
 };
 
 
 static DEFINE_SPINLOCK(clk_mgt_lock);
 static DEFINE_SPINLOCK(clk_mgt_lock);
 
 
-#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT_OFF), 0 }
+#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
+	{ (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
 struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
 struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
-	CLK_MGT_ENTRY(SGACLK),
-	CLK_MGT_ENTRY(UARTCLK),
-	CLK_MGT_ENTRY(MSP02CLK),
-	CLK_MGT_ENTRY(MSP1CLK),
-	CLK_MGT_ENTRY(I2CCLK),
-	CLK_MGT_ENTRY(SDMMCCLK),
-	CLK_MGT_ENTRY(SLIMCLK),
-	CLK_MGT_ENTRY(PER1CLK),
-	CLK_MGT_ENTRY(PER2CLK),
-	CLK_MGT_ENTRY(PER3CLK),
-	CLK_MGT_ENTRY(PER5CLK),
-	CLK_MGT_ENTRY(PER6CLK),
-	CLK_MGT_ENTRY(PER7CLK),
-	CLK_MGT_ENTRY(LCDCLK),
-	CLK_MGT_ENTRY(BMLCLK),
-	CLK_MGT_ENTRY(HSITXCLK),
-	CLK_MGT_ENTRY(HSIRXCLK),
-	CLK_MGT_ENTRY(HDMICLK),
-	CLK_MGT_ENTRY(APEATCLK),
-	CLK_MGT_ENTRY(APETRACECLK),
-	CLK_MGT_ENTRY(MCDECLK),
-	CLK_MGT_ENTRY(IPI2CCLK),
-	CLK_MGT_ENTRY(DSIALTCLK),
-	CLK_MGT_ENTRY(DMACLK),
-	CLK_MGT_ENTRY(B2R2CLK),
-	CLK_MGT_ENTRY(TVCLK),
-	CLK_MGT_ENTRY(SSPCLK),
-	CLK_MGT_ENTRY(RNGCLK),
-	CLK_MGT_ENTRY(UICCCLK),
+	CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
+	CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false),
+	CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false),
+	CLK_MGT_ENTRY(DMACLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true),
+	CLK_MGT_ENTRY(TVCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true),
+	CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false),
+};
+
+struct dsiclk {
+	u32 divsel_mask;
+	u32 divsel_shift;
+	u32 divsel;
+};
+
+static struct dsiclk dsiclk[2] = {
+	{
+		.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK,
+		.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT,
+		.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+	},
+	{
+		.divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK,
+		.divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT,
+		.divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+	}
 };
 };
 
 
-static struct regulator *hwacc_regulator[NUM_HW_ACC];
-static struct regulator *hwacc_ret_regulator[NUM_HW_ACC];
-
-static bool hwacc_enabled[NUM_HW_ACC];
-static bool hwacc_ret_enabled[NUM_HW_ACC];
-
-static const char *hwacc_regulator_name[NUM_HW_ACC] = {
-	[HW_ACC_SVAMMDSP]	= "hwacc-sva-mmdsp",
-	[HW_ACC_SVAPIPE]	= "hwacc-sva-pipe",
-	[HW_ACC_SIAMMDSP]	= "hwacc-sia-mmdsp",
-	[HW_ACC_SIAPIPE]	= "hwacc-sia-pipe",
-	[HW_ACC_SGA]		= "hwacc-sga",
-	[HW_ACC_B2R2]		= "hwacc-b2r2",
-	[HW_ACC_MCDE]		= "hwacc-mcde",
-	[HW_ACC_ESRAM1]		= "hwacc-esram1",
-	[HW_ACC_ESRAM2]		= "hwacc-esram2",
-	[HW_ACC_ESRAM3]		= "hwacc-esram3",
-	[HW_ACC_ESRAM4]		= "hwacc-esram4",
+struct dsiescclk {
+	u32 en;
+	u32 div_mask;
+	u32 div_shift;
 };
 };
 
 
-static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
-	[HW_ACC_SVAMMDSP]	= "hwacc-sva-mmdsp-ret",
-	[HW_ACC_SIAMMDSP]	= "hwacc-sia-mmdsp-ret",
-	[HW_ACC_ESRAM1]		= "hwacc-esram1-ret",
-	[HW_ACC_ESRAM2]		= "hwacc-esram2-ret",
-	[HW_ACC_ESRAM3]		= "hwacc-esram3-ret",
-	[HW_ACC_ESRAM4]		= "hwacc-esram4-ret",
+static struct dsiescclk dsiescclk[3] = {
+	{
+		.en = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN,
+		.div_mask = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK,
+		.div_shift = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT,
+	},
+	{
+		.en = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN,
+		.div_mask = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK,
+		.div_shift = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT,
+	},
+	{
+		.en = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN,
+		.div_mask = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK,
+		.div_shift = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT,
+	}
 };
 };
 
 
 /*
 /*
@@ -503,9 +531,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 /* PLLDIV=12, PLLSW=4 (PLLDDR) */
 /* PLLDIV=12, PLLSW=4 (PLLDDR) */
 #define PRCMU_DSI_CLOCK_SETTING		0x0000008C
 #define PRCMU_DSI_CLOCK_SETTING		0x0000008C
 
 
-/* PLLDIV=8, PLLSW=4 (PLLDDR) */
-#define PRCMU_DSI_CLOCK_SETTING_U8400	0x00000088
-
 /* DPI 50000000 Hz */
 /* DPI 50000000 Hz */
 #define PRCMU_DPI_CLOCK_SETTING		((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
 #define PRCMU_DPI_CLOCK_SETTING		((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
 					  (16 << PRCMU_CLK_PLL_DIV_SHIFT))
 					  (16 << PRCMU_CLK_PLL_DIV_SHIFT))
@@ -514,9 +539,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 /* D=101, N=1, R=4, SELDIV2=0 */
 /* D=101, N=1, R=4, SELDIV2=0 */
 #define PRCMU_PLLDSI_FREQ_SETTING	0x00040165
 #define PRCMU_PLLDSI_FREQ_SETTING	0x00040165
 
 
-/* D=70, N=1, R=3, SELDIV2=0 */
-#define PRCMU_PLLDSI_FREQ_SETTING_U8400	0x00030146
-
 #define PRCMU_ENABLE_PLLDSI		0x00000001
 #define PRCMU_ENABLE_PLLDSI		0x00000001
 #define PRCMU_DISABLE_PLLDSI		0x00000000
 #define PRCMU_DISABLE_PLLDSI		0x00000000
 #define PRCMU_RELEASE_RESET_DSS		0x0000400C
 #define PRCMU_RELEASE_RESET_DSS		0x0000400C
@@ -528,30 +550,17 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 
 
 #define PRCMU_PLLDSI_LOCKP_LOCKED	0x3
 #define PRCMU_PLLDSI_LOCKP_LOCKED	0x3
 
 
-static struct {
-	u8 project_number;
-	u8 api_version;
-	u8 func_version;
-	u8 errata;
-} prcmu_version;
-
-
 int db8500_prcmu_enable_dsipll(void)
 int db8500_prcmu_enable_dsipll(void)
 {
 {
 	int i;
 	int i;
-	unsigned int plldsifreq;
 
 
 	/* Clear DSIPLL_RESETN */
 	/* Clear DSIPLL_RESETN */
 	writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
 	writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
 	/* Unclamp DSIPLL in/out */
 	/* Unclamp DSIPLL in/out */
 	writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
 	writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
 
 
-	if (prcmu_is_u8400())
-		plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
-	else
-		plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
 	/* Set DSI PLL FREQ */
 	/* Set DSI PLL FREQ */
-	writel(plldsifreq, PRCM_PLLDSI_FREQ);
+	writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
 	writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
 	writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
 	/* Enable Escape clocks */
 	/* Enable Escape clocks */
 	writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
 	writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
@@ -583,12 +592,6 @@ int db8500_prcmu_disable_dsipll(void)
 int db8500_prcmu_set_display_clocks(void)
 int db8500_prcmu_set_display_clocks(void)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
-	unsigned int dsiclk;
-
-	if (prcmu_is_u8400())
-		dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
-	else
-		dsiclk = PRCMU_DSI_CLOCK_SETTING;
 
 
 	spin_lock_irqsave(&clk_mgt_lock, flags);
 	spin_lock_irqsave(&clk_mgt_lock, flags);
 
 
@@ -596,7 +599,7 @@ int db8500_prcmu_set_display_clocks(void)
 	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
 	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
 		cpu_relax();
 		cpu_relax();
 
 
-	writel(dsiclk, PRCM_HDMICLK_MGT);
+	writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
 	writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
 	writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
 	writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
 	writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
 
 
@@ -608,43 +611,41 @@ int db8500_prcmu_set_display_clocks(void)
 	return 0;
 	return 0;
 }
 }
 
 
-/**
- * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_enable_spi2(void)
+u32 db8500_prcmu_read(unsigned int reg)
+{
+	return readl(_PRCMU_BASE + reg);
+}
+
+void db8500_prcmu_write(unsigned int reg, u32 value)
 {
 {
-	u32 reg;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	spin_lock_irqsave(&gpiocr_lock, flags);
-	reg = readl(PRCM_GPIOCR);
-	writel(reg | PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-	spin_unlock_irqrestore(&gpiocr_lock, flags);
+	spin_lock_irqsave(&prcmu_lock, flags);
+	writel(value, (_PRCMU_BASE + reg));
+	spin_unlock_irqrestore(&prcmu_lock, flags);
 }
 }
 
 
-/**
- * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_disable_spi2(void)
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
 {
 {
-	u32 reg;
+	u32 val;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	spin_lock_irqsave(&gpiocr_lock, flags);
-	reg = readl(PRCM_GPIOCR);
-	writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-	spin_unlock_irqrestore(&gpiocr_lock, flags);
+	spin_lock_irqsave(&prcmu_lock, flags);
+	val = readl(_PRCMU_BASE + reg);
+	val = ((val & ~mask) | (value & mask));
+	writel(val, (_PRCMU_BASE + reg));
+	spin_unlock_irqrestore(&prcmu_lock, flags);
 }
 }
 
 
-bool prcmu_has_arm_maxopp(void)
+struct prcmu_fw_version *prcmu_get_fw_version(void)
 {
 {
-	return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
-		PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
+	return fw_info.valid ? &fw_info.version : NULL;
 }
 }
 
 
-bool prcmu_is_u8400(void)
+bool prcmu_has_arm_maxopp(void)
 {
 {
-	return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
+	return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
+		PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
 }
 }
 
 
 /**
 /**
@@ -787,6 +788,124 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
 	return 0;
 	return 0;
 }
 }
 
 
+u8 db8500_prcmu_get_power_state_result(void)
+{
+	return readb(tcdm_base + PRCM_ACK_MB0_AP_PWRSTTR_STATUS);
+}
+
+/* This function decouple the gic from the prcmu */
+int db8500_prcmu_gic_decouple(void)
+{
+	u32 val = readl(PRCM_A9_MASK_REQ);
+
+	/* Set bit 0 register value to 1 */
+	writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ,
+	       PRCM_A9_MASK_REQ);
+
+	/* Make sure the register is updated */
+	readl(PRCM_A9_MASK_REQ);
+
+	/* Wait a few cycles for the gic mask completion */
+	udelay(1);
+
+	return 0;
+}
+
+/* This function recouple the gic with the prcmu */
+int db8500_prcmu_gic_recouple(void)
+{
+	u32 val = readl(PRCM_A9_MASK_REQ);
+
+	/* Set bit 0 register value to 0 */
+	writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ);
+
+	return 0;
+}
+
+#define PRCMU_GIC_NUMBER_REGS 5
+
+/*
+ * This function checks if there are pending irq on the gic. It only
+ * makes sense if the gic has been decoupled before with the
+ * db8500_prcmu_gic_decouple function. Disabling an interrupt only
+ * disables the forwarding of the interrupt to any CPU interface. It
+ * does not prevent the interrupt from changing state, for example
+ * becoming pending, or active and pending if it is already
+ * active. Hence, we have to check the interrupt is pending *and* is
+ * active.
+ */
+bool db8500_prcmu_gic_pending_irq(void)
+{
+	u32 pr; /* Pending register */
+	u32 er; /* Enable register */
+	void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+	int i;
+
+        /* 5 registers. STI & PPI not skipped */
+	for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
+
+		pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
+		er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+		if (pr & er)
+			return true; /* There is a pending interrupt */
+	}
+
+	return false;
+}
+
+/*
+ * This function checks if there are pending interrupt on the
+ * prcmu which has been delegated to monitor the irqs with the
+ * db8500_prcmu_copy_gic_settings function.
+ */
+bool db8500_prcmu_pending_irq(void)
+{
+	u32 it, im;
+	int i;
+
+	for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+		it = readl(PRCM_ARMITVAL31TO0 + i * 4);
+		im = readl(PRCM_ARMITMSK31TO0 + i * 4);
+		if (it & im)
+			return true; /* There is a pending interrupt */
+	}
+
+	return false;
+}
+
+/*
+ * This function checks if the specified cpu is in in WFI. It's usage
+ * makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
+ * function. Of course passing smp_processor_id() to this function will
+ * always return false...
+ */
+bool db8500_prcmu_is_cpu_in_wfi(int cpu)
+{
+	return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
+		     PRCM_ARM_WFI_STANDBY_WFI0;
+}
+
+/*
+ * This function copies the gic SPI settings to the prcmu in order to
+ * monitor them and abort/finish the retention/off sequence or state.
+ */
+int db8500_prcmu_copy_gic_settings(void)
+{
+	u32 er; /* Enable register */
+	void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+	int i;
+
+        /* We skip the STI and PPI */
+	for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+		er = readl_relaxed(dist_base +
+				   GIC_DIST_ENABLE_SET + (i + 1) * 4);
+		writel(er, PRCM_ARMITMSK31TO0 + i * 4);
+	}
+
+	return 0;
+}
+
 /* This function should only be called while mb0_transfer.lock is held. */
 /* This function should only be called while mb0_transfer.lock is held. */
 static void config_wakeups(void)
 static void config_wakeups(void)
 {
 {
@@ -909,23 +1028,23 @@ int db8500_prcmu_get_arm_opp(void)
 }
 }
 
 
 /**
 /**
- * prcmu_get_ddr_opp - get the current DDR OPP
+ * db8500_prcmu_get_ddr_opp - get the current DDR OPP
  *
  *
  * Returns: the current DDR OPP
  * Returns: the current DDR OPP
  */
  */
-int prcmu_get_ddr_opp(void)
+int db8500_prcmu_get_ddr_opp(void)
 {
 {
 	return readb(PRCM_DDR_SUBSYS_APE_MINBW);
 	return readb(PRCM_DDR_SUBSYS_APE_MINBW);
 }
 }
 
 
 /**
 /**
- * set_ddr_opp - set the appropriate DDR OPP
+ * db8500_set_ddr_opp - set the appropriate DDR OPP
  * @opp: The new DDR operating point to which transition is to be made
  * @opp: The new DDR operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  * Returns: 0 on success, non-zero on failure
  *
  *
  * This function sets the operating point of the DDR.
  * This function sets the operating point of the DDR.
  */
  */
-int prcmu_set_ddr_opp(u8 opp)
+int db8500_prcmu_set_ddr_opp(u8 opp)
 {
 {
 	if (opp < DDR_100_OPP || opp > DDR_25_OPP)
 	if (opp < DDR_100_OPP || opp > DDR_25_OPP)
 		return -EINVAL;
 		return -EINVAL;
@@ -935,25 +1054,82 @@ int prcmu_set_ddr_opp(u8 opp)
 
 
 	return 0;
 	return 0;
 }
 }
+
+/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
+static void request_even_slower_clocks(bool enable)
+{
+	void __iomem *clock_reg[] = {
+		PRCM_ACLK_MGT,
+		PRCM_DMACLK_MGT
+	};
+	unsigned long flags;
+	unsigned int i;
+
+	spin_lock_irqsave(&clk_mgt_lock, flags);
+
+	/* Grab the HW semaphore. */
+	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+		cpu_relax();
+
+	for (i = 0; i < ARRAY_SIZE(clock_reg); i++) {
+		u32 val;
+		u32 div;
+
+		val = readl(clock_reg[i]);
+		div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK);
+		if (enable) {
+			if ((div <= 1) || (div > 15)) {
+				pr_err("prcmu: Bad clock divider %d in %s\n",
+					div, __func__);
+				goto unlock_and_return;
+			}
+			div <<= 1;
+		} else {
+			if (div <= 2)
+				goto unlock_and_return;
+			div >>= 1;
+		}
+		val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) |
+			(div & PRCM_CLK_MGT_CLKPLLDIV_MASK));
+		writel(val, clock_reg[i]);
+	}
+
+unlock_and_return:
+	/* Release the HW semaphore. */
+	writel(0, PRCM_SEM);
+
+	spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
 /**
 /**
- * set_ape_opp - set the appropriate APE OPP
+ * db8500_set_ape_opp - set the appropriate APE OPP
  * @opp: The new APE operating point to which transition is to be made
  * @opp: The new APE operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  * Returns: 0 on success, non-zero on failure
  *
  *
  * This function sets the operating point of the APE.
  * This function sets the operating point of the APE.
  */
  */
-int prcmu_set_ape_opp(u8 opp)
+int db8500_prcmu_set_ape_opp(u8 opp)
 {
 {
 	int r = 0;
 	int r = 0;
 
 
+	if (opp == mb1_transfer.ape_opp)
+		return 0;
+
 	mutex_lock(&mb1_transfer.lock);
 	mutex_lock(&mb1_transfer.lock);
 
 
+	if (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)
+		request_even_slower_clocks(false);
+
+	if ((opp != APE_100_OPP) && (mb1_transfer.ape_opp != APE_100_OPP))
+		goto skip_message;
+
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
 		cpu_relax();
 		cpu_relax();
 
 
 	writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
 	writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
 	writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
 	writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
-	writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+	writeb(((opp == APE_50_PARTLY_25_OPP) ? APE_50_OPP : opp),
+		(tcdm_base + PRCM_REQ_MB1_APE_OPP));
 
 
 	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
 	writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
 	wait_for_completion(&mb1_transfer.work);
 	wait_for_completion(&mb1_transfer.work);
@@ -962,17 +1138,24 @@ int prcmu_set_ape_opp(u8 opp)
 		(mb1_transfer.ack.ape_opp != opp))
 		(mb1_transfer.ack.ape_opp != opp))
 		r = -EIO;
 		r = -EIO;
 
 
+skip_message:
+	if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
+		(r && (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)))
+		request_even_slower_clocks(true);
+	if (!r)
+		mb1_transfer.ape_opp = opp;
+
 	mutex_unlock(&mb1_transfer.lock);
 	mutex_unlock(&mb1_transfer.lock);
 
 
 	return r;
 	return r;
 }
 }
 
 
 /**
 /**
- * prcmu_get_ape_opp - get the current APE OPP
+ * db8500_prcmu_get_ape_opp - get the current APE OPP
  *
  *
  * Returns: the current APE OPP
  * Returns: the current APE OPP
  */
  */
-int prcmu_get_ape_opp(void)
+int db8500_prcmu_get_ape_opp(void)
 {
 {
 	return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
 	return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
 }
 }
@@ -1056,7 +1239,9 @@ static int request_pll(u8 clock, bool enable)
 {
 {
 	int r = 0;
 	int r = 0;
 
 
-	if (clock == PRCMU_PLLSOC1)
+	if (clock == PRCMU_PLLSOC0)
+		clock = (enable ? PLL_SOC0_ON : PLL_SOC0_OFF);
+	else if (clock == PRCMU_PLLSOC1)
 		clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
 		clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
 	else
 	else
 		return -EINVAL;
 		return -EINVAL;
@@ -1080,132 +1265,6 @@ static int request_pll(u8 clock, bool enable)
 	return r;
 	return r;
 }
 }
 
 
-/**
- * prcmu_set_hwacc - set the power state of a h/w accelerator
- * @hwacc_dev: The hardware accelerator (enum hw_acc_dev).
- * @state: The new power state (enum hw_acc_state).
- *
- * This function sets the power state of a hardware accelerator.
- * This function should not be called from interrupt context.
- *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator framework API.
- */
-int prcmu_set_hwacc(u16 hwacc_dev, u8 state)
-{
-	int r = 0;
-	bool ram_retention = false;
-	bool enable, enable_ret;
-
-	/* check argument */
-	BUG_ON(hwacc_dev >= NUM_HW_ACC);
-
-	/* get state of switches */
-	enable = hwacc_enabled[hwacc_dev];
-	enable_ret = hwacc_ret_enabled[hwacc_dev];
-
-	/* set flag if retention is possible */
-	switch (hwacc_dev) {
-	case HW_ACC_SVAMMDSP:
-	case HW_ACC_SIAMMDSP:
-	case HW_ACC_ESRAM1:
-	case HW_ACC_ESRAM2:
-	case HW_ACC_ESRAM3:
-	case HW_ACC_ESRAM4:
-		ram_retention = true;
-		break;
-	}
-
-	/* check argument */
-	BUG_ON(state > HW_ON);
-	BUG_ON(state == HW_OFF_RAMRET && !ram_retention);
-
-	/* modify enable flags */
-	switch (state) {
-	case HW_OFF:
-		enable_ret = false;
-		enable = false;
-		break;
-	case HW_ON:
-		enable = true;
-		break;
-	case HW_OFF_RAMRET:
-		enable_ret = true;
-		enable = false;
-		break;
-	}
-
-	/* get regulator (lazy) */
-	if (hwacc_regulator[hwacc_dev] == NULL) {
-		hwacc_regulator[hwacc_dev] = regulator_get(NULL,
-			hwacc_regulator_name[hwacc_dev]);
-		if (IS_ERR(hwacc_regulator[hwacc_dev])) {
-			pr_err("prcmu: failed to get supply %s\n",
-				hwacc_regulator_name[hwacc_dev]);
-			r = PTR_ERR(hwacc_regulator[hwacc_dev]);
-			goto out;
-		}
-	}
-
-	if (ram_retention) {
-		if (hwacc_ret_regulator[hwacc_dev] == NULL) {
-			hwacc_ret_regulator[hwacc_dev] = regulator_get(NULL,
-				hwacc_ret_regulator_name[hwacc_dev]);
-			if (IS_ERR(hwacc_ret_regulator[hwacc_dev])) {
-				pr_err("prcmu: failed to get supply %s\n",
-					hwacc_ret_regulator_name[hwacc_dev]);
-				r = PTR_ERR(hwacc_ret_regulator[hwacc_dev]);
-				goto out;
-			}
-		}
-	}
-
-	/* set regulators */
-	if (ram_retention) {
-		if (enable_ret && !hwacc_ret_enabled[hwacc_dev]) {
-			r = regulator_enable(hwacc_ret_regulator[hwacc_dev]);
-			if (r < 0) {
-				pr_err("prcmu_set_hwacc: ret enable failed\n");
-				goto out;
-			}
-			hwacc_ret_enabled[hwacc_dev] = true;
-		}
-	}
-
-	if (enable && !hwacc_enabled[hwacc_dev]) {
-		r = regulator_enable(hwacc_regulator[hwacc_dev]);
-		if (r < 0) {
-			pr_err("prcmu_set_hwacc: enable failed\n");
-			goto out;
-		}
-		hwacc_enabled[hwacc_dev] = true;
-	}
-
-	if (!enable && hwacc_enabled[hwacc_dev]) {
-		r = regulator_disable(hwacc_regulator[hwacc_dev]);
-		if (r < 0) {
-			pr_err("prcmu_set_hwacc: disable failed\n");
-			goto out;
-		}
-		hwacc_enabled[hwacc_dev] = false;
-	}
-
-	if (ram_retention) {
-		if (!enable_ret && hwacc_ret_enabled[hwacc_dev]) {
-			r = regulator_disable(hwacc_ret_regulator[hwacc_dev]);
-			if (r < 0) {
-				pr_err("prcmu_set_hwacc: ret disable failed\n");
-				goto out;
-			}
-			hwacc_ret_enabled[hwacc_dev] = false;
-		}
-	}
-
-out:
-	return r;
-}
-EXPORT_SYMBOL(prcmu_set_hwacc);
-
 /**
 /**
  * db8500_prcmu_set_epod - set the state of a EPOD (power domain)
  * db8500_prcmu_set_epod - set the state of a EPOD (power domain)
  * @epod_id: The EPOD to set
  * @epod_id: The EPOD to set
@@ -1375,7 +1434,7 @@ static int request_timclk(bool enable)
 	return 0;
 	return 0;
 }
 }
 
 
-static int request_reg_clock(u8 clock, bool enable)
+static int request_clock(u8 clock, bool enable)
 {
 {
 	u32 val;
 	u32 val;
 	unsigned long flags;
 	unsigned long flags;
@@ -1386,14 +1445,14 @@ static int request_reg_clock(u8 clock, bool enable)
 	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
 	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
 		cpu_relax();
 		cpu_relax();
 
 
-	val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+	val = readl(clk_mgt[clock].reg);
 	if (enable) {
 	if (enable) {
 		val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
 		val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
 	} else {
 	} else {
 		clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
 		clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
 		val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
 		val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
 	}
 	}
-	writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+	writel(val, clk_mgt[clock].reg);
 
 
 	/* Release the HW semaphore. */
 	/* Release the HW semaphore. */
 	writel(0, PRCM_SEM);
 	writel(0, PRCM_SEM);
@@ -1413,7 +1472,7 @@ static int request_sga_clock(u8 clock, bool enable)
 		writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
 		writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
 	}
 	}
 
 
-	ret = request_reg_clock(clock, enable);
+	ret = request_clock(clock, enable);
 
 
 	if (!ret && !enable) {
 	if (!ret && !enable) {
 		val = readl(PRCM_CGATING_BYPASS);
 		val = readl(PRCM_CGATING_BYPASS);
@@ -1423,6 +1482,78 @@ static int request_sga_clock(u8 clock, bool enable)
 	return ret;
 	return ret;
 }
 }
 
 
+static inline bool plldsi_locked(void)
+{
+	return (readl(PRCM_PLLDSI_LOCKP) &
+		(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+		 PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3)) ==
+		(PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+		 PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3);
+}
+
+static int request_plldsi(bool enable)
+{
+	int r = 0;
+	u32 val;
+
+	writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+		PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI), (enable ?
+		PRCM_MMIP_LS_CLAMP_CLR : PRCM_MMIP_LS_CLAMP_SET));
+
+	val = readl(PRCM_PLLDSI_ENABLE);
+	if (enable)
+		val |= PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+	else
+		val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+	writel(val, PRCM_PLLDSI_ENABLE);
+
+	if (enable) {
+		unsigned int i;
+		bool locked = plldsi_locked();
+
+		for (i = 10; !locked && (i > 0); --i) {
+			udelay(100);
+			locked = plldsi_locked();
+		}
+		if (locked) {
+			writel(PRCM_APE_RESETN_DSIPLL_RESETN,
+				PRCM_APE_RESETN_SET);
+		} else {
+			writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+				PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI),
+				PRCM_MMIP_LS_CLAMP_SET);
+			val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+			writel(val, PRCM_PLLDSI_ENABLE);
+			r = -EAGAIN;
+		}
+	} else {
+		writel(PRCM_APE_RESETN_DSIPLL_RESETN, PRCM_APE_RESETN_CLR);
+	}
+	return r;
+}
+
+static int request_dsiclk(u8 n, bool enable)
+{
+	u32 val;
+
+	val = readl(PRCM_DSI_PLLOUT_SEL);
+	val &= ~dsiclk[n].divsel_mask;
+	val |= ((enable ? dsiclk[n].divsel : PRCM_DSI_PLLOUT_SEL_OFF) <<
+		dsiclk[n].divsel_shift);
+	writel(val, PRCM_DSI_PLLOUT_SEL);
+	return 0;
+}
+
+static int request_dsiescclk(u8 n, bool enable)
+{
+	u32 val;
+
+	val = readl(PRCM_DSITVCLK_DIV);
+	enable ? (val |= dsiescclk[n].en) : (val &= ~dsiescclk[n].en);
+	writel(val, PRCM_DSITVCLK_DIV);
+	return 0;
+}
+
 /**
 /**
  * db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
  * db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
  * @clock:      The clock for which the request is made.
  * @clock:      The clock for which the request is made.
@@ -1433,21 +1564,435 @@ static int request_sga_clock(u8 clock, bool enable)
  */
  */
 int db8500_prcmu_request_clock(u8 clock, bool enable)
 int db8500_prcmu_request_clock(u8 clock, bool enable)
 {
 {
-	switch(clock) {
-	case PRCMU_SGACLK:
+	if (clock == PRCMU_SGACLK)
 		return request_sga_clock(clock, enable);
 		return request_sga_clock(clock, enable);
-	case PRCMU_TIMCLK:
+	else if (clock < PRCMU_NUM_REG_CLOCKS)
+		return request_clock(clock, enable);
+	else if (clock == PRCMU_TIMCLK)
 		return request_timclk(enable);
 		return request_timclk(enable);
-	case PRCMU_SYSCLK:
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		return request_dsiclk((clock - PRCMU_DSI0CLK), enable);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		return request_dsiescclk((clock - PRCMU_DSI0ESCCLK), enable);
+	else if (clock == PRCMU_PLLDSI)
+		return request_plldsi(enable);
+	else if (clock == PRCMU_SYSCLK)
 		return request_sysclk(enable);
 		return request_sysclk(enable);
-	case PRCMU_PLLSOC1:
+	else if ((clock == PRCMU_PLLSOC0) || (clock == PRCMU_PLLSOC1))
 		return request_pll(clock, enable);
 		return request_pll(clock, enable);
+	else
+		return -EINVAL;
+}
+
+static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
+	int branch)
+{
+	u64 rate;
+	u32 val;
+	u32 d;
+	u32 div = 1;
+
+	val = readl(reg);
+
+	rate = src_rate;
+	rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT);
+
+	d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT);
+	if (d > 1)
+		div *= d;
+
+	d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT);
+	if (d > 1)
+		div *= d;
+
+	if (val & PRCM_PLL_FREQ_SELDIV2)
+		div *= 2;
+
+	if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
+		(val & PRCM_PLL_FREQ_DIV2EN) &&
+		((reg == PRCM_PLLSOC0_FREQ) ||
+		 (reg == PRCM_PLLDDR_FREQ))))
+		div *= 2;
+
+	(void)do_div(rate, div);
+
+	return (unsigned long)rate;
+}
+
+#define ROOT_CLOCK_RATE 38400000
+
+static unsigned long clock_rate(u8 clock)
+{
+	u32 val;
+	u32 pllsw;
+	unsigned long rate = ROOT_CLOCK_RATE;
+
+	val = readl(clk_mgt[clock].reg);
+
+	if (val & PRCM_CLK_MGT_CLK38) {
+		if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV))
+			rate /= 2;
+		return rate;
+	}
+
+	val |= clk_mgt[clock].pllsw;
+	pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+
+	if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+		rate = pll_rate(PRCM_PLLSOC0_FREQ, rate, clk_mgt[clock].branch);
+	else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+		rate = pll_rate(PRCM_PLLSOC1_FREQ, rate, clk_mgt[clock].branch);
+	else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_DDR)
+		rate = pll_rate(PRCM_PLLDDR_FREQ, rate, clk_mgt[clock].branch);
+	else
+		return 0;
+
+	if ((clock == PRCMU_SGACLK) &&
+		(val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) {
+		u64 r = (rate * 10);
+
+		(void)do_div(r, 25);
+		return (unsigned long)r;
+	}
+	val &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
+	if (val)
+		return rate / val;
+	else
+		return 0;
+}
+
+static unsigned long dsiclk_rate(u8 n)
+{
+	u32 divsel;
+	u32 div = 1;
+
+	divsel = readl(PRCM_DSI_PLLOUT_SEL);
+	divsel = ((divsel & dsiclk[n].divsel_mask) >> dsiclk[n].divsel_shift);
+
+	if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
+		divsel = dsiclk[n].divsel;
+
+	switch (divsel) {
+	case PRCM_DSI_PLLOUT_SEL_PHI_4:
+		div *= 2;
+	case PRCM_DSI_PLLOUT_SEL_PHI_2:
+		div *= 2;
+	case PRCM_DSI_PLLOUT_SEL_PHI:
+		return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+			PLL_RAW) / div;
 	default:
 	default:
-		break;
+		return 0;
+	}
+}
+
+static unsigned long dsiescclk_rate(u8 n)
+{
+	u32 div;
+
+	div = readl(PRCM_DSITVCLK_DIV);
+	div = ((div & dsiescclk[n].div_mask) >> (dsiescclk[n].div_shift));
+	return clock_rate(PRCMU_TVCLK) / max((u32)1, div);
+}
+
+unsigned long prcmu_clock_rate(u8 clock)
+{
+	if (clock < PRCMU_NUM_REG_CLOCKS)
+		return clock_rate(clock);
+	else if (clock == PRCMU_TIMCLK)
+		return ROOT_CLOCK_RATE / 16;
+	else if (clock == PRCMU_SYSCLK)
+		return ROOT_CLOCK_RATE;
+	else if (clock == PRCMU_PLLSOC0)
+		return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+	else if (clock == PRCMU_PLLSOC1)
+		return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+	else if (clock == PRCMU_PLLDDR)
+		return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+	else if (clock == PRCMU_PLLDSI)
+		return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+			PLL_RAW);
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		return dsiclk_rate(clock - PRCMU_DSI0CLK);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		return dsiescclk_rate(clock - PRCMU_DSI0ESCCLK);
+	else
+		return 0;
+}
+
+static unsigned long clock_source_rate(u32 clk_mgt_val, int branch)
+{
+	if (clk_mgt_val & PRCM_CLK_MGT_CLK38)
+		return ROOT_CLOCK_RATE;
+	clk_mgt_val &= PRCM_CLK_MGT_CLKPLLSW_MASK;
+	if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+		return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, branch);
+	else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+		return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, branch);
+	else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_DDR)
+		return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, branch);
+	else
+		return 0;
+}
+
+static u32 clock_divider(unsigned long src_rate, unsigned long rate)
+{
+	u32 div;
+
+	div = (src_rate / rate);
+	if (div == 0)
+		return 1;
+	if (rate < (src_rate / div))
+		div++;
+	return div;
+}
+
+static long round_clock_rate(u8 clock, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+	unsigned long src_rate;
+	long rounded_rate;
+
+	val = readl(clk_mgt[clock].reg);
+	src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+		clk_mgt[clock].branch);
+	div = clock_divider(src_rate, rate);
+	if (val & PRCM_CLK_MGT_CLK38) {
+		if (clk_mgt[clock].clk38div) {
+			if (div > 2)
+				div = 2;
+		} else {
+			div = 1;
+		}
+	} else if ((clock == PRCMU_SGACLK) && (div == 3)) {
+		u64 r = (src_rate * 10);
+
+		(void)do_div(r, 25);
+		if (r <= rate)
+			return (unsigned long)r;
+	}
+	rounded_rate = (src_rate / min(div, (u32)31));
+
+	return rounded_rate;
+}
+
+#define MIN_PLL_VCO_RATE 600000000ULL
+#define MAX_PLL_VCO_RATE 1680640000ULL
+
+static long round_plldsi_rate(unsigned long rate)
+{
+	long rounded_rate = 0;
+	unsigned long src_rate;
+	unsigned long rem;
+	u32 r;
+
+	src_rate = clock_rate(PRCMU_HDMICLK);
+	rem = rate;
+
+	for (r = 7; (rem > 0) && (r > 0); r--) {
+		u64 d;
+
+		d = (r * rate);
+		(void)do_div(d, src_rate);
+		if (d < 6)
+			d = 6;
+		else if (d > 255)
+			d = 255;
+		d *= src_rate;
+		if (((2 * d) < (r * MIN_PLL_VCO_RATE)) ||
+			((r * MAX_PLL_VCO_RATE) < (2 * d)))
+			continue;
+		(void)do_div(d, r);
+		if (rate < d) {
+			if (rounded_rate == 0)
+				rounded_rate = (long)d;
+			break;
+		}
+		if ((rate - d) < rem) {
+			rem = (rate - d);
+			rounded_rate = (long)d;
+		}
+	}
+	return rounded_rate;
+}
+
+static long round_dsiclk_rate(unsigned long rate)
+{
+	u32 div;
+	unsigned long src_rate;
+	long rounded_rate;
+
+	src_rate = pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+		PLL_RAW);
+	div = clock_divider(src_rate, rate);
+	rounded_rate = (src_rate / ((div > 2) ? 4 : div));
+
+	return rounded_rate;
+}
+
+static long round_dsiescclk_rate(unsigned long rate)
+{
+	u32 div;
+	unsigned long src_rate;
+	long rounded_rate;
+
+	src_rate = clock_rate(PRCMU_TVCLK);
+	div = clock_divider(src_rate, rate);
+	rounded_rate = (src_rate / min(div, (u32)255));
+
+	return rounded_rate;
+}
+
+long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+	if (clock < PRCMU_NUM_REG_CLOCKS)
+		return round_clock_rate(clock, rate);
+	else if (clock == PRCMU_PLLDSI)
+		return round_plldsi_rate(rate);
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		return round_dsiclk_rate(rate);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		return round_dsiescclk_rate(rate);
+	else
+		return (long)prcmu_clock_rate(clock);
+}
+
+static void set_clock_rate(u8 clock, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+	unsigned long src_rate;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk_mgt_lock, flags);
+
+	/* Grab the HW semaphore. */
+	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+		cpu_relax();
+
+	val = readl(clk_mgt[clock].reg);
+	src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+		clk_mgt[clock].branch);
+	div = clock_divider(src_rate, rate);
+	if (val & PRCM_CLK_MGT_CLK38) {
+		if (clk_mgt[clock].clk38div) {
+			if (div > 1)
+				val |= PRCM_CLK_MGT_CLK38DIV;
+			else
+				val &= ~PRCM_CLK_MGT_CLK38DIV;
+		}
+	} else if (clock == PRCMU_SGACLK) {
+		val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK |
+			PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN);
+		if (div == 3) {
+			u64 r = (src_rate * 10);
+
+			(void)do_div(r, 25);
+			if (r <= rate) {
+				val |= PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN;
+				div = 0;
+			}
+		}
+		val |= min(div, (u32)31);
+	} else {
+		val &= ~PRCM_CLK_MGT_CLKPLLDIV_MASK;
+		val |= min(div, (u32)31);
+	}
+	writel(val, clk_mgt[clock].reg);
+
+	/* Release the HW semaphore. */
+	writel(0, PRCM_SEM);
+
+	spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
+static int set_plldsi_rate(unsigned long rate)
+{
+	unsigned long src_rate;
+	unsigned long rem;
+	u32 pll_freq = 0;
+	u32 r;
+
+	src_rate = clock_rate(PRCMU_HDMICLK);
+	rem = rate;
+
+	for (r = 7; (rem > 0) && (r > 0); r--) {
+		u64 d;
+		u64 hwrate;
+
+		d = (r * rate);
+		(void)do_div(d, src_rate);
+		if (d < 6)
+			d = 6;
+		else if (d > 255)
+			d = 255;
+		hwrate = (d * src_rate);
+		if (((2 * hwrate) < (r * MIN_PLL_VCO_RATE)) ||
+			((r * MAX_PLL_VCO_RATE) < (2 * hwrate)))
+			continue;
+		(void)do_div(hwrate, r);
+		if (rate < hwrate) {
+			if (pll_freq == 0)
+				pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+					(r << PRCM_PLL_FREQ_R_SHIFT));
+			break;
+		}
+		if ((rate - hwrate) < rem) {
+			rem = (rate - hwrate);
+			pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+				(r << PRCM_PLL_FREQ_R_SHIFT));
+		}
 	}
 	}
+	if (pll_freq == 0)
+		return -EINVAL;
+
+	pll_freq |= (1 << PRCM_PLL_FREQ_N_SHIFT);
+	writel(pll_freq, PRCM_PLLDSI_FREQ);
+
+	return 0;
+}
+
+static void set_dsiclk_rate(u8 n, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+
+	div = clock_divider(pll_rate(PRCM_PLLDSI_FREQ,
+			clock_rate(PRCMU_HDMICLK), PLL_RAW), rate);
+
+	dsiclk[n].divsel = (div == 1) ? PRCM_DSI_PLLOUT_SEL_PHI :
+			   (div == 2) ? PRCM_DSI_PLLOUT_SEL_PHI_2 :
+			   /* else */	PRCM_DSI_PLLOUT_SEL_PHI_4;
+
+	val = readl(PRCM_DSI_PLLOUT_SEL);
+	val &= ~dsiclk[n].divsel_mask;
+	val |= (dsiclk[n].divsel << dsiclk[n].divsel_shift);
+	writel(val, PRCM_DSI_PLLOUT_SEL);
+}
+
+static void set_dsiescclk_rate(u8 n, unsigned long rate)
+{
+	u32 val;
+	u32 div;
+
+	div = clock_divider(clock_rate(PRCMU_TVCLK), rate);
+	val = readl(PRCM_DSITVCLK_DIV);
+	val &= ~dsiescclk[n].div_mask;
+	val |= (min(div, (u32)255) << dsiescclk[n].div_shift);
+	writel(val, PRCM_DSITVCLK_DIV);
+}
+
+int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
 	if (clock < PRCMU_NUM_REG_CLOCKS)
 	if (clock < PRCMU_NUM_REG_CLOCKS)
-		return request_reg_clock(clock, enable);
-	return -EINVAL;
+		set_clock_rate(clock, rate);
+	else if (clock == PRCMU_PLLDSI)
+		return set_plldsi_rate(rate);
+	else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+		set_dsiclk_rate((clock - PRCMU_DSI0CLK), rate);
+	else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+		set_dsiescclk_rate((clock - PRCMU_DSI0ESCCLK), rate);
+	return 0;
 }
 }
 
 
 int db8500_prcmu_config_esram0_deep_sleep(u8 state)
 int db8500_prcmu_config_esram0_deep_sleep(u8 state)
@@ -1476,7 +2021,7 @@ int db8500_prcmu_config_esram0_deep_sleep(u8 state)
 	return 0;
 	return 0;
 }
 }
 
 
-int prcmu_config_hotdog(u8 threshold)
+int db8500_prcmu_config_hotdog(u8 threshold)
 {
 {
 	mutex_lock(&mb4_transfer.lock);
 	mutex_lock(&mb4_transfer.lock);
 
 
@@ -1494,7 +2039,7 @@ int prcmu_config_hotdog(u8 threshold)
 	return 0;
 	return 0;
 }
 }
 
 
-int prcmu_config_hotmon(u8 low, u8 high)
+int db8500_prcmu_config_hotmon(u8 low, u8 high)
 {
 {
 	mutex_lock(&mb4_transfer.lock);
 	mutex_lock(&mb4_transfer.lock);
 
 
@@ -1533,7 +2078,7 @@ static int config_hot_period(u16 val)
 	return 0;
 	return 0;
 }
 }
 
 
-int prcmu_start_temp_sense(u16 cycles32k)
+int db8500_prcmu_start_temp_sense(u16 cycles32k)
 {
 {
 	if (cycles32k == 0xFFFF)
 	if (cycles32k == 0xFFFF)
 		return -EINVAL;
 		return -EINVAL;
@@ -1541,7 +2086,7 @@ int prcmu_start_temp_sense(u16 cycles32k)
 	return config_hot_period(cycles32k);
 	return config_hot_period(cycles32k);
 }
 }
 
 
-int prcmu_stop_temp_sense(void)
+int db8500_prcmu_stop_temp_sense(void)
 {
 {
 	return config_hot_period(0xFFFF);
 	return config_hot_period(0xFFFF);
 }
 }
@@ -1570,7 +2115,7 @@ static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
 
 
 }
 }
 
 
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
 {
 	BUG_ON(num == 0 || num > 0xf);
 	BUG_ON(num == 0 || num > 0xf);
 	return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
 	return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
@@ -1578,17 +2123,17 @@ int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 			    A9WDOG_AUTO_OFF_DIS);
 			    A9WDOG_AUTO_OFF_DIS);
 }
 }
 
 
-int prcmu_enable_a9wdog(u8 id)
+int db8500_prcmu_enable_a9wdog(u8 id)
 {
 {
 	return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
 	return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
 }
 }
 
 
-int prcmu_disable_a9wdog(u8 id)
+int db8500_prcmu_disable_a9wdog(u8 id)
 {
 {
 	return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
 	return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
 }
 }
 
 
-int prcmu_kick_a9wdog(u8 id)
+int db8500_prcmu_kick_a9wdog(u8 id)
 {
 {
 	return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
 	return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
 }
 }
@@ -1596,16 +2141,8 @@ int prcmu_kick_a9wdog(u8 id)
 /*
 /*
  * timeout is 28 bit, in ms.
  * timeout is 28 bit, in ms.
  */
  */
-#define MAX_WATCHDOG_TIMEOUT 131000
-int prcmu_load_a9wdog(u8 id, u32 timeout)
+int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
 {
 {
-	if (timeout > MAX_WATCHDOG_TIMEOUT)
-		/*
-		 * Due to calculation bug in prcmu fw, timeouts
-		 * can't be bigger than 131 seconds.
-		 */
-		return -EINVAL;
-
 	return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
 	return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
 			    (id & A9WDOG_ID_MASK) |
 			    (id & A9WDOG_ID_MASK) |
 			    /*
 			    /*
@@ -1618,41 +2155,6 @@ int prcmu_load_a9wdog(u8 id, u32 timeout)
 			    (u8)((timeout >> 20) & 0xff));
 			    (u8)((timeout >> 20) & 0xff));
 }
 }
 
 
-/**
- * prcmu_set_clock_divider() - Configure the clock divider.
- * @clock:	The clock for which the request is made.
- * @divider:	The clock divider. (< 32)
- *
- * This function should only be used by the clock implementation.
- * Do not use it from any other place!
- */
-int prcmu_set_clock_divider(u8 clock, u8 divider)
-{
-	u32 val;
-	unsigned long flags;
-
-	if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
-		return -EINVAL;
-
-	spin_lock_irqsave(&clk_mgt_lock, flags);
-
-	/* Grab the HW semaphore. */
-	while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
-		cpu_relax();
-
-	val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
-	val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
-	val |= (u32)divider;
-	writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
-
-	/* Release the HW semaphore. */
-	writel(0, PRCM_SEM);
-
-	spin_unlock_irqrestore(&clk_mgt_lock, flags);
-
-	return 0;
-}
-
 /**
 /**
  * prcmu_abb_read() - Read register value(s) from the ABB.
  * prcmu_abb_read() - Read register value(s) from the ABB.
  * @slave:	The I2C slave address.
  * @slave:	The I2C slave address.
@@ -1675,6 +2177,7 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
 		cpu_relax();
 		cpu_relax();
 
 
+	writeb(0, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
 	writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
 	writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
 	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
 	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
 	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
 	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1700,16 +2203,19 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
 }
 }
 
 
 /**
 /**
- * prcmu_abb_write() - Write register value(s) to the ABB.
+ * prcmu_abb_write_masked() - Write masked register value(s) to the ABB.
  * @slave:	The I2C slave address.
  * @slave:	The I2C slave address.
  * @reg:	The (start) register address.
  * @reg:	The (start) register address.
  * @value:	The value(s) to write.
  * @value:	The value(s) to write.
+ * @mask:	The mask(s) to use.
  * @size:	The number of registers to write.
  * @size:	The number of registers to write.
  *
  *
- * Reads register value(s) from the ABB.
+ * Writes masked register value(s) to the ABB.
+ * For each @value, only the bits set to 1 in the corresponding @mask
+ * will be written. The other bits are not changed.
  * @size has to be 1 for the current firmware version.
  * @size has to be 1 for the current firmware version.
  */
  */
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size)
 {
 {
 	int r;
 	int r;
 
 
@@ -1721,6 +2227,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
 	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
 		cpu_relax();
 		cpu_relax();
 
 
+	writeb(~*mask, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
 	writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
 	writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
 	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
 	writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
 	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
 	writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1742,6 +2249,23 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
 	return r;
 	return r;
 }
 }
 
 
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:	The I2C slave address.
+ * @reg:	The (start) register address.
+ * @value:	The value(s) to write.
+ * @size:	The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+	u8 mask = ~0;
+
+	return prcmu_abb_write_masked(slave, reg, value, &mask, size);
+}
+
 /**
 /**
  * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
  * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
  */
  */
@@ -1850,9 +2374,9 @@ u16 db8500_prcmu_get_reset_code(void)
 }
 }
 
 
 /**
 /**
- * prcmu_reset_modem - ask the PRCMU to reset modem
+ * db8500_prcmu_reset_modem - ask the PRCMU to reset modem
  */
  */
-void prcmu_modem_reset(void)
+void db8500_prcmu_modem_reset(void)
 {
 {
 	mutex_lock(&mb1_transfer.lock);
 	mutex_lock(&mb1_transfer.lock);
 
 
@@ -2099,6 +2623,26 @@ static struct irq_chip prcmu_irq_chip = {
 	.irq_unmask	= prcmu_irq_unmask,
 	.irq_unmask	= prcmu_irq_unmask,
 };
 };
 
 
+static char *fw_project_name(u8 project)
+{
+	switch (project) {
+	case PRCMU_FW_PROJECT_U8500:
+		return "U8500";
+	case PRCMU_FW_PROJECT_U8500_C2:
+		return "U8500 C2";
+	case PRCMU_FW_PROJECT_U9500:
+		return "U9500";
+	case PRCMU_FW_PROJECT_U9500_C2:
+		return "U9500 C2";
+	case PRCMU_FW_PROJECT_U8520:
+		return "U8520";
+	case PRCMU_FW_PROJECT_U8420:
+		return "U8420";
+	default:
+		return "Unknown";
+	}
+}
+
 void __init db8500_prcmu_early_init(void)
 void __init db8500_prcmu_early_init(void)
 {
 {
 	unsigned int i;
 	unsigned int i;
@@ -2108,11 +2652,13 @@ void __init db8500_prcmu_early_init(void)
 		if (tcpm_base != NULL) {
 		if (tcpm_base != NULL) {
 			u32 version;
 			u32 version;
 			version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
 			version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
-			prcmu_version.project_number = version & 0xFF;
-			prcmu_version.api_version = (version >> 8) & 0xFF;
-			prcmu_version.func_version = (version >> 16) & 0xFF;
-			prcmu_version.errata = (version >> 24) & 0xFF;
-			pr_info("PRCMU firmware version %d.%d.%d\n",
+			fw_info.version.project = version & 0xFF;
+			fw_info.version.api_version = (version >> 8) & 0xFF;
+			fw_info.version.func_version = (version >> 16) & 0xFF;
+			fw_info.version.errata = (version >> 24) & 0xFF;
+			fw_info.valid = true;
+			pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
+				fw_project_name(fw_info.version.project),
 				(version >> 8) & 0xFF, (version >> 16) & 0xFF,
 				(version >> 8) & 0xFF, (version >> 16) & 0xFF,
 				(version >> 24) & 0xFF);
 				(version >> 24) & 0xFF);
 			iounmap(tcpm_base);
 			iounmap(tcpm_base);
@@ -2130,6 +2676,7 @@ void __init db8500_prcmu_early_init(void)
 	init_completion(&mb0_transfer.ac_wake_work);
 	init_completion(&mb0_transfer.ac_wake_work);
 	mutex_init(&mb1_transfer.lock);
 	mutex_init(&mb1_transfer.lock);
 	init_completion(&mb1_transfer.work);
 	init_completion(&mb1_transfer.work);
+	mb1_transfer.ape_opp = APE_NO_CHANGE;
 	mutex_init(&mb2_transfer.lock);
 	mutex_init(&mb2_transfer.lock);
 	init_completion(&mb2_transfer.work);
 	init_completion(&mb2_transfer.work);
 	spin_lock_init(&mb2_transfer.auto_pm_lock);
 	spin_lock_init(&mb2_transfer.auto_pm_lock);
@@ -2154,7 +2701,7 @@ void __init db8500_prcmu_early_init(void)
 	}
 	}
 }
 }
 
 
-static void __init db8500_prcmu_init_clkforce(void)
+static void __init init_prcm_registers(void)
 {
 {
 	u32 val;
 	u32 val;
 
 
@@ -2186,19 +2733,17 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = {
 	REGULATOR_SUPPLY("vcore", "uart1"),
 	REGULATOR_SUPPLY("vcore", "uart1"),
 	REGULATOR_SUPPLY("vcore", "uart2"),
 	REGULATOR_SUPPLY("vcore", "uart2"),
 	REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
 	REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+	REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
 };
 };
 
 
 static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
 static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
-	/* CG2900 and CW1200 power to off-chip peripherals */
-	REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
-	REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
 	REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
 	REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
 	/* AV8100 regulator */
 	/* AV8100 regulator */
 	REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
 	REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
 };
 };
 
 
 static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
 static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
-	REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+	REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
 	REGULATOR_SUPPLY("vsupply", "mcde"),
 	REGULATOR_SUPPLY("vsupply", "mcde"),
 };
 };
 
 
@@ -2235,6 +2780,7 @@ static struct regulator_consumer_supply db8500_esram12_consumers[] = {
 static struct regulator_consumer_supply db8500_esram34_consumers[] = {
 static struct regulator_consumer_supply db8500_esram34_consumers[] = {
 	REGULATOR_SUPPLY("v-esram34", "mcde"),
 	REGULATOR_SUPPLY("v-esram34", "mcde"),
 	REGULATOR_SUPPLY("esram34", "cm_control"),
 	REGULATOR_SUPPLY("esram34", "cm_control"),
+	REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
 };
 };
 
 
 static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
 static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
@@ -2291,7 +2837,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
 		},
 		},
 	},
 	},
 	[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
 	[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 		.constraints = {
 			.name = "db8500-sva-mmdsp",
 			.name = "db8500-sva-mmdsp",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2307,7 +2853,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
 		},
 		},
 	},
 	},
 	[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
 	[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 		.constraints = {
 			.name = "db8500-sva-pipe",
 			.name = "db8500-sva-pipe",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2316,7 +2862,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
 		.num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
 		.num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
 	},
 	},
 	[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
 	[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 		.constraints = {
 			.name = "db8500-sia-mmdsp",
 			.name = "db8500-sia-mmdsp",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2331,7 +2877,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
 		},
 		},
 	},
 	},
 	[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
 	[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
-		.supply_regulator = "db8500-vape",
+		/* dependency to u8500-vape is handled outside regulator framework */
 		.constraints = {
 		.constraints = {
 			.name = "db8500-sia-pipe",
 			.name = "db8500-sia-pipe",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2359,7 +2905,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
 		.num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
 		.num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
 	},
 	},
 	[DB8500_REGULATOR_SWITCH_ESRAM12] = {
 	[DB8500_REGULATOR_SWITCH_ESRAM12] = {
-		.supply_regulator = "db8500-vape",
+		/*
+		 * esram12 is set in retention and supplied by Vsafe when Vape is off,
+		 * no need to hold Vape
+		 */
 		.constraints = {
 		.constraints = {
 			.name = "db8500-esram12",
 			.name = "db8500-esram12",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2374,7 +2923,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
 		},
 		},
 	},
 	},
 	[DB8500_REGULATOR_SWITCH_ESRAM34] = {
 	[DB8500_REGULATOR_SWITCH_ESRAM34] = {
-		.supply_regulator = "db8500-vape",
+		/*
+		 * esram34 is set in retention and supplied by Vsafe when Vape is off,
+		 * no need to hold Vape
+		 */
 		.constraints = {
 		.constraints = {
 			.name = "db8500-esram34",
 			.name = "db8500-esram34",
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2412,7 +2964,7 @@ static int __init db8500_prcmu_probe(struct platform_device *pdev)
 	if (ux500_is_svp())
 	if (ux500_is_svp())
 		return -ENODEV;
 		return -ENODEV;
 
 
-	db8500_prcmu_init_clkforce();
+	init_prcm_registers();
 
 
 	/* Clean up the mailbox interrupts after pre-kernel code. */
 	/* Clean up the mailbox interrupts after pre-kernel code. */
 	writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
 	writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);

+ 88 - 42
drivers/mfd/dbx500-prcmu-regs.h

@@ -17,41 +17,41 @@
 
 
 #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
 #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
 
 
-#define PRCM_SVACLK_MGT_OFF		0x008
-#define PRCM_SIACLK_MGT_OFF		0x00C
-#define PRCM_SGACLK_MGT_OFF		0x014
-#define PRCM_UARTCLK_MGT_OFF		0x018
-#define PRCM_MSP02CLK_MGT_OFF		0x01C
-#define PRCM_I2CCLK_MGT_OFF		0x020
-#define PRCM_SDMMCCLK_MGT_OFF		0x024
-#define PRCM_SLIMCLK_MGT_OFF		0x028
-#define PRCM_PER1CLK_MGT_OFF		0x02C
-#define PRCM_PER2CLK_MGT_OFF		0x030
-#define PRCM_PER3CLK_MGT_OFF		0x034
-#define PRCM_PER5CLK_MGT_OFF		0x038
-#define PRCM_PER6CLK_MGT_OFF		0x03C
-#define PRCM_PER7CLK_MGT_OFF		0x040
-#define PRCM_PWMCLK_MGT_OFF		0x044 /* for DB5500 */
-#define PRCM_IRDACLK_MGT_OFF		0x048 /* for DB5500 */
-#define PRCM_IRRCCLK_MGT_OFF		0x04C /* for DB5500 */
-#define PRCM_LCDCLK_MGT_OFF		0x044
-#define PRCM_BMLCLK_MGT_OFF		0x04C
-#define PRCM_HSITXCLK_MGT_OFF		0x050
-#define PRCM_HSIRXCLK_MGT_OFF		0x054
-#define PRCM_HDMICLK_MGT_OFF		0x058
-#define PRCM_APEATCLK_MGT_OFF		0x05C
-#define PRCM_APETRACECLK_MGT_OFF	0x060
-#define PRCM_MCDECLK_MGT_OFF		0x064
-#define PRCM_IPI2CCLK_MGT_OFF		0x068
-#define PRCM_DSIALTCLK_MGT_OFF		0x06C
-#define PRCM_DMACLK_MGT_OFF		0x074
-#define PRCM_B2R2CLK_MGT_OFF		0x078
-#define PRCM_TVCLK_MGT_OFF		0x07C
-#define PRCM_UNIPROCLK_MGT_OFF		0x278
-#define PRCM_SSPCLK_MGT_OFF		0x280
-#define PRCM_RNGCLK_MGT_OFF		0x284
-#define PRCM_UICCCLK_MGT_OFF		0x27C
-#define PRCM_MSP1CLK_MGT_OFF		0x288
+#define PRCM_CLK_MGT(_offset) (void __iomem *)(IO_ADDRESS(U8500_PRCMU_BASE) \
+	+ _offset)
+#define PRCM_ACLK_MGT		PRCM_CLK_MGT(0x004)
+#define PRCM_SVACLK_MGT		PRCM_CLK_MGT(0x008)
+#define PRCM_SIACLK_MGT		PRCM_CLK_MGT(0x00C)
+#define PRCM_SGACLK_MGT		PRCM_CLK_MGT(0x014)
+#define PRCM_UARTCLK_MGT	PRCM_CLK_MGT(0x018)
+#define PRCM_MSP02CLK_MGT	PRCM_CLK_MGT(0x01C)
+#define PRCM_I2CCLK_MGT		PRCM_CLK_MGT(0x020)
+#define PRCM_SDMMCCLK_MGT	PRCM_CLK_MGT(0x024)
+#define PRCM_SLIMCLK_MGT	PRCM_CLK_MGT(0x028)
+#define PRCM_PER1CLK_MGT	PRCM_CLK_MGT(0x02C)
+#define PRCM_PER2CLK_MGT	PRCM_CLK_MGT(0x030)
+#define PRCM_PER3CLK_MGT	PRCM_CLK_MGT(0x034)
+#define PRCM_PER5CLK_MGT	PRCM_CLK_MGT(0x038)
+#define PRCM_PER6CLK_MGT	PRCM_CLK_MGT(0x03C)
+#define PRCM_PER7CLK_MGT	PRCM_CLK_MGT(0x040)
+#define PRCM_LCDCLK_MGT		PRCM_CLK_MGT(0x044)
+#define PRCM_BMLCLK_MGT		PRCM_CLK_MGT(0x04C)
+#define PRCM_HSITXCLK_MGT	PRCM_CLK_MGT(0x050)
+#define PRCM_HSIRXCLK_MGT	PRCM_CLK_MGT(0x054)
+#define PRCM_HDMICLK_MGT	PRCM_CLK_MGT(0x058)
+#define PRCM_APEATCLK_MGT	PRCM_CLK_MGT(0x05C)
+#define PRCM_APETRACECLK_MGT	PRCM_CLK_MGT(0x060)
+#define PRCM_MCDECLK_MGT	PRCM_CLK_MGT(0x064)
+#define PRCM_IPI2CCLK_MGT	PRCM_CLK_MGT(0x068)
+#define PRCM_DSIALTCLK_MGT	PRCM_CLK_MGT(0x06C)
+#define PRCM_DMACLK_MGT		PRCM_CLK_MGT(0x074)
+#define PRCM_B2R2CLK_MGT	PRCM_CLK_MGT(0x078)
+#define PRCM_TVCLK_MGT		PRCM_CLK_MGT(0x07C)
+#define PRCM_UNIPROCLK_MGT	PRCM_CLK_MGT(0x278)
+#define PRCM_SSPCLK_MGT		PRCM_CLK_MGT(0x280)
+#define PRCM_RNGCLK_MGT		PRCM_CLK_MGT(0x284)
+#define PRCM_UICCCLK_MGT	PRCM_CLK_MGT(0x27C)
+#define PRCM_MSP1CLK_MGT	PRCM_CLK_MGT(0x288)
 
 
 #define PRCM_ARM_PLLDIVPS	(_PRCMU_BASE + 0x118)
 #define PRCM_ARM_PLLDIVPS	(_PRCMU_BASE + 0x118)
 #define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE		0x3f
 #define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE		0x3f
@@ -79,6 +79,8 @@
 
 
 /* ARM WFI Standby signal register */
 /* ARM WFI Standby signal register */
 #define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
 #define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
+#define PRCM_ARM_WFI_STANDBY_WFI0               0x08
+#define PRCM_ARM_WFI_STANDBY_WFI1               0x10
 #define PRCM_IOCR		(_PRCMU_BASE + 0x310)
 #define PRCM_IOCR		(_PRCMU_BASE + 0x310)
 #define PRCM_IOCR_IOFORCE			0x1
 #define PRCM_IOCR_IOFORCE			0x1
 
 
@@ -131,20 +133,58 @@
 #define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
 #define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
 #define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
 #define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
 
 
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP		BIT(11)
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI	BIT(22)
+
 /* PRCMU clock/PLL/reset registers */
 /* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLSOC0_FREQ	   (_PRCMU_BASE + 0x080)
+#define PRCM_PLLSOC1_FREQ	   (_PRCMU_BASE + 0x084)
+#define PRCM_PLLDDR_FREQ	   (_PRCMU_BASE + 0x08C)
+#define PRCM_PLL_FREQ_D_SHIFT	0
+#define PRCM_PLL_FREQ_D_MASK	BITS(0, 7)
+#define PRCM_PLL_FREQ_N_SHIFT	8
+#define PRCM_PLL_FREQ_N_MASK	BITS(8, 13)
+#define PRCM_PLL_FREQ_R_SHIFT	16
+#define PRCM_PLL_FREQ_R_MASK	BITS(16, 18)
+#define PRCM_PLL_FREQ_SELDIV2	BIT(24)
+#define PRCM_PLL_FREQ_DIV2EN	BIT(25)
+
 #define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
 #define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
 #define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
 #define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
-#define PRCM_LCDCLK_MGT            (_PRCMU_BASE + PRCM_LCDCLK_MGT_OFF)
-#define PRCM_MCDECLK_MGT           (_PRCMU_BASE + PRCM_MCDECLK_MGT_OFF)
-#define PRCM_HDMICLK_MGT           (_PRCMU_BASE + PRCM_HDMICLK_MGT_OFF)
-#define PRCM_TVCLK_MGT             (_PRCMU_BASE + PRCM_TVCLK_MGT_OFF)
 #define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
 #define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
 #define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
 #define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
 #define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
 #define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
 #define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
 
 
+#define PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE BIT(0)
+
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10	BIT(0)
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3	BIT(1)
+
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT	0
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK	BITS(0, 2)
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT	8
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK	BITS(8, 10)
+
+#define PRCM_DSI_PLLOUT_SEL_OFF		0
+#define PRCM_DSI_PLLOUT_SEL_PHI		1
+#define PRCM_DSI_PLLOUT_SEL_PHI_2	2
+#define PRCM_DSI_PLLOUT_SEL_PHI_4	3
+
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT	0
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK		BITS(0, 7)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT	8
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK		BITS(8, 15)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT	16
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK		BITS(16, 23)
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN		BIT(24)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN		BIT(25)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN		BIT(26)
+
+#define PRCM_APE_RESETN_DSIPLL_RESETN BIT(14)
+
 #define PRCM_CLKOCR		   (_PRCMU_BASE + 0x1CC)
 #define PRCM_CLKOCR		   (_PRCMU_BASE + 0x1CC)
 #define PRCM_CLKOCR_CLKOUT0_REF_CLK	(1 << 0)
 #define PRCM_CLKOCR_CLKOUT0_REF_CLK	(1 << 0)
 #define PRCM_CLKOCR_CLKOUT0_MASK	BITS(0, 13)
 #define PRCM_CLKOCR_CLKOUT0_MASK	BITS(0, 13)
@@ -183,9 +223,15 @@
 #define PRCM_CLKOCR_CLKOSEL1_MASK	BITS(22, 24)
 #define PRCM_CLKOCR_CLKOSEL1_MASK	BITS(22, 24)
 #define PRCM_CLKOCR_CLK1TYPE		BIT(28)
 #define PRCM_CLKOCR_CLK1TYPE		BIT(28)
 
 
-#define PRCM_CLK_MGT_CLKPLLDIV_MASK	BITS(0, 4)
-#define PRCM_CLK_MGT_CLKPLLSW_MASK	BITS(5, 7)
-#define PRCM_CLK_MGT_CLKEN		BIT(8)
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK		BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC0		BIT(5)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC1		BIT(6)
+#define PRCM_CLK_MGT_CLKPLLSW_DDR		BIT(7)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK		BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN			BIT(8)
+#define PRCM_CLK_MGT_CLK38			BIT(9)
+#define PRCM_CLK_MGT_CLK38DIV			BIT(11)
+#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN	BIT(12)
 
 
 /* GPIOCR register */
 /* GPIOCR register */
 #define PRCM_GPIOCR_SPI2_SELECT BIT(23)
 #define PRCM_GPIOCR_SPI2_SELECT BIT(23)

+ 9 - 2
drivers/mfd/mc13xxx-core.c

@@ -560,6 +560,8 @@ EXPORT_SYMBOL(mc13xxx_get_flags);
 
 
 #define MC13XXX_ADC1_CHAN0_SHIFT	5
 #define MC13XXX_ADC1_CHAN0_SHIFT	5
 #define MC13XXX_ADC1_CHAN1_SHIFT	8
 #define MC13XXX_ADC1_CHAN1_SHIFT	8
+#define MC13783_ADC1_ATO_SHIFT		11
+#define MC13783_ADC1_ATOX		(1 << 19)
 
 
 struct mc13xxx_adcdone_data {
 struct mc13xxx_adcdone_data {
 	struct mc13xxx *mc13xxx;
 	struct mc13xxx *mc13xxx;
@@ -580,7 +582,8 @@ static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
 #define MC13XXX_ADC_WORKING (1 << 0)
 #define MC13XXX_ADC_WORKING (1 << 0)
 
 
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
-		unsigned int channel, unsigned int *sample)
+		unsigned int channel, u8 ato, bool atox,
+		unsigned int *sample)
 {
 {
 	u32 adc0, adc1, old_adc0;
 	u32 adc0, adc1, old_adc0;
 	int i, ret;
 	int i, ret;
@@ -631,6 +634,9 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
+	adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
+	if (atox)
+		adc1 |= MC13783_ADC1_ATOX;
 	dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
 	dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
 	mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
 	mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
 			mc13xxx_handler_adcdone, __func__, &adcdone_data);
 			mc13xxx_handler_adcdone, __func__, &adcdone_data);
@@ -813,7 +819,8 @@ err_revision:
 		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
 		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
 
 
 	if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
 	if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
-		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
+				&pdata->touch, sizeof(pdata->touch));
 
 
 	if (pdata) {
 	if (pdata) {
 		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
 		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",

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

@@ -162,7 +162,7 @@ int mfd_add_devices(struct device *parent, int id,
 	atomic_t *cnts;
 	atomic_t *cnts;
 
 
 	/* initialize reference counting for all cells */
 	/* initialize reference counting for all cells */
-	cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
+	cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL);
 	if (!cnts)
 	if (!cnts)
 		return -ENOMEM;
 		return -ENOMEM;
 
 

+ 3 - 4
drivers/mfd/omap-usb-host.c

@@ -170,7 +170,7 @@ struct usbhs_hcd_omap {
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
 const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
-static u64 usbhs_dmamask = ~(u32)0;
+static u64 usbhs_dmamask = DMA_BIT_MASK(32);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -223,7 +223,7 @@ static struct platform_device *omap_usbhs_alloc_child(const char *name,
 	}
 	}
 
 
 	child->dev.dma_mask		= &usbhs_dmamask;
 	child->dev.dma_mask		= &usbhs_dmamask;
-	child->dev.coherent_dma_mask	= 0xffffffff;
+	dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
 	child->dev.parent		= dev;
 	child->dev.parent		= dev;
 
 
 	ret = platform_device_add(child);
 	ret = platform_device_add(child);
@@ -799,14 +799,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
 
 
 	platform_set_drvdata(pdev, omap);
 	platform_set_drvdata(pdev, omap);
 
 
+	omap_usbhs_init(dev);
 	ret = omap_usbhs_alloc_children(pdev);
 	ret = omap_usbhs_alloc_children(pdev);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "omap_usbhs_alloc_children failed\n");
 		dev_err(dev, "omap_usbhs_alloc_children failed\n");
 		goto err_alloc;
 		goto err_alloc;
 	}
 	}
 
 
-	omap_usbhs_init(dev);
-
 	goto end_probe;
 	goto end_probe;
 
 
 err_alloc:
 err_alloc:

+ 1 - 7
drivers/mfd/pcf50633-core.c

@@ -46,13 +46,7 @@ EXPORT_SYMBOL_GPL(pcf50633_read_block);
 int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
 int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
 					int nr_regs, u8 *data)
 					int nr_regs, u8 *data)
 {
 {
-	int ret;
-
-	ret = regmap_raw_write(pcf->regmap, reg, data, nr_regs);
-	if (ret != 0)
-		return ret;
-
-	return nr_regs;
+	return regmap_raw_write(pcf->regmap, reg, data, nr_regs);
 }
 }
 EXPORT_SYMBOL_GPL(pcf50633_write_block);
 EXPORT_SYMBOL_GPL(pcf50633_write_block);
 
 

+ 1 - 26
drivers/mfd/pcf50633-gpio.c

@@ -19,32 +19,7 @@
 
 
 #include <linux/mfd/pcf50633/core.h>
 #include <linux/mfd/pcf50633/core.h>
 #include <linux/mfd/pcf50633/gpio.h>
 #include <linux/mfd/pcf50633/gpio.h>
-
-enum pcf50633_regulator_id {
-	PCF50633_REGULATOR_AUTO,
-	PCF50633_REGULATOR_DOWN1,
-	PCF50633_REGULATOR_DOWN2,
-	PCF50633_REGULATOR_LDO1,
-	PCF50633_REGULATOR_LDO2,
-	PCF50633_REGULATOR_LDO3,
-	PCF50633_REGULATOR_LDO4,
-	PCF50633_REGULATOR_LDO5,
-	PCF50633_REGULATOR_LDO6,
-	PCF50633_REGULATOR_HCLDO,
-	PCF50633_REGULATOR_MEMLDO,
-};
-
-#define PCF50633_REG_AUTOOUT	0x1a
-#define PCF50633_REG_DOWN1OUT	0x1e
-#define PCF50633_REG_DOWN2OUT	0x22
-#define PCF50633_REG_MEMLDOOUT	0x26
-#define PCF50633_REG_LDO1OUT	0x2d
-#define PCF50633_REG_LDO2OUT	0x2f
-#define PCF50633_REG_LDO3OUT	0x31
-#define PCF50633_REG_LDO4OUT	0x33
-#define PCF50633_REG_LDO5OUT	0x35
-#define PCF50633_REG_LDO6OUT	0x37
-#define PCF50633_REG_HCLDOOUT	0x39
+#include <linux/mfd/pcf50633/pmic.h>
 
 
 static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
 static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
 	[PCF50633_REGULATOR_AUTO]	= PCF50633_REG_AUTOOUT,
 	[PCF50633_REGULATOR_AUTO]	= PCF50633_REG_AUTOOUT,

+ 1 - 6
drivers/mfd/pcf50633-irq.c

@@ -19,12 +19,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
 #include <linux/mfd/pcf50633/core.h>
 #include <linux/mfd/pcf50633/core.h>
-
-/* Two MBCS registers used during cold start */
-#define PCF50633_REG_MBCS1		0x4b
-#define PCF50633_REG_MBCS2		0x4c
-#define PCF50633_MBCS1_USBPRES 		0x01
-#define PCF50633_MBCS1_ADAPTPRES	0x01
+#include <linux/mfd/pcf50633/mbc.h>
 
 
 int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
 int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
 			void (*handler) (int, void *), void *data)
 			void (*handler) (int, void *), void *data)

+ 408 - 0
drivers/mfd/rc5t583-irq.c

@@ -0,0 +1,408 @@
+/*
+ * Interrupt driver for RICOH583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * based on code
+ *      Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mfd/rc5t583.h>
+
+enum int_type {
+	SYS_INT  = 0x1,
+	DCDC_INT = 0x2,
+	RTC_INT  = 0x4,
+	ADC_INT  = 0x8,
+	GPIO_INT = 0x10,
+};
+
+static int gpedge_add[] = {
+	RC5T583_GPIO_GPEDGE2,
+	RC5T583_GPIO_GPEDGE2
+};
+
+static int irq_en_add[] = {
+	RC5T583_INT_EN_SYS1,
+	RC5T583_INT_EN_SYS2,
+	RC5T583_INT_EN_DCDC,
+	RC5T583_INT_EN_RTC,
+	RC5T583_INT_EN_ADC1,
+	RC5T583_INT_EN_ADC2,
+	RC5T583_INT_EN_ADC3,
+	RC5T583_GPIO_EN_INT
+};
+
+static int irq_mon_add[] = {
+	RC5T583_INT_MON_SYS1,
+	RC5T583_INT_MON_SYS2,
+	RC5T583_INT_MON_DCDC,
+	RC5T583_INT_MON_RTC,
+	RC5T583_INT_IR_ADCL,
+	RC5T583_INT_IR_ADCH,
+	RC5T583_INT_IR_ADCEND,
+	RC5T583_INT_IR_GPIOF,
+	RC5T583_INT_IR_GPIOR
+};
+
+static int irq_clr_add[] = {
+	RC5T583_INT_IR_SYS1,
+	RC5T583_INT_IR_SYS2,
+	RC5T583_INT_IR_DCDC,
+	RC5T583_INT_IR_RTC,
+	RC5T583_INT_IR_ADCL,
+	RC5T583_INT_IR_ADCH,
+	RC5T583_INT_IR_ADCEND,
+	RC5T583_INT_IR_GPIOF,
+	RC5T583_INT_IR_GPIOR
+};
+
+static int main_int_type[] = {
+	SYS_INT,
+	SYS_INT,
+	DCDC_INT,
+	RTC_INT,
+	ADC_INT,
+	ADC_INT,
+	ADC_INT,
+	GPIO_INT,
+	GPIO_INT,
+};
+
+struct rc5t583_irq_data {
+	u8	int_type;
+	u8	master_bit;
+	u8	int_en_bit;
+	u8	mask_reg_index;
+	int	grp_index;
+};
+
+#define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
+			_int_bit, _mask_ind)		\
+	{						\
+		.int_type	= _int_type,		\
+		.master_bit	= _master_bit,		\
+		.grp_index	= _grp_index,		\
+		.int_en_bit	= _int_bit,		\
+		.mask_reg_index	= _mask_ind,		\
+	}
+
+static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
+	[RC5T583_IRQ_ONKEY]		= RC5T583_IRQ(SYS_INT,  0, 0, 0, 0),
+	[RC5T583_IRQ_ACOK]		= RC5T583_IRQ(SYS_INT,  0, 1, 1, 0),
+	[RC5T583_IRQ_LIDOPEN]		= RC5T583_IRQ(SYS_INT,  0, 2, 2, 0),
+	[RC5T583_IRQ_PREOT]		= RC5T583_IRQ(SYS_INT,  0, 3, 3, 0),
+	[RC5T583_IRQ_CLKSTP]		= RC5T583_IRQ(SYS_INT,  0, 4, 4, 0),
+	[RC5T583_IRQ_ONKEY_OFF]		= RC5T583_IRQ(SYS_INT,  0, 5, 5, 0),
+	[RC5T583_IRQ_WD]		= RC5T583_IRQ(SYS_INT,  0, 7, 7, 0),
+	[RC5T583_IRQ_EN_PWRREQ1]	= RC5T583_IRQ(SYS_INT,  0, 8, 0, 1),
+	[RC5T583_IRQ_EN_PWRREQ2]	= RC5T583_IRQ(SYS_INT,  0, 9, 1, 1),
+	[RC5T583_IRQ_PRE_VINDET]	= RC5T583_IRQ(SYS_INT,  0, 10, 2, 1),
+
+	[RC5T583_IRQ_DC0LIM]		= RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
+	[RC5T583_IRQ_DC1LIM]		= RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
+	[RC5T583_IRQ_DC2LIM]		= RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
+	[RC5T583_IRQ_DC3LIM]		= RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
+
+	[RC5T583_IRQ_CTC]		= RC5T583_IRQ(RTC_INT,  2, 0, 0, 3),
+	[RC5T583_IRQ_YALE]		= RC5T583_IRQ(RTC_INT,  2, 5, 5, 3),
+	[RC5T583_IRQ_DALE]		= RC5T583_IRQ(RTC_INT,  2, 6, 6, 3),
+	[RC5T583_IRQ_WALE]		= RC5T583_IRQ(RTC_INT,  2, 7, 7, 3),
+
+	[RC5T583_IRQ_AIN1L]		= RC5T583_IRQ(ADC_INT,  3, 0, 0, 4),
+	[RC5T583_IRQ_AIN2L]		= RC5T583_IRQ(ADC_INT,  3, 1, 1, 4),
+	[RC5T583_IRQ_AIN3L]		= RC5T583_IRQ(ADC_INT,  3, 2, 2, 4),
+	[RC5T583_IRQ_VBATL]		= RC5T583_IRQ(ADC_INT,  3, 3, 3, 4),
+	[RC5T583_IRQ_VIN3L]		= RC5T583_IRQ(ADC_INT,  3, 4, 4, 4),
+	[RC5T583_IRQ_VIN8L]		= RC5T583_IRQ(ADC_INT,  3, 5, 5, 4),
+	[RC5T583_IRQ_AIN1H]		= RC5T583_IRQ(ADC_INT,  3, 6, 0, 5),
+	[RC5T583_IRQ_AIN2H]		= RC5T583_IRQ(ADC_INT,  3, 7, 1, 5),
+	[RC5T583_IRQ_AIN3H]		= RC5T583_IRQ(ADC_INT,  3, 8, 2, 5),
+	[RC5T583_IRQ_VBATH]		= RC5T583_IRQ(ADC_INT,  3, 9, 3, 5),
+	[RC5T583_IRQ_VIN3H]		= RC5T583_IRQ(ADC_INT,  3, 10, 4, 5),
+	[RC5T583_IRQ_VIN8H]		= RC5T583_IRQ(ADC_INT,  3, 11, 5, 5),
+	[RC5T583_IRQ_ADCEND]		= RC5T583_IRQ(ADC_INT,  3, 12, 0, 6),
+
+	[RC5T583_IRQ_GPIO0]		= RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
+	[RC5T583_IRQ_GPIO1]		= RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
+	[RC5T583_IRQ_GPIO2]		= RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
+	[RC5T583_IRQ_GPIO3]		= RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
+	[RC5T583_IRQ_GPIO4]		= RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
+	[RC5T583_IRQ_GPIO5]		= RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
+	[RC5T583_IRQ_GPIO6]		= RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
+	[RC5T583_IRQ_GPIO7]		= RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
+};
+
+static void rc5t583_irq_lock(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	mutex_lock(&rc5t583->irq_lock);
+}
+
+static void rc5t583_irq_unmask(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+	const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+	rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
+	rc5t583->intc_inten_reg |= 1 << data->master_bit;
+	rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
+}
+
+static void rc5t583_irq_mask(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+	const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+	rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
+	if (!rc5t583->group_irq_en[data->grp_index])
+		rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
+
+	rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
+}
+
+static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+	const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+	int val = 0;
+	int gpedge_index;
+	int gpedge_bit_pos;
+
+	/* Supporting only trigger level inetrrupt */
+	if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
+		gpedge_index = data->int_en_bit / 4;
+		gpedge_bit_pos = data->int_en_bit % 4;
+
+		if (type & IRQ_TYPE_EDGE_FALLING)
+			val |= 0x2;
+
+		if (type & IRQ_TYPE_EDGE_RISING)
+			val |= 0x1;
+
+		rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
+		rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
+		rc5t583_irq_unmask(irq_data);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
+		ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+				rc5t583->gpedge_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				gpedge_add[i], ret);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
+		ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+					rc5t583->irq_en_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				irq_en_add[i], ret);
+	}
+
+	ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
+				rc5t583->intc_inten_reg);
+	if (ret < 0)
+		dev_warn(rc5t583->dev,
+			"Error in writing reg 0x%02x error: %d\n",
+			RC5T583_INTC_INTEN, ret);
+
+	mutex_unlock(&rc5t583->irq_lock);
+}
+#ifdef CONFIG_PM_SLEEP
+static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
+{
+	struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+	return irq_set_irq_wake(rc5t583->chip_irq, on);
+}
+#else
+#define rc5t583_irq_set_wake NULL
+#endif
+
+static irqreturn_t rc5t583_irq(int irq, void *data)
+{
+	struct rc5t583 *rc5t583 = data;
+	uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
+	uint8_t master_int;
+	int i;
+	int ret;
+	unsigned int rtc_int_sts = 0;
+
+	/* Clear the status */
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
+		int_sts[i] = 0;
+
+	ret  = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
+	if (ret < 0) {
+		dev_err(rc5t583->dev,
+			"Error in reading reg 0x%02x error: %d\n",
+			RC5T583_INTC_INTMON, ret);
+		return IRQ_HANDLED;
+	}
+
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
+		if (!(master_int & main_int_type[i]))
+			continue;
+
+		ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
+		if (ret < 0) {
+			dev_warn(rc5t583->dev,
+				"Error in reading reg 0x%02x error: %d\n",
+				irq_mon_add[i], ret);
+			int_sts[i] = 0;
+			continue;
+		}
+
+		if (main_int_type[i] & RTC_INT) {
+			rtc_int_sts = 0;
+			if (int_sts[i] & 0x1)
+				rtc_int_sts |= BIT(6);
+			if (int_sts[i] & 0x2)
+				rtc_int_sts |= BIT(7);
+			if (int_sts[i] & 0x4)
+				rtc_int_sts |= BIT(0);
+			if (int_sts[i] & 0x8)
+				rtc_int_sts |= BIT(5);
+		}
+
+		ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
+				~int_sts[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in reading reg 0x%02x error: %d\n",
+				irq_clr_add[i], ret);
+
+		if (main_int_type[i] & RTC_INT)
+			int_sts[i] = rtc_int_sts;
+	}
+
+	/* Merge gpio interrupts for rising and falling case*/
+	int_sts[7] |= int_sts[8];
+
+	/* Call interrupt handler if enabled */
+	for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
+		const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
+		if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
+			(rc5t583->group_irq_en[data->master_bit] &
+					(1 << data->grp_index)))
+			handle_nested_irq(rc5t583->irq_base + i);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct irq_chip rc5t583_irq_chip = {
+	.name = "rc5t583-irq",
+	.irq_mask = rc5t583_irq_mask,
+	.irq_unmask = rc5t583_irq_unmask,
+	.irq_bus_lock = rc5t583_irq_lock,
+	.irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
+	.irq_set_type = rc5t583_irq_set_type,
+	.irq_set_wake = rc5t583_irq_set_wake,
+};
+
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
+{
+	int i, ret;
+
+	if (!irq_base) {
+		dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&rc5t583->irq_lock);
+
+	/* Initailize all int register to 0 */
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+		ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+				rc5t583->irq_en_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				irq_en_add[i], ret);
+	}
+
+	for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++)  {
+		ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+				rc5t583->gpedge_reg[i]);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				gpedge_add[i], ret);
+	}
+
+	ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
+	if (ret < 0)
+		dev_warn(rc5t583->dev,
+			"Error in writing reg 0x%02x error: %d\n",
+			RC5T583_INTC_INTEN, ret);
+
+	/* Clear all interrupts in case they woke up active. */
+	for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+		ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				irq_clr_add[i], ret);
+	}
+
+	rc5t583->irq_base = irq_base;
+	rc5t583->chip_irq = irq;
+
+	for (i = 0; i < RC5T583_MAX_IRQS; i++) {
+		int __irq = i + rc5t583->irq_base;
+		irq_set_chip_data(__irq, rc5t583);
+		irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
+					 handle_simple_irq);
+		irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(__irq, IRQF_VALID);
+#endif
+	}
+
+	ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
+				"rc5t583", rc5t583);
+	if (ret < 0)
+		dev_err(rc5t583->dev,
+			"Error in registering interrupt error: %d\n", ret);
+	return ret;
+}
+
+int rc5t583_irq_exit(struct rc5t583 *rc5t583)
+{
+	if (rc5t583->chip_irq)
+		free_irq(rc5t583->chip_irq, rc5t583);
+	return 0;
+}

+ 386 - 0
drivers/mfd/rc5t583.c

@@ -0,0 +1,386 @@
+/*
+ * Core driver access RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ *	Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rc5t583.h>
+#include <linux/regmap.h>
+
+#define RICOH_ONOFFSEL_REG	0x10
+#define RICOH_SWCTL_REG		0x5E
+
+struct deepsleep_control_data {
+	u8 reg_add;
+	u8 ds_pos_bit;
+};
+
+#define DEEPSLEEP_INIT(_id, _reg, _pos)		\
+	{					\
+		.reg_add = RC5T583_##_reg,	\
+		.ds_pos_bit = _pos,		\
+	}
+
+static struct deepsleep_control_data deepsleep_data[] = {
+	DEEPSLEEP_INIT(DC0, SLPSEQ1, 0),
+	DEEPSLEEP_INIT(DC1, SLPSEQ1, 4),
+	DEEPSLEEP_INIT(DC2, SLPSEQ2, 0),
+	DEEPSLEEP_INIT(DC3, SLPSEQ2, 4),
+	DEEPSLEEP_INIT(LDO0, SLPSEQ3, 0),
+	DEEPSLEEP_INIT(LDO1, SLPSEQ3, 4),
+	DEEPSLEEP_INIT(LDO2, SLPSEQ4, 0),
+	DEEPSLEEP_INIT(LDO3, SLPSEQ4, 4),
+	DEEPSLEEP_INIT(LDO4, SLPSEQ5, 0),
+	DEEPSLEEP_INIT(LDO5, SLPSEQ5, 4),
+	DEEPSLEEP_INIT(LDO6, SLPSEQ6, 0),
+	DEEPSLEEP_INIT(LDO7, SLPSEQ6, 4),
+	DEEPSLEEP_INIT(LDO8, SLPSEQ7, 0),
+	DEEPSLEEP_INIT(LDO9, SLPSEQ7, 4),
+	DEEPSLEEP_INIT(PSO0, SLPSEQ8, 0),
+	DEEPSLEEP_INIT(PSO1, SLPSEQ8, 4),
+	DEEPSLEEP_INIT(PSO2, SLPSEQ9, 0),
+	DEEPSLEEP_INIT(PSO3, SLPSEQ9, 4),
+	DEEPSLEEP_INIT(PSO4, SLPSEQ10, 0),
+	DEEPSLEEP_INIT(PSO5, SLPSEQ10, 4),
+	DEEPSLEEP_INIT(PSO6, SLPSEQ11, 0),
+	DEEPSLEEP_INIT(PSO7, SLPSEQ11, 4),
+};
+
+#define EXT_PWR_REQ		\
+	(RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
+
+static struct mfd_cell rc5t583_subdevs[] = {
+	{.name = "rc5t583-regulator",},
+	{.name = "rc5t583-rtc",      },
+	{.name = "rc5t583-key",      }
+};
+
+int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_write(rc5t583->regmap, reg, val);
+}
+
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	unsigned int ival;
+	int ret;
+	ret = regmap_read(rc5t583->regmap, reg, &ival);
+	if (!ret)
+		*val = (uint8_t)ival;
+	return ret;
+}
+
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+			unsigned int bit_mask)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
+}
+
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+			unsigned int bit_mask)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
+}
+
+int rc5t583_update(struct device *dev, unsigned int reg,
+		unsigned int val, unsigned int mask)
+{
+	struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+	return regmap_update_bits(rc5t583->regmap, reg, mask, val);
+}
+
+static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
+	int id, int ext_pwr, int slots)
+{
+	int ret;
+	uint8_t sleepseq_val;
+	unsigned int en_bit;
+	unsigned int slot_bit;
+
+	if (id == RC5T583_DS_DC0) {
+		dev_err(dev, "PWRREQ1 is invalid control for rail %d\n", id);
+		return -EINVAL;
+	}
+
+	en_bit = deepsleep_data[id].ds_pos_bit;
+	slot_bit = en_bit + 1;
+	ret = rc5t583_read(dev, deepsleep_data[id].reg_add, &sleepseq_val);
+	if (ret < 0) {
+		dev_err(dev, "Error in reading reg 0x%x\n",
+				deepsleep_data[id].reg_add);
+		return ret;
+	}
+
+	sleepseq_val &= ~(0xF << en_bit);
+	sleepseq_val |= BIT(en_bit);
+	sleepseq_val |= ((slots & 0x7) << slot_bit);
+	ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(1));
+	if (ret < 0) {
+		dev_err(dev, "Error in updating the 0x%02x register\n",
+				RICOH_ONOFFSEL_REG);
+		return ret;
+	}
+
+	ret = rc5t583_write(dev, deepsleep_data[id].reg_add, sleepseq_val);
+	if (ret < 0) {
+		dev_err(dev, "Error in writing reg 0x%x\n",
+				deepsleep_data[id].reg_add);
+		return ret;
+	}
+
+	if (id == RC5T583_DS_LDO4) {
+		ret = rc5t583_write(dev, RICOH_SWCTL_REG, 0x1);
+		if (ret < 0)
+			dev_err(dev, "Error in writing reg 0x%x\n",
+				RICOH_SWCTL_REG);
+	}
+	return ret;
+}
+
+static int __rc5t583_set_ext_pwrreq2_control(struct device *dev,
+	int id, int ext_pwr)
+{
+	int ret;
+
+	if (id != RC5T583_DS_DC0) {
+		dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
+		return -EINVAL;
+	}
+
+	ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(2));
+	if (ret < 0)
+		dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
+	return ret;
+}
+
+int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
+	int ext_pwr_req, int deepsleep_slot_nr)
+{
+	if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
+		return -EINVAL;
+
+	if (ext_pwr_req & RC5T583_EXT_PWRREQ1_CONTROL)
+		return __rc5t583_set_ext_pwrreq1_control(dev, ds_id,
+				ext_pwr_req, deepsleep_slot_nr);
+
+	if (ext_pwr_req & RC5T583_EXT_PWRREQ2_CONTROL)
+		return __rc5t583_set_ext_pwrreq2_control(dev,
+			ds_id, ext_pwr_req);
+	return 0;
+}
+
+static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
+	struct rc5t583_platform_data *pdata)
+{
+	int ret;
+	int i;
+	uint8_t on_off_val = 0;
+
+	/*  Clear ONOFFSEL register */
+	if (pdata->enable_shutdown)
+		on_off_val = 0x1;
+
+	ret = rc5t583_write(rc5t583->dev, RICOH_ONOFFSEL_REG, on_off_val);
+	if (ret < 0)
+		dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+					RICOH_ONOFFSEL_REG, ret);
+
+	ret = rc5t583_write(rc5t583->dev, RICOH_SWCTL_REG, 0x0);
+	if (ret < 0)
+		dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+					RICOH_SWCTL_REG, ret);
+
+	/* Clear sleep sequence register */
+	for (i = RC5T583_SLPSEQ1; i <= RC5T583_SLPSEQ11; ++i) {
+		ret = rc5t583_write(rc5t583->dev, i, 0x0);
+		if (ret < 0)
+			dev_warn(rc5t583->dev,
+				"Error in writing reg 0x%02x error: %d\n",
+				i, ret);
+	}
+	return 0;
+}
+
+static bool volatile_reg(struct device *dev, unsigned int reg)
+{
+	/* Enable caching in interrupt registers */
+	switch (reg) {
+	case RC5T583_INT_EN_SYS1:
+	case RC5T583_INT_EN_SYS2:
+	case RC5T583_INT_EN_DCDC:
+	case RC5T583_INT_EN_RTC:
+	case RC5T583_INT_EN_ADC1:
+	case RC5T583_INT_EN_ADC2:
+	case RC5T583_INT_EN_ADC3:
+	case RC5T583_GPIO_GPEDGE1:
+	case RC5T583_GPIO_GPEDGE2:
+	case RC5T583_GPIO_EN_INT:
+		return false;
+
+	case RC5T583_GPIO_MON_IOIN:
+		/* This is gpio input register */
+		return true;
+
+	default:
+		/* Enable caching in gpio registers */
+		if ((reg >= RC5T583_GPIO_IOSEL) &&
+				(reg <= RC5T583_GPIO_GPOFUNC))
+			return false;
+
+		/* Enable caching in sleep seq registers */
+		if ((reg >= RC5T583_SLPSEQ1) && (reg <= RC5T583_SLPSEQ11))
+			return false;
+
+		/* Enable caching of regulator registers */
+		if ((reg >= RC5T583_REG_DC0CTL) && (reg <= RC5T583_REG_SR3CTL))
+			return false;
+		if ((reg >= RC5T583_REG_LDOEN1) &&
+					(reg <= RC5T583_REG_LDO9DAC_DS))
+			return false;
+
+		break;
+	}
+
+	return true;
+}
+
+static const struct regmap_config rc5t583_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_reg = volatile_reg,
+	.max_register = RC5T583_MAX_REGS,
+	.num_reg_defaults_raw = RC5T583_MAX_REGS,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
+			      const struct i2c_device_id *id)
+{
+	struct rc5t583 *rc5t583;
+	struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
+	int ret;
+	bool irq_init_success = false;
+
+	if (!pdata) {
+		dev_err(&i2c->dev, "Err: Platform data not found\n");
+		return -EINVAL;
+	}
+
+	rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL);
+	if (!rc5t583) {
+		dev_err(&i2c->dev, "Memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	rc5t583->dev = &i2c->dev;
+	i2c_set_clientdata(i2c, rc5t583);
+
+	rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+	if (IS_ERR(rc5t583->regmap)) {
+		ret = PTR_ERR(rc5t583->regmap);
+		dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
+	if (ret < 0)
+		goto err_irq_init;
+
+	if (i2c->irq) {
+		ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
+		/* Still continue with waring if irq init fails */
+		if (ret)
+			dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
+		else
+			irq_init_success = true;
+	}
+
+	ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
+			ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
+	if (ret) {
+		dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
+		goto err_add_devs;
+	}
+
+	return 0;
+
+err_add_devs:
+	if (irq_init_success)
+		rc5t583_irq_exit(rc5t583);
+err_irq_init:
+	regmap_exit(rc5t583->regmap);
+	return ret;
+}
+
+static int  __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
+{
+	struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(rc5t583->dev);
+	rc5t583_irq_exit(rc5t583);
+	regmap_exit(rc5t583->regmap);
+	return 0;
+}
+
+static const struct i2c_device_id rc5t583_i2c_id[] = {
+	{.name = "rc5t583", .driver_data = 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, rc5t583_i2c_id);
+
+static struct i2c_driver rc5t583_i2c_driver = {
+	.driver = {
+		   .name = "rc5t583",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = rc5t583_i2c_probe,
+	.remove = __devexit_p(rc5t583_i2c_remove),
+	.id_table = rc5t583_i2c_id,
+};
+
+static int __init rc5t583_i2c_init(void)
+{
+	return i2c_add_driver(&rc5t583_i2c_driver);
+}
+subsys_initcall(rc5t583_i2c_init);
+
+static void __exit rc5t583_i2c_exit(void)
+{
+	i2c_del_driver(&rc5t583_i2c_driver);
+}
+
+module_exit(rc5t583_i2c_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("RICOH RC5T583 power management system device driver");
+MODULE_LICENSE("GPL v2");

+ 45 - 13
drivers/mfd/s5m-core.c

@@ -26,7 +26,27 @@
 #include <linux/mfd/s5m87xx/s5m-rtc.h>
 #include <linux/mfd/s5m87xx/s5m-rtc.h>
 #include <linux/regmap.h>
 #include <linux/regmap.h>
 
 
-static struct mfd_cell s5m87xx_devs[] = {
+static struct mfd_cell s5m8751_devs[] = {
+	{
+		.name = "s5m8751-pmic",
+	}, {
+		.name = "s5m-charger",
+	}, {
+		.name = "s5m8751-codec",
+	},
+};
+
+static struct mfd_cell s5m8763_devs[] = {
+	{
+		.name = "s5m8763-pmic",
+	}, {
+		.name = "s5m-rtc",
+	}, {
+		.name = "s5m-charger",
+	},
+};
+
+static struct mfd_cell s5m8767_devs[] = {
 	{
 	{
 		.name = "s5m8767-pmic",
 		.name = "s5m8767-pmic",
 	}, {
 	}, {
@@ -42,7 +62,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_read);
 
 
 int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 {
 {
-	return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
+	return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
 }
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_read);
 EXPORT_SYMBOL_GPL(s5m_bulk_read);
 
 
@@ -54,7 +74,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_write);
 
 
 int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 {
 {
-	return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+	return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
 }
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_write);
 EXPORT_SYMBOL_GPL(s5m_bulk_write);
 
 
@@ -74,10 +94,10 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 {
 {
 	struct s5m_platform_data *pdata = i2c->dev.platform_data;
 	struct s5m_platform_data *pdata = i2c->dev.platform_data;
 	struct s5m87xx_dev *s5m87xx;
 	struct s5m87xx_dev *s5m87xx;
-	int ret = 0;
-	int error;
+	int ret;
 
 
-	s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+	s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
+				GFP_KERNEL);
 	if (s5m87xx == NULL)
 	if (s5m87xx == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -96,9 +116,9 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 
 
 	s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
 	s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
 	if (IS_ERR(s5m87xx->regmap)) {
 	if (IS_ERR(s5m87xx->regmap)) {
-		error = PTR_ERR(s5m87xx->regmap);
+		ret = PTR_ERR(s5m87xx->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-			error);
+			ret);
 		goto err;
 		goto err;
 	}
 	}
 
 
@@ -112,9 +132,23 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 
 
 	pm_runtime_set_active(s5m87xx->dev);
 	pm_runtime_set_active(s5m87xx->dev);
 
 
-	ret = mfd_add_devices(s5m87xx->dev, -1,
-				s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
-				NULL, 0);
+	switch (s5m87xx->device_type) {
+	case S5M8751X:
+		ret = mfd_add_devices(s5m87xx->dev, -1, s5m8751_devs,
+					ARRAY_SIZE(s5m8751_devs), NULL, 0);
+		break;
+	case S5M8763X:
+		ret = mfd_add_devices(s5m87xx->dev, -1, s5m8763_devs,
+					ARRAY_SIZE(s5m8763_devs), NULL, 0);
+		break;
+	case S5M8767X:
+		ret = mfd_add_devices(s5m87xx->dev, -1, s5m8767_devs,
+					ARRAY_SIZE(s5m8767_devs), NULL, 0);
+		break;
+	default:
+		/* If this happens the probe function is problem */
+		BUG();
+	}
 
 
 	if (ret < 0)
 	if (ret < 0)
 		goto err;
 		goto err;
@@ -126,7 +160,6 @@ err:
 	s5m_irq_exit(s5m87xx);
 	s5m_irq_exit(s5m87xx);
 	i2c_unregister_device(s5m87xx->rtc);
 	i2c_unregister_device(s5m87xx->rtc);
 	regmap_exit(s5m87xx->regmap);
 	regmap_exit(s5m87xx->regmap);
-	kfree(s5m87xx);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -138,7 +171,6 @@ static int s5m87xx_i2c_remove(struct i2c_client *i2c)
 	s5m_irq_exit(s5m87xx);
 	s5m_irq_exit(s5m87xx);
 	i2c_unregister_device(s5m87xx->rtc);
 	i2c_unregister_device(s5m87xx->rtc);
 	regmap_exit(s5m87xx->regmap);
 	regmap_exit(s5m87xx->regmap);
-	kfree(s5m87xx);
 	return 0;
 	return 0;
 }
 }
 
 

+ 11 - 3
drivers/mfd/s5m-irq.c

@@ -342,7 +342,10 @@ int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
 			s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
 			s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
 			break;
 			break;
 		default:
 		default:
-			break;
+			dev_err(s5m87xx->dev,
+				"Unknown device type %d\n",
+				s5m87xx->device_type);
+			return -EINVAL;
 
 
 		}
 		}
 	}
 	}
@@ -444,7 +447,9 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
 		}
 		}
 		break;
 		break;
 	default:
 	default:
-		break;
+		dev_err(s5m87xx->dev,
+			"Unknown device type %d\n", s5m87xx->device_type);
+		return -EINVAL;
 	}
 	}
 
 
 	if (!s5m87xx->ono)
 	if (!s5m87xx->ono)
@@ -467,12 +472,15 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
 					IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
 					IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
 		break;
 		break;
 	default:
 	default:
+		ret = -EINVAL;
 		break;
 		break;
 	}
 	}
 
 
-	if (ret)
+	if (ret) {
 		dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
 		dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
 			s5m87xx->ono, ret);
 			s5m87xx->ono, ret);
+		return ret;
+	}
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 9
drivers/mfd/sm501.c

@@ -387,14 +387,6 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
 
 
 EXPORT_SYMBOL_GPL(sm501_unit_power);
 EXPORT_SYMBOL_GPL(sm501_unit_power);
 
 
-
-/* Perform a rounded division. */
-static long sm501fb_round_div(long num, long denom)
-{
-        /* n / d + 1 / 2 = (2n + d) / 2d */
-        return (2 * num + denom) / (2 * denom);
-}
-
 /* clock value structure. */
 /* clock value structure. */
 struct sm501_clock {
 struct sm501_clock {
 	unsigned long mclk;
 	unsigned long mclk;
@@ -428,7 +420,7 @@ static int sm501_calc_clock(unsigned long freq,
 		/* try all 8 shift values.*/
 		/* try all 8 shift values.*/
 		for (shift = 0; shift < 8; shift++) {
 		for (shift = 0; shift < 8; shift++) {
 			/* Calculate difference to requested clock */
 			/* Calculate difference to requested clock */
-			diff = sm501fb_round_div(mclk, divider << shift) - freq;
+			diff = DIV_ROUND_CLOSEST(mclk, divider << shift) - freq;
 			if (diff < 0)
 			if (diff < 0)
 				diff = -diff;
 				diff = -diff;
 
 

+ 96 - 38
drivers/mfd/stmpe.c

@@ -298,6 +298,11 @@ static struct mfd_cell stmpe_gpio_cell = {
 	.num_resources	= ARRAY_SIZE(stmpe_gpio_resources),
 	.num_resources	= ARRAY_SIZE(stmpe_gpio_resources),
 };
 };
 
 
+static struct mfd_cell stmpe_gpio_cell_noirq = {
+	.name		= "stmpe-gpio",
+	/* gpio cell resources consist of an irq only so no resources here */
+};
+
 /*
 /*
  * Keypad (1601, 2401, 2403)
  * Keypad (1601, 2401, 2403)
  */
  */
@@ -346,6 +351,13 @@ static struct stmpe_variant_block stmpe801_blocks[] = {
 	},
 	},
 };
 };
 
 
+static struct stmpe_variant_block stmpe801_blocks_noirq[] = {
+	{
+		.cell	= &stmpe_gpio_cell_noirq,
+		.block	= STMPE_BLOCK_GPIO,
+	},
+};
+
 static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
 static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
 			   bool enable)
 			   bool enable)
 {
 {
@@ -367,6 +379,17 @@ static struct stmpe_variant_info stmpe801 = {
 	.enable		= stmpe801_enable,
 	.enable		= stmpe801_enable,
 };
 };
 
 
+static struct stmpe_variant_info stmpe801_noirq = {
+	.name		= "stmpe801",
+	.id_val		= STMPE801_ID,
+	.id_mask	= 0xffff,
+	.num_gpios	= 8,
+	.regs		= stmpe801_regs,
+	.blocks		= stmpe801_blocks_noirq,
+	.num_blocks	= ARRAY_SIZE(stmpe801_blocks_noirq),
+	.enable		= stmpe801_enable,
+};
+
 /*
 /*
  * Touchscreen (STMPE811 or STMPE610)
  * Touchscreen (STMPE811 or STMPE610)
  */
  */
@@ -712,7 +735,7 @@ static struct stmpe_variant_info stmpe2403 = {
 	.enable_autosleep	= stmpe1601_autosleep, /* same as stmpe1601 */
 	.enable_autosleep	= stmpe1601_autosleep, /* same as stmpe1601 */
 };
 };
 
 
-static struct stmpe_variant_info *stmpe_variant_info[] = {
+static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
 	[STMPE610]	= &stmpe610,
 	[STMPE610]	= &stmpe610,
 	[STMPE801]	= &stmpe801,
 	[STMPE801]	= &stmpe801,
 	[STMPE811]	= &stmpe811,
 	[STMPE811]	= &stmpe811,
@@ -721,6 +744,16 @@ static struct stmpe_variant_info *stmpe_variant_info[] = {
 	[STMPE2403]	= &stmpe2403,
 	[STMPE2403]	= &stmpe2403,
 };
 };
 
 
+/*
+ * These devices can be connected in a 'no-irq' configuration - the irq pin
+ * is not used and the device cannot interrupt the CPU. Here we only list
+ * devices which support this configuration - the driver will fail probing
+ * for any devices not listed here which are configured in this way.
+ */
+static struct stmpe_variant_info *stmpe_noirq_variant_info[STMPE_NBR_PARTS] = {
+	[STMPE801]	= &stmpe801_noirq,
+};
+
 static irqreturn_t stmpe_irq(int irq, void *data)
 static irqreturn_t stmpe_irq(int irq, void *data)
 {
 {
 	struct stmpe *stmpe = data;
 	struct stmpe *stmpe = data;
@@ -864,7 +897,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
 	unsigned int irq_trigger = stmpe->pdata->irq_trigger;
 	unsigned int irq_trigger = stmpe->pdata->irq_trigger;
 	int autosleep_timeout = stmpe->pdata->autosleep_timeout;
 	int autosleep_timeout = stmpe->pdata->autosleep_timeout;
 	struct stmpe_variant_info *variant = stmpe->variant;
 	struct stmpe_variant_info *variant = stmpe->variant;
-	u8 icr;
+	u8 icr = 0;
 	unsigned int id;
 	unsigned int id;
 	u8 data[2];
 	u8 data[2];
 	int ret;
 	int ret;
@@ -887,31 +920,33 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	if (id == STMPE801_ID)
-		icr = STMPE801_REG_SYS_CTRL_INT_EN;
-	else
-		icr = STMPE_ICR_LSB_GIM;
-
-	/* STMPE801 doesn't support Edge interrupts */
-	if (id != STMPE801_ID) {
-		if (irq_trigger == IRQF_TRIGGER_FALLING ||
-				irq_trigger == IRQF_TRIGGER_RISING)
-			icr |= STMPE_ICR_LSB_EDGE;
-	}
-
-	if (irq_trigger == IRQF_TRIGGER_RISING ||
-			irq_trigger == IRQF_TRIGGER_HIGH) {
+	if (stmpe->irq >= 0) {
 		if (id == STMPE801_ID)
 		if (id == STMPE801_ID)
-			icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+			icr = STMPE801_REG_SYS_CTRL_INT_EN;
 		else
 		else
-			icr |= STMPE_ICR_LSB_HIGH;
-	}
+			icr = STMPE_ICR_LSB_GIM;
 
 
-	if (stmpe->pdata->irq_invert_polarity) {
-		if (id == STMPE801_ID)
-			icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
-		else
-			icr ^= STMPE_ICR_LSB_HIGH;
+		/* STMPE801 doesn't support Edge interrupts */
+		if (id != STMPE801_ID) {
+			if (irq_trigger == IRQF_TRIGGER_FALLING ||
+					irq_trigger == IRQF_TRIGGER_RISING)
+				icr |= STMPE_ICR_LSB_EDGE;
+		}
+
+		if (irq_trigger == IRQF_TRIGGER_RISING ||
+				irq_trigger == IRQF_TRIGGER_HIGH) {
+			if (id == STMPE801_ID)
+				icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+			else
+				icr |= STMPE_ICR_LSB_HIGH;
+		}
+
+		if (stmpe->pdata->irq_invert_polarity) {
+			if (id == STMPE801_ID)
+				icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+			else
+				icr ^= STMPE_ICR_LSB_HIGH;
+		}
 	}
 	}
 
 
 	if (stmpe->pdata->autosleep) {
 	if (stmpe->pdata->autosleep) {
@@ -1001,19 +1036,38 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
 		stmpe->irq = ci->irq;
 		stmpe->irq = ci->irq;
 	}
 	}
 
 
+	if (stmpe->irq < 0) {
+		/* use alternate variant info for no-irq mode, if supported */
+		dev_info(stmpe->dev,
+			"%s configured in no-irq mode by platform data\n",
+			stmpe->variant->name);
+		if (!stmpe_noirq_variant_info[stmpe->partnum]) {
+			dev_err(stmpe->dev,
+				"%s does not support no-irq mode!\n",
+				stmpe->variant->name);
+			ret = -ENODEV;
+			goto free_gpio;
+		}
+		stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
+	}
+
 	ret = stmpe_chip_init(stmpe);
 	ret = stmpe_chip_init(stmpe);
 	if (ret)
 	if (ret)
 		goto free_gpio;
 		goto free_gpio;
 
 
-	ret = stmpe_irq_init(stmpe);
-	if (ret)
-		goto free_gpio;
+	if (stmpe->irq >= 0) {
+		ret = stmpe_irq_init(stmpe);
+		if (ret)
+			goto free_gpio;
 
 
-	ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
-			pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
-	if (ret) {
-		dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
-		goto out_removeirq;
+		ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+				pdata->irq_trigger | IRQF_ONESHOT,
+				"stmpe", stmpe);
+		if (ret) {
+			dev_err(stmpe->dev, "failed to request IRQ: %d\n",
+					ret);
+			goto out_removeirq;
+		}
 	}
 	}
 
 
 	ret = stmpe_devices_init(stmpe);
 	ret = stmpe_devices_init(stmpe);
@@ -1026,9 +1080,11 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
 
 
 out_removedevs:
 out_removedevs:
 	mfd_remove_devices(stmpe->dev);
 	mfd_remove_devices(stmpe->dev);
-	free_irq(stmpe->irq, stmpe);
+	if (stmpe->irq >= 0)
+		free_irq(stmpe->irq, stmpe);
 out_removeirq:
 out_removeirq:
-	stmpe_irq_remove(stmpe);
+	if (stmpe->irq >= 0)
+		stmpe_irq_remove(stmpe);
 free_gpio:
 free_gpio:
 	if (pdata->irq_over_gpio)
 	if (pdata->irq_over_gpio)
 		gpio_free(pdata->irq_gpio);
 		gpio_free(pdata->irq_gpio);
@@ -1041,8 +1097,10 @@ int stmpe_remove(struct stmpe *stmpe)
 {
 {
 	mfd_remove_devices(stmpe->dev);
 	mfd_remove_devices(stmpe->dev);
 
 
-	free_irq(stmpe->irq, stmpe);
-	stmpe_irq_remove(stmpe);
+	if (stmpe->irq >= 0) {
+		free_irq(stmpe->irq, stmpe);
+		stmpe_irq_remove(stmpe);
+	}
 
 
 	if (stmpe->pdata->irq_over_gpio)
 	if (stmpe->pdata->irq_over_gpio)
 		gpio_free(stmpe->pdata->irq_gpio);
 		gpio_free(stmpe->pdata->irq_gpio);
@@ -1057,7 +1115,7 @@ static int stmpe_suspend(struct device *dev)
 {
 {
 	struct stmpe *stmpe = dev_get_drvdata(dev);
 	struct stmpe *stmpe = dev_get_drvdata(dev);
 
 
-	if (device_may_wakeup(dev))
+	if (stmpe->irq >= 0 && device_may_wakeup(dev))
 		enable_irq_wake(stmpe->irq);
 		enable_irq_wake(stmpe->irq);
 
 
 	return 0;
 	return 0;
@@ -1067,7 +1125,7 @@ static int stmpe_resume(struct device *dev)
 {
 {
 	struct stmpe *stmpe = dev_get_drvdata(dev);
 	struct stmpe *stmpe = dev_get_drvdata(dev);
 
 
-	if (device_may_wakeup(dev))
+	if (stmpe->irq >= 0 && device_may_wakeup(dev))
 		disable_irq_wake(stmpe->irq);
 		disable_irq_wake(stmpe->irq);
 
 
 	return 0;
 	return 0;

+ 387 - 0
drivers/mfd/tps65090.c

@@ -0,0 +1,387 @@
+/*
+ * Core driver for TI TPS65090 PMIC family
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65090.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#define NUM_INT_REG 2
+#define TOTAL_NUM_REG 0x18
+
+/* interrupt status registers */
+#define TPS65090_INT_STS	0x0
+#define TPS65090_INT_STS2	0x1
+
+/* interrupt mask registers */
+#define TPS65090_INT_MSK	0x2
+#define TPS65090_INT_MSK2	0x3
+
+struct tps65090_irq_data {
+	u8		mask_reg;
+	u8		mask_pos;
+};
+
+#define TPS65090_IRQ(_reg, _mask_pos)		\
+	{					\
+		.mask_reg	= (_reg),	\
+		.mask_pos	= (_mask_pos),	\
+	}
+
+static const struct tps65090_irq_data tps65090_irqs[] = {
+	[0]		= TPS65090_IRQ(0, 0),
+	[1]		= TPS65090_IRQ(0, 1),
+	[2]		= TPS65090_IRQ(0, 2),
+	[3]		= TPS65090_IRQ(0, 3),
+	[4]		= TPS65090_IRQ(0, 4),
+	[5]		= TPS65090_IRQ(0, 5),
+	[6]		= TPS65090_IRQ(0, 6),
+	[7]		= TPS65090_IRQ(0, 7),
+	[8]		= TPS65090_IRQ(1, 0),
+	[9]		= TPS65090_IRQ(1, 1),
+	[10]		= TPS65090_IRQ(1, 2),
+	[11]		= TPS65090_IRQ(1, 3),
+	[12]		= TPS65090_IRQ(1, 4),
+	[13]		= TPS65090_IRQ(1, 5),
+	[14]		= TPS65090_IRQ(1, 6),
+	[15]		= TPS65090_IRQ(1, 7),
+};
+
+static struct mfd_cell tps65090s[] = {
+	{
+		.name = "tps65910-pmic",
+	},
+	{
+		.name = "tps65910-regulator",
+	},
+};
+
+struct tps65090 {
+	struct mutex		lock;
+	struct device		*dev;
+	struct i2c_client	*client;
+	struct regmap		*rmap;
+	struct irq_chip		irq_chip;
+	struct mutex		irq_lock;
+	int			irq_base;
+	unsigned int		id;
+};
+
+int tps65090_write(struct device *dev, int reg, uint8_t val)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	return regmap_write(tps->rmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65090_write);
+
+int tps65090_read(struct device *dev, int reg, uint8_t *val)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	unsigned int temp_val;
+	int ret;
+	ret = regmap_read(tps->rmap, reg, &temp_val);
+	if (!ret)
+		*val = temp_val;
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps65090_read);
+
+int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_set_bits);
+
+int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+	struct tps65090 *tps = dev_get_drvdata(dev);
+	return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_clr_bits);
+
+static void tps65090_irq_lock(struct irq_data *data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&tps65090->irq_lock);
+}
+
+static void tps65090_irq_mask(struct irq_data *irq_data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->hwirq;
+	const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+	tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+		data->mask_pos);
+}
+
+static void tps65090_irq_unmask(struct irq_data *irq_data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+	unsigned int __irq = irq_data->irq - tps65090->irq_base;
+	const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+	tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+		data->mask_pos);
+}
+
+static void tps65090_irq_sync_unlock(struct irq_data *data)
+{
+	struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+	mutex_unlock(&tps65090->irq_lock);
+}
+
+static irqreturn_t tps65090_irq(int irq, void *data)
+{
+	struct tps65090 *tps65090 = data;
+	int ret = 0;
+	u8 status, mask;
+	unsigned long int acks = 0;
+	int i;
+
+	for (i = 0; i < NUM_INT_REG; i++) {
+		ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask);
+		if (ret < 0) {
+			dev_err(tps65090->dev,
+				"failed to read mask reg [addr:%d]\n",
+				TPS65090_INT_MSK + i);
+			return IRQ_NONE;
+		}
+		ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i,
+			&status);
+		if (ret < 0) {
+			dev_err(tps65090->dev,
+				"failed to read status reg [addr:%d]\n",
+				 TPS65090_INT_STS + i);
+			return IRQ_NONE;
+		}
+		if (status) {
+			/* Ack only those interrupts which are not masked */
+			status &= (~mask);
+			ret = tps65090_write(tps65090->dev,
+					TPS65090_INT_STS + i, status);
+			if (ret < 0) {
+				dev_err(tps65090->dev,
+					"failed to write interrupt status\n");
+				return IRQ_NONE;
+			}
+			acks |= (status << (i * 8));
+		}
+	}
+
+	for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs))
+		handle_nested_irq(tps65090->irq_base + i);
+	return acks ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
+	int irq_base)
+{
+	int i, ret;
+
+	if (!irq_base) {
+		dev_err(tps65090->dev, "IRQ base not set\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&tps65090->irq_lock);
+
+	for (i = 0; i < NUM_INT_REG; i++)
+		tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF);
+
+	for (i = 0; i < NUM_INT_REG; i++)
+		tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff);
+
+	tps65090->irq_base = irq_base;
+	tps65090->irq_chip.name = "tps65090";
+	tps65090->irq_chip.irq_mask = tps65090_irq_mask;
+	tps65090->irq_chip.irq_unmask = tps65090_irq_unmask;
+	tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock;
+	tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock;
+
+	for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
+		int __irq = i + tps65090->irq_base;
+		irq_set_chip_data(__irq, tps65090);
+		irq_set_chip_and_handler(__irq, &tps65090->irq_chip,
+					 handle_simple_irq);
+		irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(__irq, IRQF_VALID);
+#endif
+	}
+
+	ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT,
+				"tps65090", tps65090);
+	if (!ret) {
+		device_init_wakeup(tps65090->dev, 1);
+		enable_irq_wake(irq);
+	}
+
+	return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
+		return true;
+	else
+		return false;
+}
+
+static const struct regmap_config tps65090_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = TOTAL_NUM_REG,
+	.num_reg_defaults_raw = TOTAL_NUM_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = is_volatile_reg,
+};
+
+static int __devinit tps65090_i2c_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct tps65090_platform_data *pdata = client->dev.platform_data;
+	struct tps65090 *tps65090;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&client->dev, "tps65090 requires platform data\n");
+		return -EINVAL;
+	}
+
+	tps65090 = devm_kzalloc(&client->dev, sizeof(struct tps65090),
+		GFP_KERNEL);
+	if (tps65090 == NULL)
+		return -ENOMEM;
+
+	tps65090->client = client;
+	tps65090->dev = &client->dev;
+	i2c_set_clientdata(client, tps65090);
+
+	mutex_init(&tps65090->lock);
+
+	if (client->irq) {
+		ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base);
+		if (ret) {
+			dev_err(&client->dev, "IRQ init failed with err: %d\n",
+				ret);
+			goto err_exit;
+		}
+	}
+
+	tps65090->rmap = regmap_init_i2c(tps65090->client,
+		&tps65090_regmap_config);
+	if (IS_ERR(tps65090->rmap)) {
+		dev_err(&client->dev, "regmap_init failed with err: %ld\n",
+			PTR_ERR(tps65090->rmap));
+		goto err_irq_exit;
+	};
+
+	ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
+		ARRAY_SIZE(tps65090s), NULL, 0);
+	if (ret) {
+		dev_err(&client->dev, "add mfd devices failed with err: %d\n",
+			ret);
+		goto err_regmap_exit;
+	}
+
+	return 0;
+
+err_regmap_exit:
+	regmap_exit(tps65090->rmap);
+
+err_irq_exit:
+	if (client->irq)
+		free_irq(client->irq, tps65090);
+err_exit:
+	return ret;
+}
+
+static int __devexit tps65090_i2c_remove(struct i2c_client *client)
+{
+	struct tps65090 *tps65090 = i2c_get_clientdata(client);
+
+	mfd_remove_devices(tps65090->dev);
+	regmap_exit(tps65090->rmap);
+	if (client->irq)
+		free_irq(client->irq, tps65090);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tps65090_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+	if (client->irq)
+		disable_irq(client->irq);
+	return 0;
+}
+
+static int tps65090_i2c_resume(struct i2c_client *client)
+{
+	if (client->irq)
+		enable_irq(client->irq);
+	return 0;
+}
+#endif
+
+static const struct i2c_device_id tps65090_id_table[] = {
+	{ "tps65090", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, tps65090_id_table);
+
+static struct i2c_driver tps65090_driver = {
+	.driver	= {
+		.name	= "tps65090",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= tps65090_i2c_probe,
+	.remove		= __devexit_p(tps65090_i2c_remove),
+#ifdef CONFIG_PM
+	.suspend	= tps65090_i2c_suspend,
+	.resume		= tps65090_i2c_resume,
+#endif
+	.id_table	= tps65090_id_table,
+};
+
+static int __init tps65090_init(void)
+{
+	return i2c_add_driver(&tps65090_driver);
+}
+subsys_initcall(tps65090_init);
+
+static void __exit tps65090_exit(void)
+{
+	i2c_del_driver(&tps65090_driver);
+}
+module_exit(tps65090_exit);
+
+MODULE_DESCRIPTION("TPS65090 core driver");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");

+ 242 - 0
drivers/mfd/tps65217.c

@@ -0,0 +1,242 @@
+/*
+ * tps65217.c
+ *
+ * TPS65217 chip family multi-function driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65217.h>
+
+/**
+ * tps65217_reg_read: Read a single tps65217 register.
+ *
+ * @tps: Device to read from.
+ * @reg: Register to read.
+ * @val: Contians the value
+ */
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+			unsigned int *val)
+{
+	return regmap_read(tps->regmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_read);
+
+/**
+ * tps65217_reg_write: Write a single tps65217 register.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+			unsigned int val, unsigned int level)
+{
+	int ret;
+	unsigned int xor_reg_val;
+
+	switch (level) {
+	case TPS65217_PROTECT_NONE:
+		return regmap_write(tps->regmap, reg, val);
+	case TPS65217_PROTECT_L1:
+		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+							xor_reg_val);
+		if (ret < 0)
+			return ret;
+
+		return regmap_write(tps->regmap, reg, val);
+	case TPS65217_PROTECT_L2:
+		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+							xor_reg_val);
+		if (ret < 0)
+			return ret;
+		ret = regmap_write(tps->regmap, reg, val);
+		if (ret < 0)
+			return ret;
+		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+							xor_reg_val);
+		if (ret < 0)
+			return ret;
+		return regmap_write(tps->regmap, reg, val);
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_write);
+
+/**
+ * tps65217_update_bits: Modify bits w.r.t mask, val and level.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to read-write to.
+ * @mask: Mask.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int val, unsigned int level)
+{
+	int ret;
+	unsigned int data;
+
+	ret = tps65217_reg_read(tps, reg, &data);
+	if (ret) {
+		dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
+		return ret;
+	}
+
+	data &= ~mask;
+	data |= val & mask;
+
+	ret = tps65217_reg_write(tps, reg, data, level);
+	if (ret)
+		dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
+
+	return ret;
+}
+
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int val, unsigned int level)
+{
+	return tps65217_update_bits(tps, reg, mask, val, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_set_bits);
+
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int level)
+{
+	return tps65217_update_bits(tps, reg, mask, 0, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_clear_bits);
+
+static struct regmap_config tps65217_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int __devinit tps65217_probe(struct i2c_client *client,
+				const struct i2c_device_id *ids)
+{
+	struct tps65217 *tps;
+	struct tps65217_board *pdata = client->dev.platform_data;
+	int i, ret;
+	unsigned int version;
+
+	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+	if (!tps)
+		return -ENOMEM;
+
+	tps->pdata = pdata;
+	tps->regmap = regmap_init_i2c(client, &tps65217_regmap_config);
+	if (IS_ERR(tps->regmap)) {
+		ret = PTR_ERR(tps->regmap);
+		dev_err(tps->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(client, tps);
+	tps->dev = &client->dev;
+
+	ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
+	if (ret < 0) {
+		dev_err(tps->dev, "Failed to read revision"
+					" register: %d\n", ret);
+		goto err_regmap;
+	}
+
+	dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
+			(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
+			version & TPS65217_CHIPID_REV_MASK);
+
+	for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
+		struct platform_device *pdev;
+
+		pdev = platform_device_alloc("tps65217-pmic", i);
+		if (!pdev) {
+			dev_err(tps->dev, "Cannot create regulator %d\n", i);
+			continue;
+		}
+
+		pdev->dev.parent = tps->dev;
+		platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
+					sizeof(pdata->tps65217_init_data[i]));
+		tps->regulator_pdev[i] = pdev;
+
+		platform_device_add(pdev);
+	}
+
+	return 0;
+
+err_regmap:
+	regmap_exit(tps->regmap);
+
+	return ret;
+}
+
+static int __devexit tps65217_remove(struct i2c_client *client)
+{
+	struct tps65217 *tps = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
+		platform_device_unregister(tps->regulator_pdev[i]);
+
+	regmap_exit(tps->regmap);
+
+	return 0;
+}
+
+static const struct i2c_device_id tps65217_id_table[] = {
+	{"tps65217", 0xF0},
+	{/* end of list */}
+};
+MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
+
+static struct i2c_driver tps65217_driver = {
+	.driver		= {
+		.name	= "tps65217",
+	},
+	.id_table	= tps65217_id_table,
+	.probe		= tps65217_probe,
+	.remove		= __devexit_p(tps65217_remove),
+};
+
+static int __init tps65217_init(void)
+{
+	return i2c_add_driver(&tps65217_driver);
+}
+subsys_initcall(tps65217_init);
+
+static void __exit tps65217_exit(void)
+{
+	i2c_del_driver(&tps65217_driver);
+}
+module_exit(tps65217_exit);
+
+MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
+MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
+MODULE_LICENSE("GPL v2");

+ 11 - 0
drivers/mfd/tps65910-irq.c

@@ -145,12 +145,23 @@ static void tps65910_irq_disable(struct irq_data *data)
 	tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 	tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 }
 }
 
 
+#ifdef CONFIG_PM_SLEEP
+static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
+{
+	struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+	return irq_set_irq_wake(tps65910->chip_irq, enable);
+}
+#else
+#define tps65910_irq_set_wake NULL
+#endif
+
 static struct irq_chip tps65910_irq_chip = {
 static struct irq_chip tps65910_irq_chip = {
 	.name = "tps65910",
 	.name = "tps65910",
 	.irq_bus_lock = tps65910_irq_lock,
 	.irq_bus_lock = tps65910_irq_lock,
 	.irq_bus_sync_unlock = tps65910_irq_sync_unlock,
 	.irq_bus_sync_unlock = tps65910_irq_sync_unlock,
 	.irq_disable = tps65910_irq_disable,
 	.irq_disable = tps65910_irq_disable,
 	.irq_enable = tps65910_irq_enable,
 	.irq_enable = tps65910_irq_enable,
+	.irq_set_wake = tps65910_irq_set_wake,
 };
 };
 
 
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,

+ 46 - 77
drivers/mfd/tps65910.c

@@ -16,10 +16,12 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/core.h>
+#include <linux/regmap.h>
 #include <linux/mfd/tps65910.h>
 #include <linux/mfd/tps65910.h>
 
 
 static struct mfd_cell tps65910s[] = {
 static struct mfd_cell tps65910s[] = {
@@ -38,99 +40,56 @@ static struct mfd_cell tps65910s[] = {
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
 				  int bytes, void *dest)
 				  int bytes, void *dest)
 {
 {
-	struct i2c_client *i2c = tps65910->i2c_client;
-	struct i2c_msg xfer[2];
-	int ret;
-
-	/* Write register */
-	xfer[0].addr = i2c->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = i2c->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = bytes;
-	xfer[1].buf = dest;
-
-	ret = i2c_transfer(i2c->adapter, xfer, 2);
-	if (ret == 2)
-		ret = 0;
-	else if (ret >= 0)
-		ret = -EIO;
-
-	return ret;
+	return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
 }
 }
 
 
 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
-				   int bytes, void *src)
+				  int bytes, void *src)
 {
 {
-	struct i2c_client *i2c = tps65910->i2c_client;
-	/* we add 1 byte for device register */
-	u8 msg[TPS65910_MAX_REGISTER + 1];
-	int ret;
-
-	if (bytes > TPS65910_MAX_REGISTER)
-		return -EINVAL;
-
-	msg[0] = reg;
-	memcpy(&msg[1], src, bytes);
-
-	ret = i2c_master_send(i2c, msg, bytes + 1);
-	if (ret < 0)
-		return ret;
-	if (ret != bytes + 1)
-		return -EIO;
-	return 0;
+	return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
 }
 }
 
 
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
 {
-	u8 data;
-	int err;
-
-	mutex_lock(&tps65910->io_mutex);
-	err = tps65910_i2c_read(tps65910, reg, 1, &data);
-	if (err) {
-		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-		goto out;
-	}
-
-	data |= mask;
-	err = tps65910_i2c_write(tps65910, reg, 1, &data);
-	if (err)
-		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-	mutex_unlock(&tps65910->io_mutex);
-	return err;
+	return regmap_update_bits(tps65910->regmap, reg, mask, mask);
 }
 }
 EXPORT_SYMBOL_GPL(tps65910_set_bits);
 EXPORT_SYMBOL_GPL(tps65910_set_bits);
 
 
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
 {
-	u8 data;
-	int err;
-
-	mutex_lock(&tps65910->io_mutex);
-	err = tps65910_i2c_read(tps65910, reg, 1, &data);
-	if (err) {
-		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-		goto out;
-	}
-
-	data &= ~mask;
-	err = tps65910_i2c_write(tps65910, reg, 1, &data);
-	if (err)
-		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-	mutex_unlock(&tps65910->io_mutex);
-	return err;
+	return regmap_update_bits(tps65910->regmap, reg, mask, 0);
 }
 }
 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
 
 
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct tps65910 *tps65910 = dev_get_drvdata(dev);
+
+	/*
+	 * Caching all regulator registers.
+	 * All regualator register address range is same for
+	 * TPS65910 and TPS65911
+	 */
+	if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
+		/* Check for non-existing register */
+		if (tps65910_chip_id(tps65910) == TPS65910)
+			if ((reg == TPS65911_VDDCTRL_OP) ||
+				(reg == TPS65911_VDDCTRL_SR))
+				return true;
+		return false;
+	}
+	return true;
+}
+
+static const struct regmap_config tps65910_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_reg = is_volatile_reg,
+	.max_register = TPS65910_MAX_REGISTER,
+	.num_reg_defaults_raw = TPS65910_MAX_REGISTER,
+	.cache_type = REGCACHE_RBTREE,
+};
+
 static int tps65910_i2c_probe(struct i2c_client *i2c,
 static int tps65910_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 			    const struct i2c_device_id *id)
 {
 {
@@ -161,6 +120,13 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
 	tps65910->write = tps65910_i2c_write;
 	tps65910->write = tps65910_i2c_write;
 	mutex_init(&tps65910->io_mutex);
 	mutex_init(&tps65910->io_mutex);
 
 
+	tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config);
+	if (IS_ERR(tps65910->regmap)) {
+		ret = PTR_ERR(tps65910->regmap);
+		dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+		goto regmap_err;
+	}
+
 	ret = mfd_add_devices(tps65910->dev, -1,
 	ret = mfd_add_devices(tps65910->dev, -1,
 			      tps65910s, ARRAY_SIZE(tps65910s),
 			      tps65910s, ARRAY_SIZE(tps65910s),
 			      NULL, 0);
 			      NULL, 0);
@@ -178,6 +144,8 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
 	return ret;
 	return ret;
 
 
 err:
 err:
+	regmap_exit(tps65910->regmap);
+regmap_err:
 	kfree(tps65910);
 	kfree(tps65910);
 	kfree(init_data);
 	kfree(init_data);
 	return ret;
 	return ret;
@@ -189,6 +157,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
 
 
 	tps65910_irq_exit(tps65910);
 	tps65910_irq_exit(tps65910);
 	mfd_remove_devices(tps65910->dev);
 	mfd_remove_devices(tps65910->dev);
+	regmap_exit(tps65910->regmap);
 	kfree(tps65910);
 	kfree(tps65910);
 
 
 	return 0;
 	return 0;

+ 69 - 84
drivers/mfd/twl-core.c

@@ -46,9 +46,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <plat/cpu.h>
-#endif
+#include "twl-core.h"
 
 
 /*
 /*
  * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
  * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
@@ -116,8 +114,8 @@
 #define twl_has_watchdog()        false
 #define twl_has_watchdog()        false
 #endif
 #endif
 
 
-#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\
-	defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
+#if defined(CONFIG_MFD_TWL4030_AUDIO) || \
+	defined(CONFIG_MFD_TWL4030_AUDIO_MODULE)
 #define twl_has_codec()	true
 #define twl_has_codec()	true
 #else
 #else
 #define twl_has_codec()	false
 #define twl_has_codec()	false
@@ -147,12 +145,10 @@
 #define SUB_CHIP_ID1 1
 #define SUB_CHIP_ID1 1
 #define SUB_CHIP_ID2 2
 #define SUB_CHIP_ID2 2
 #define SUB_CHIP_ID3 3
 #define SUB_CHIP_ID3 3
+#define SUB_CHIP_ID_INVAL 0xff
 
 
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 
 
-#define TWL4030_NR_IRQS    34 /* core:8, power:8, gpio: 18 */
-#define TWL6030_NR_IRQS    20
-
 /* Base Address defns for twl4030_map[] */
 /* Base Address defns for twl4030_map[] */
 
 
 /* subchip/slave 0 - USB ID */
 /* subchip/slave 0 - USB ID */
@@ -314,7 +310,7 @@ static struct twl_mapping twl6030_map[] = {
 	 * so they continue to match the order in this table.
 	 * so they continue to match the order in this table.
 	 */
 	 */
 	{ SUB_CHIP_ID1, TWL6030_BASEADD_USB },
 	{ SUB_CHIP_ID1, TWL6030_BASEADD_USB },
-	{ SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
+	{ SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
 	{ SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
 	{ SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
 	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
 	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
 	{ SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
 	{ SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
@@ -376,6 +372,11 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
 		return -EPERM;
 		return -EPERM;
 	}
 	}
 	sid = twl_map[mod_no].sid;
 	sid = twl_map[mod_no].sid;
+	if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+		pr_err("%s: module %d is not part of the pmic\n",
+		       DRIVER_NAME, mod_no);
+		return -EINVAL;
+	}
 	twl = &twl_modules[sid];
 	twl = &twl_modules[sid];
 
 
 	mutex_lock(&twl->xfer_lock);
 	mutex_lock(&twl->xfer_lock);
@@ -433,6 +434,11 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
 		return -EPERM;
 		return -EPERM;
 	}
 	}
 	sid = twl_map[mod_no].sid;
 	sid = twl_map[mod_no].sid;
+	if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+		pr_err("%s: module %d is not part of the pmic\n",
+		       DRIVER_NAME, mod_no);
+		return -EINVAL;
+	}
 	twl = &twl_modules[sid];
 	twl = &twl_modules[sid];
 
 
 	mutex_lock(&twl->xfer_lock);
 	mutex_lock(&twl->xfer_lock);
@@ -663,7 +669,8 @@ add_regulator(int num, struct regulator_init_data *pdata,
  */
  */
 
 
 static int
 static int
-add_children(struct twl4030_platform_data *pdata, unsigned long features)
+add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
+		unsigned long features)
 {
 {
 	struct device	*child;
 	struct device	*child;
 	unsigned sub_chip_id;
 	unsigned sub_chip_id;
@@ -671,7 +678,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 	if (twl_has_gpio() && pdata->gpio) {
 	if (twl_has_gpio() && pdata->gpio) {
 		child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
 		child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
 				pdata->gpio, sizeof(*pdata->gpio),
 				pdata->gpio, sizeof(*pdata->gpio),
-				false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
+				false, irq_base + GPIO_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
@@ -679,7 +686,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 	if (twl_has_keypad() && pdata->keypad) {
 	if (twl_has_keypad() && pdata->keypad) {
 		child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
 		child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
 				pdata->keypad, sizeof(*pdata->keypad),
 				pdata->keypad, sizeof(*pdata->keypad),
-				true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
+				true, irq_base + KEYPAD_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
@@ -687,7 +694,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 	if (twl_has_madc() && pdata->madc) {
 	if (twl_has_madc() && pdata->madc) {
 		child = add_child(2, "twl4030_madc",
 		child = add_child(2, "twl4030_madc",
 				pdata->madc, sizeof(*pdata->madc),
 				pdata->madc, sizeof(*pdata->madc),
-				true, pdata->irq_base + MADC_INTR_OFFSET, 0);
+				true, irq_base + MADC_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
@@ -703,7 +710,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 		sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
 		sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
 		child = add_child(sub_chip_id, "twl_rtc",
 		child = add_child(sub_chip_id, "twl_rtc",
 				NULL, 0,
 				NULL, 0,
-				true, pdata->irq_base + RTC_INTR_OFFSET, 0);
+				true, irq_base + RTC_INTR_OFFSET, 0);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
@@ -756,8 +763,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 				pdata->usb, sizeof(*pdata->usb),
 				pdata->usb, sizeof(*pdata->usb),
 				true,
 				true,
 				/* irq0 = USB_PRES, irq1 = USB */
 				/* irq0 = USB_PRES, irq1 = USB */
-				pdata->irq_base + USB_PRES_INTR_OFFSET,
-				pdata->irq_base + USB_INTR_OFFSET);
+				irq_base + USB_PRES_INTR_OFFSET,
+				irq_base + USB_INTR_OFFSET);
 
 
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
@@ -805,8 +812,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 			pdata->usb, sizeof(*pdata->usb),
 			pdata->usb, sizeof(*pdata->usb),
 			true,
 			true,
 			/* irq1 = VBUS_PRES, irq0 = USB ID */
 			/* irq1 = VBUS_PRES, irq0 = USB ID */
-			pdata->irq_base + USBOTG_INTR_OFFSET,
-			pdata->irq_base + USB_PRES_INTR_OFFSET);
+			irq_base + USBOTG_INTR_OFFSET,
+			irq_base + USB_PRES_INTR_OFFSET);
 
 
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
@@ -833,7 +840,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
 
 	if (twl_has_pwrbutton() && twl_class_is_4030()) {
 	if (twl_has_pwrbutton() && twl_class_is_4030()) {
 		child = add_child(1, "twl4030_pwrbutton",
 		child = add_child(1, "twl4030_pwrbutton",
-				NULL, 0, true, pdata->irq_base + 8 + 0, 0);
+				NULL, 0, true, irq_base + 8 + 0, 0);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
@@ -847,15 +854,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
 
 
-	if (twl_has_codec() && pdata->audio && twl_class_is_6030()) {
-		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-		child = add_child(sub_chip_id, "twl6040",
-				pdata->audio, sizeof(*pdata->audio),
-				false, 0, 0);
-		if (IS_ERR(child))
-			return PTR_ERR(child);
-	}
-
 	/* 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,
@@ -1092,8 +1090,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 		child = add_child(3, "twl4030_bci",
 		child = add_child(3, "twl4030_bci",
 				pdata->bci, sizeof(*pdata->bci), false,
 				pdata->bci, sizeof(*pdata->bci), false,
 				/* irq0 = CHG_PRES, irq1 = BCI */
 				/* irq0 = CHG_PRES, irq1 = BCI */
-				pdata->irq_base + BCI_PRES_INTR_OFFSET,
-				pdata->irq_base + BCI_INTR_OFFSET);
+				irq_base + BCI_PRES_INTR_OFFSET,
+				irq_base + BCI_INTR_OFFSET);
 		if (IS_ERR(child))
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
@@ -1193,26 +1191,24 @@ static void clocks_init(struct device *dev,
 
 
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl4030_exit_irq(void);
-int twl4030_init_chip_irq(const char *chip);
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl6030_exit_irq(void);
 
 
 static int twl_remove(struct i2c_client *client)
 static int twl_remove(struct i2c_client *client)
 {
 {
-	unsigned i;
+	unsigned i, num_slaves;
 	int status;
 	int status;
 
 
-	if (twl_class_is_4030())
+	if (twl_class_is_4030()) {
 		status = twl4030_exit_irq();
 		status = twl4030_exit_irq();
-	else
+		num_slaves = TWL_NUM_SLAVES;
+	} else {
 		status = twl6030_exit_irq();
 		status = twl6030_exit_irq();
+		num_slaves = TWL_NUM_SLAVES - 1;
+	}
 
 
 	if (status < 0)
 	if (status < 0)
 		return status;
 		return status;
 
 
-	for (i = 0; i < TWL_NUM_SLAVES; i++) {
+	for (i = 0; i < num_slaves; i++) {
 		struct twl_client	*twl = &twl_modules[i];
 		struct twl_client	*twl = &twl_modules[i];
 
 
 		if (twl->client && twl->client != client)
 		if (twl->client && twl->client != client)
@@ -1223,20 +1219,15 @@ static int twl_remove(struct i2c_client *client)
 	return 0;
 	return 0;
 }
 }
 
 
-/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
+/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
 static int __devinit
 static int __devinit
 twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 {
-	int				status;
-	unsigned			i;
 	struct twl4030_platform_data	*pdata = client->dev.platform_data;
 	struct twl4030_platform_data	*pdata = client->dev.platform_data;
 	struct device_node		*node = client->dev.of_node;
 	struct device_node		*node = client->dev.of_node;
-	u8 temp;
-	int ret = 0;
-	int nr_irqs = TWL4030_NR_IRQS;
-
-	if ((id->driver_data) & TWL6030_CLASS)
-		nr_irqs = TWL6030_NR_IRQS;
+	int				irq_base = 0;
+	int				status;
+	unsigned			i, num_slaves;
 
 
 	if (node && !pdata) {
 	if (node && !pdata) {
 		/*
 		/*
@@ -1255,17 +1246,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
-	if (IS_ERR_VALUE(status)) {
-		dev_err(&client->dev, "Fail to allocate IRQ descs\n");
-		return status;
-	}
-
-	pdata->irq_base = status;
-	pdata->irq_end = pdata->irq_base + nr_irqs;
-	irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
-			      &irq_domain_simple_ops, NULL);
-
 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
 		dev_dbg(&client->dev, "can't talk I2C?\n");
 		dev_dbg(&client->dev, "can't talk I2C?\n");
 		return -EIO;
 		return -EIO;
@@ -1276,13 +1256,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
-	for (i = 0; i < TWL_NUM_SLAVES; i++) {
-		struct twl_client	*twl = &twl_modules[i];
+	if ((id->driver_data) & TWL6030_CLASS) {
+		twl_id = TWL6030_CLASS_ID;
+		twl_map = &twl6030_map[0];
+		num_slaves = TWL_NUM_SLAVES - 1;
+	} else {
+		twl_id = TWL4030_CLASS_ID;
+		twl_map = &twl4030_map[0];
+		num_slaves = TWL_NUM_SLAVES;
+	}
+
+	for (i = 0; i < num_slaves; i++) {
+		struct twl_client *twl = &twl_modules[i];
 
 
 		twl->address = client->addr + i;
 		twl->address = client->addr + i;
-		if (i == 0)
+		if (i == 0) {
 			twl->client = client;
 			twl->client = client;
-		else {
+		} else {
 			twl->client = i2c_new_dummy(client->adapter,
 			twl->client = i2c_new_dummy(client->adapter,
 					twl->address);
 					twl->address);
 			if (!twl->client) {
 			if (!twl->client) {
@@ -1294,22 +1284,16 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		}
 		}
 		mutex_init(&twl->xfer_lock);
 		mutex_init(&twl->xfer_lock);
 	}
 	}
+
 	inuse = true;
 	inuse = true;
-	if ((id->driver_data) & TWL6030_CLASS) {
-		twl_id = TWL6030_CLASS_ID;
-		twl_map = &twl6030_map[0];
-	} else {
-		twl_id = TWL4030_CLASS_ID;
-		twl_map = &twl4030_map[0];
-	}
 
 
 	/* setup clock framework */
 	/* setup clock framework */
 	clocks_init(&client->dev, pdata->clock);
 	clocks_init(&client->dev, pdata->clock);
 
 
 	/* read TWL IDCODE Register */
 	/* read TWL IDCODE Register */
 	if (twl_id == TWL4030_CLASS_ID) {
 	if (twl_id == TWL4030_CLASS_ID) {
-		ret = twl_read_idcode_register();
-		WARN(ret < 0, "Error: reading twl_idcode register value\n");
+		status = twl_read_idcode_register();
+		WARN(status < 0, "Error: reading twl_idcode register value\n");
 	}
 	}
 
 
 	/* load power event scripts */
 	/* load power event scripts */
@@ -1317,31 +1301,31 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		twl4030_power_init(pdata->power);
 		twl4030_power_init(pdata->power);
 
 
 	/* Maybe init the T2 Interrupt subsystem */
 	/* Maybe init the T2 Interrupt subsystem */
-	if (client->irq
-			&& pdata->irq_base
-			&& pdata->irq_end > pdata->irq_base) {
+	if (client->irq) {
 		if (twl_class_is_4030()) {
 		if (twl_class_is_4030()) {
 			twl4030_init_chip_irq(id->name);
 			twl4030_init_chip_irq(id->name);
-			status = twl4030_init_irq(client->irq, pdata->irq_base,
-			pdata->irq_end);
+			irq_base = twl4030_init_irq(&client->dev, client->irq);
 		} else {
 		} else {
-			status = twl6030_init_irq(client->irq, pdata->irq_base,
-			pdata->irq_end);
+			irq_base = twl6030_init_irq(&client->dev, client->irq);
 		}
 		}
 
 
-		if (status < 0)
+		if (irq_base < 0) {
+			status = irq_base;
 			goto fail;
 			goto fail;
+		}
 	}
 	}
 
 
-	/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
+	/*
+	 * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
 	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
 	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
 	 * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
 	 * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
 	 */
 	 */
-
 	if (twl_class_is_4030()) {
 	if (twl_class_is_4030()) {
+		u8 temp;
+
 		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
 		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
 		temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
 		temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
-		I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+			I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
 		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
 		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
 	}
 	}
 
 
@@ -1349,11 +1333,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (node)
 	if (node)
 		status = of_platform_populate(node, NULL, NULL, &client->dev);
 		status = of_platform_populate(node, NULL, NULL, &client->dev);
 	if (status)
 	if (status)
-		status = add_children(pdata, id->driver_data);
+		status = add_children(pdata, irq_base, id->driver_data);
 
 
 fail:
 fail:
 	if (status < 0)
 	if (status < 0)
 		twl_remove(client);
 		twl_remove(client);
+
 	return status;
 	return status;
 }
 }
 
 

+ 2 - 2
drivers/mfd/twl-core.h

@@ -1,9 +1,9 @@
 #ifndef __TWL_CORE_H__
 #ifndef __TWL_CORE_H__
 #define __TWL_CORE_H__
 #define __TWL_CORE_H__
 
 
-extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl6030_init_irq(struct device *dev, int irq_num);
 extern int twl6030_exit_irq(void);
 extern int twl6030_exit_irq(void);
-extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl4030_init_irq(struct device *dev, int irq_num);
 extern int twl4030_exit_irq(void);
 extern int twl4030_exit_irq(void);
 extern int twl4030_init_chip_irq(const char *chip);
 extern int twl4030_init_chip_irq(const char *chip);
 
 

+ 60 - 47
drivers/mfd/twl4030-irq.c

@@ -28,10 +28,12 @@
  */
  */
 
 
 #include <linux/init.h>
 #include <linux/init.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
-
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 
 
 #include "twl-core.h"
 #include "twl-core.h"
@@ -53,13 +55,14 @@
  *	base + 8  .. base + 15	SIH for PWR_INT
  *	base + 8  .. base + 15	SIH for PWR_INT
  *	base + 16 .. base + 33	SIH for GPIO
  *	base + 16 .. base + 33	SIH for GPIO
  */
  */
+#define TWL4030_CORE_NR_IRQS	8
+#define TWL4030_PWR_NR_IRQS	8
 
 
 /* PIH register offsets */
 /* PIH register offsets */
 #define REG_PIH_ISR_P1			0x01
 #define REG_PIH_ISR_P1			0x01
 #define REG_PIH_ISR_P2			0x02
 #define REG_PIH_ISR_P2			0x02
 #define REG_PIH_SIR			0x03	/* for testing */
 #define REG_PIH_SIR			0x03	/* for testing */
 
 
-
 /* Linux could (eventually) use either IRQ line */
 /* Linux could (eventually) use either IRQ line */
 static int irq_line;
 static int irq_line;
 
 
@@ -111,7 +114,8 @@ static int nr_sih_modules;
 #define TWL4030_MODULE_INT_PWR		TWL4030_MODULE_INT
 #define TWL4030_MODULE_INT_PWR		TWL4030_MODULE_INT
 
 
 
 
-/* Order in this table matches order in PIH_ISR.  That is,
+/*
+ * Order in this table matches order in PIH_ISR.  That is,
  * BIT(n) in PIH_ISR is sih_modules[n].
  * BIT(n) in PIH_ISR is sih_modules[n].
  */
  */
 /* sih_modules_twl4030 is used both in twl4030 and twl5030 */
 /* sih_modules_twl4030 is used both in twl4030 and twl5030 */
@@ -288,7 +292,6 @@ static unsigned twl4030_irq_base;
  */
  */
 static irqreturn_t handle_twl4030_pih(int irq, void *devid)
 static irqreturn_t handle_twl4030_pih(int irq, void *devid)
 {
 {
-	int		module_irq;
 	irqreturn_t	ret;
 	irqreturn_t	ret;
 	u8		pih_isr;
 	u8		pih_isr;
 
 
@@ -299,16 +302,18 @@ static irqreturn_t handle_twl4030_pih(int irq, void *devid)
 		return IRQ_NONE;
 		return IRQ_NONE;
 	}
 	}
 
 
-	/* these handlers deal with the relevant SIH irq status */
-	for (module_irq = twl4030_irq_base;
-			pih_isr;
-			pih_isr >>= 1, module_irq++) {
-		if (pih_isr & 0x1)
-			handle_nested_irq(module_irq);
+	while (pih_isr) {
+		unsigned long	pending = __ffs(pih_isr);
+		unsigned int	irq;
+
+		pih_isr &= ~BIT(pending);
+		irq = pending + twl4030_irq_base;
+		handle_nested_irq(irq);
 	}
 	}
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
+
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
 /*
 /*
@@ -337,7 +342,6 @@ static int twl4030_init_sih_modules(unsigned line)
 	memset(buf, 0xff, sizeof buf);
 	memset(buf, 0xff, sizeof buf);
 	sih = sih_modules;
 	sih = sih_modules;
 	for (i = 0; i < nr_sih_modules; i++, sih++) {
 	for (i = 0; i < nr_sih_modules; i++, sih++) {
-
 		/* skip USB -- it's funky */
 		/* skip USB -- it's funky */
 		if (!sih->bytes_ixr)
 		if (!sih->bytes_ixr)
 			continue;
 			continue;
@@ -352,7 +356,8 @@ static int twl4030_init_sih_modules(unsigned line)
 			pr_err("twl4030: err %d initializing %s %s\n",
 			pr_err("twl4030: err %d initializing %s %s\n",
 					status, sih->name, "IMR");
 					status, sih->name, "IMR");
 
 
-		/* Maybe disable "exclusive" mode; buffer second pending irq;
+		/*
+		 * Maybe disable "exclusive" mode; buffer second pending irq;
 		 * set Clear-On-Read (COR) bit.
 		 * set Clear-On-Read (COR) bit.
 		 *
 		 *
 		 * NOTE that sometimes COR polarity is documented as being
 		 * NOTE that sometimes COR polarity is documented as being
@@ -382,7 +387,8 @@ static int twl4030_init_sih_modules(unsigned line)
 		if (sih->irq_lines <= line)
 		if (sih->irq_lines <= line)
 			continue;
 			continue;
 
 
-		/* Clear pending interrupt status.  Either the read was
+		/*
+		 * Clear pending interrupt status.  Either the read was
 		 * enough, or we need to write those bits.  Repeat, in
 		 * enough, or we need to write those bits.  Repeat, in
 		 * case an IRQ is pending (PENDDIS=0) ... that's not
 		 * case an IRQ is pending (PENDDIS=0) ... that's not
 		 * uncommon with PWR_INT.PWRON.
 		 * uncommon with PWR_INT.PWRON.
@@ -398,7 +404,8 @@ static int twl4030_init_sih_modules(unsigned line)
 				status = twl_i2c_write(sih->module, buf,
 				status = twl_i2c_write(sih->module, buf,
 					sih->mask[line].isr_offset,
 					sih->mask[line].isr_offset,
 					sih->bytes_ixr);
 					sih->bytes_ixr);
-			/* else COR=1 means read sufficed.
+			/*
+			 * else COR=1 means read sufficed.
 			 * (for most SIH modules...)
 			 * (for most SIH modules...)
 			 */
 			 */
 		}
 		}
@@ -410,7 +417,8 @@ static int twl4030_init_sih_modules(unsigned line)
 static inline void activate_irq(int irq)
 static inline void activate_irq(int irq)
 {
 {
 #ifdef CONFIG_ARM
 #ifdef CONFIG_ARM
-	/* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+	/*
+	 * ARM requires an extra step to clear IRQ_NOREQUEST, which it
 	 * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
 	 * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
 	 */
 	 */
 	set_irq_flags(irq, IRQF_VALID);
 	set_irq_flags(irq, IRQF_VALID);
@@ -620,33 +628,24 @@ static irqreturn_t handle_twl4030_sih(int irq, void *data)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-static unsigned twl4030_irq_next;
-
-/* returns the first IRQ used by this SIH bank,
- * or negative errno
- */
-int twl4030_sih_setup(int module)
+/* returns the first IRQ used by this SIH bank, or negative errno */
+int twl4030_sih_setup(struct device *dev, int module, int irq_base)
 {
 {
 	int			sih_mod;
 	int			sih_mod;
 	const struct sih	*sih = NULL;
 	const struct sih	*sih = NULL;
 	struct sih_agent	*agent;
 	struct sih_agent	*agent;
 	int			i, irq;
 	int			i, irq;
 	int			status = -EINVAL;
 	int			status = -EINVAL;
-	unsigned		irq_base = twl4030_irq_next;
 
 
 	/* only support modules with standard clear-on-read for now */
 	/* only support modules with standard clear-on-read for now */
-	for (sih_mod = 0, sih = sih_modules;
-			sih_mod < nr_sih_modules;
+	for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;
 			sih_mod++, sih++) {
 			sih_mod++, sih++) {
 		if (sih->module == module && sih->set_cor) {
 		if (sih->module == module && sih->set_cor) {
-			if (!WARN((irq_base + sih->bits) > NR_IRQS,
-					"irq %d for %s too big\n",
-					irq_base + sih->bits,
-					sih->name))
-				status = 0;
+			status = 0;
 			break;
 			break;
 		}
 		}
 	}
 	}
+
 	if (status < 0)
 	if (status < 0)
 		return status;
 		return status;
 
 
@@ -654,8 +653,6 @@ int twl4030_sih_setup(int module)
 	if (!agent)
 	if (!agent)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	status = 0;
-
 	agent->irq_base = irq_base;
 	agent->irq_base = irq_base;
 	agent->sih = sih;
 	agent->sih = sih;
 	agent->imr = ~0;
 	agent->imr = ~0;
@@ -671,8 +668,6 @@ int twl4030_sih_setup(int module)
 		activate_irq(irq);
 		activate_irq(irq);
 	}
 	}
 
 
-	twl4030_irq_next += i;
-
 	/* replace generic PIH handler (handle_simple_irq) */
 	/* replace generic PIH handler (handle_simple_irq) */
 	irq = sih_mod + twl4030_irq_base;
 	irq = sih_mod + twl4030_irq_base;
 	irq_set_handler_data(irq, agent);
 	irq_set_handler_data(irq, agent);
@@ -680,26 +675,43 @@ int twl4030_sih_setup(int module)
 	status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
 	status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
 				      agent->irq_name ?: sih->name, NULL);
 				      agent->irq_name ?: sih->name, NULL);
 
 
-	pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
-			irq, irq_base, twl4030_irq_next - 1);
+	dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
+			irq, irq_base, irq_base + i - 1);
 
 
 	return status < 0 ? status : irq_base;
 	return status < 0 ? status : irq_base;
 }
 }
 
 
 /* FIXME need a call to reverse twl4030_sih_setup() ... */
 /* FIXME need a call to reverse twl4030_sih_setup() ... */
 
 
-
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
 /* FIXME pass in which interrupt line we'll use ... */
 /* FIXME pass in which interrupt line we'll use ... */
 #define twl_irq_line	0
 #define twl_irq_line	0
 
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl4030_init_irq(struct device *dev, int irq_num)
 {
 {
 	static struct irq_chip	twl4030_irq_chip;
 	static struct irq_chip	twl4030_irq_chip;
+	int			status, i;
+	int			irq_base, irq_end, nr_irqs;
+	struct			device_node *node = dev->of_node;
 
 
-	int			status;
-	int			i;
+	/*
+	 * TWL core and pwr interrupts must be contiguous because
+	 * the hwirqs numbers are defined contiguously from 1 to 15.
+	 * Create only one domain for both.
+	 */
+	nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
+
+	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+	if (IS_ERR_VALUE(irq_base)) {
+		dev_err(dev, "Fail to allocate IRQ descs\n");
+		return irq_base;
+	}
+
+	irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+			      &irq_domain_simple_ops, NULL);
+
+	irq_end = irq_base + TWL4030_CORE_NR_IRQS;
 
 
 	/*
 	/*
 	 * Mask and clear all TWL4030 interrupts since initially we do
 	 * Mask and clear all TWL4030 interrupts since initially we do
@@ -711,7 +723,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 
 
 	twl4030_irq_base = irq_base;
 	twl4030_irq_base = irq_base;
 
 
-	/* install an irq handler for each of the SIH modules;
+	/*
+	 * Install an irq handler for each of the SIH modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 */
 	 */
 	twl4030_irq_chip = dummy_irq_chip;
 	twl4030_irq_chip = dummy_irq_chip;
@@ -725,14 +738,14 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 		irq_set_nested_thread(i, 1);
 		irq_set_nested_thread(i, 1);
 		activate_irq(i);
 		activate_irq(i);
 	}
 	}
-	twl4030_irq_next = i;
-	pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-			irq_num, irq_base, twl4030_irq_next - 1);
+
+	dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",
+			irq_num, irq_base, irq_end);
 
 
 	/* ... and the PWR_INT module ... */
 	/* ... and the PWR_INT module ... */
-	status = twl4030_sih_setup(TWL4030_MODULE_INT);
+	status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);
 	if (status < 0) {
 	if (status < 0) {
-		pr_err("twl4030: sih_setup PWR INT --> %d\n", status);
+		dev_err(dev, "sih_setup PWR INT --> %d\n", status);
 		goto fail;
 		goto fail;
 	}
 	}
 
 
@@ -741,11 +754,11 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 				      IRQF_ONESHOT,
 				      IRQF_ONESHOT,
 				      "TWL4030-PIH", NULL);
 				      "TWL4030-PIH", NULL);
 	if (status < 0) {
 	if (status < 0) {
-		pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
+		dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);
 		goto fail_rqirq;
 		goto fail_rqirq;
 	}
 	}
 
 
-	return status;
+	return irq_base;
 fail_rqirq:
 fail_rqirq:
 	/* clean up twl4030_sih_setup */
 	/* clean up twl4030_sih_setup */
 fail:
 fail:

+ 54 - 32
drivers/mfd/twl6030-irq.c

@@ -39,6 +39,8 @@
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
 #include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 
 #include "twl-core.h"
 #include "twl-core.h"
 
 
@@ -51,8 +53,8 @@
  *
  *
  * We set up IRQs starting at a platform-specified base. An interrupt map table,
  * We set up IRQs starting at a platform-specified base. An interrupt map table,
  * specifies mapping between interrupt number and the associated module.
  * specifies mapping between interrupt number and the associated module.
- *
  */
  */
+#define TWL6030_NR_IRQS    20
 
 
 static int twl6030_interrupt_mapping[24] = {
 static int twl6030_interrupt_mapping[24] = {
 	PWR_INTR_OFFSET,	/* Bit 0	PWRON			*/
 	PWR_INTR_OFFSET,	/* Bit 0	PWRON			*/
@@ -185,8 +187,17 @@ static int twl6030_irq_thread(void *data)
 			}
 			}
 		local_irq_enable();
 		local_irq_enable();
 		}
 		}
-		ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
-				REG_INT_STS_A, 3); /* clear INT_STS_A */
+
+		/*
+		 * NOTE:
+		 * Simulation confirms that documentation is wrong w.r.t the
+		 * interrupt status clear operation. A single *byte* write to
+		 * any one of STS_A to STS_C register results in all three
+		 * STS registers being reset. Since it does not matter which
+		 * value is written, all three registers are cleared on a
+		 * single byte write, so we just use 0x0 to clear.
+		 */
+		ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
 		if (ret)
 		if (ret)
 			pr_warning("twl6030: I2C error in clearing PIH ISR\n");
 			pr_warning("twl6030: I2C error in clearing PIH ISR\n");
 
 
@@ -227,7 +238,7 @@ static inline void activate_irq(int irq)
 #endif
 #endif
 }
 }
 
 
-int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
+static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
 {
 	if (on)
 	if (on)
 		atomic_inc(&twl6030_wakeirqs);
 		atomic_inc(&twl6030_wakeirqs);
@@ -237,11 +248,6 @@ int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 	return 0;
 	return 0;
 }
 }
 
 
-/*----------------------------------------------------------------------*/
-
-static unsigned twl6030_irq_next;
-
-/*----------------------------------------------------------------------*/
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
 {
 {
 	int ret;
 	int ret;
@@ -311,7 +317,8 @@ int twl6030_mmc_card_detect_config(void)
 									ret);
 									ret);
 		return ret;
 		return ret;
 	}
 	}
-	return 0;
+
+	return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
 }
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
 
@@ -340,29 +347,44 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
 
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl6030_init_irq(struct device *dev, int irq_num)
 {
 {
-
-	int	status = 0;
-	int	i;
+	struct			device_node *node = dev->of_node;
+	int			nr_irqs, irq_base, irq_end;
 	struct task_struct	*task;
 	struct task_struct	*task;
-	int ret;
-	u8 mask[4];
+	static struct irq_chip  twl6030_irq_chip;
+	int			status = 0;
+	int			i;
+	u8			mask[4];
+
+	nr_irqs = TWL6030_NR_IRQS;
+
+	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+	if (IS_ERR_VALUE(irq_base)) {
+		dev_err(dev, "Fail to allocate IRQ descs\n");
+		return irq_base;
+	}
+
+	irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+			      &irq_domain_simple_ops, NULL);
+
+	irq_end = irq_base + nr_irqs;
 
 
-	static struct irq_chip	twl6030_irq_chip;
 	mask[1] = 0xFF;
 	mask[1] = 0xFF;
 	mask[2] = 0xFF;
 	mask[2] = 0xFF;
 	mask[3] = 0xFF;
 	mask[3] = 0xFF;
-	ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-			REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
-	ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-			REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
-	ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-			REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
+
+	/* mask all int lines */
+	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+	/* mask all int sts */
+	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+	/* clear INT_STS_A,B,C */
+	twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
 
 
 	twl6030_irq_base = irq_base;
 	twl6030_irq_base = irq_base;
 
 
-	/* install an irq handler for each of the modules;
+	/*
+	 * install an irq handler for each of the modules;
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 * clone dummy irq_chip since PIH can't *do* anything
 	 */
 	 */
 	twl6030_irq_chip = dummy_irq_chip;
 	twl6030_irq_chip = dummy_irq_chip;
@@ -377,30 +399,29 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 		activate_irq(i);
 		activate_irq(i);
 	}
 	}
 
 
-	twl6030_irq_next = i;
-	pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-			irq_num, irq_base, twl6030_irq_next - 1);
+	dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
+			irq_num, irq_base, irq_end);
 
 
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
 	/* install an irq handler to demultiplex the TWL6030 interrupt */
 	init_completion(&irq_event);
 	init_completion(&irq_event);
 
 
-	status = request_irq(irq_num, handle_twl6030_pih, 0,
-				"TWL6030-PIH", &irq_event);
+	status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
+			     &irq_event);
 	if (status < 0) {
 	if (status < 0) {
-		pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
+		dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
 		goto fail_irq;
 		goto fail_irq;
 	}
 	}
 
 
 	task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
 	task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
 	if (IS_ERR(task)) {
 	if (IS_ERR(task)) {
-		pr_err("twl6030: could not create irq %d thread!\n", irq_num);
+		dev_err(dev, "could not create irq %d thread!\n", irq_num);
 		status = PTR_ERR(task);
 		status = PTR_ERR(task);
 		goto fail_kthread;
 		goto fail_kthread;
 	}
 	}
 
 
 	twl_irq = irq_num;
 	twl_irq = irq_num;
 	register_pm_notifier(&twl6030_irq_pm_notifier_block);
 	register_pm_notifier(&twl6030_irq_pm_notifier_block);
-	return status;
+	return irq_base;
 
 
 fail_kthread:
 fail_kthread:
 	free_irq(irq_num, &irq_event);
 	free_irq(irq_num, &irq_event);
@@ -408,6 +429,7 @@ fail_kthread:
 fail_irq:
 fail_irq:
 	for (i = irq_base; i < irq_end; i++)
 	for (i = irq_base; i < irq_end; i++)
 		irq_set_chip_and_handler(i, NULL, NULL);
 		irq_set_chip_and_handler(i, NULL, NULL);
+
 	return status;
 	return status;
 }
 }
 
 

+ 1 - 1
drivers/mfd/wm831x-spi.c

@@ -89,7 +89,7 @@ static const struct spi_device_id wm831x_spi_ids[] = {
 	{ "wm8326", WM8326 },
 	{ "wm8326", WM8326 },
 	{ },
 	{ },
 };
 };
-MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
+MODULE_DEVICE_TABLE(spi, wm831x_spi_ids);
 
 
 static struct spi_driver wm831x_spi_driver = {
 static struct spi_driver wm831x_spi_driver = {
 	.driver = {
 	.driver = {

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

@@ -271,8 +271,7 @@ static int wm8400_init(struct wm8400 *wm8400,
 		return -EIO;
 		return -EIO;
 	}
 	}
 	if (i != reg_data[WM8400_RESET_ID].default_val) {
 	if (i != reg_data[WM8400_RESET_ID].default_val) {
-		dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
-			reg);
+		dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", i);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 

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

@@ -639,7 +639,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
 	}
 	}
 
 
 	pm_runtime_enable(wm8994->dev);
 	pm_runtime_enable(wm8994->dev);
-	pm_runtime_resume(wm8994->dev);
+	pm_runtime_idle(wm8994->dev);
 
 
 	return 0;
 	return 0;
 
 

+ 2 - 18
drivers/mfd/wm8994-regmap.c

@@ -20,7 +20,6 @@
 #include "wm8994.h"
 #include "wm8994.h"
 
 
 static struct reg_default wm1811_defaults[] = {
 static struct reg_default wm1811_defaults[] = {
-	{ 0x0000, 0x1811 },    /* R0    - Software Reset */
 	{ 0x0001, 0x0000 },    /* R1    - Power Management (1) */
 	{ 0x0001, 0x0000 },    /* R1    - Power Management (1) */
 	{ 0x0002, 0x6000 },    /* R2    - Power Management (2) */
 	{ 0x0002, 0x6000 },    /* R2    - Power Management (2) */
 	{ 0x0003, 0x0000 },    /* R3    - Power Management (3) */
 	{ 0x0003, 0x0000 },    /* R3    - Power Management (3) */
@@ -61,7 +60,7 @@ static struct reg_default wm1811_defaults[] = {
 	{ 0x0036, 0x0000 },    /* R54   - Speaker Mixer */
 	{ 0x0036, 0x0000 },    /* R54   - Speaker Mixer */
 	{ 0x0037, 0x0000 },    /* R55   - Additional Control */
 	{ 0x0037, 0x0000 },    /* R55   - Additional Control */
 	{ 0x0038, 0x0000 },    /* R56   - AntiPOP (1) */
 	{ 0x0038, 0x0000 },    /* R56   - AntiPOP (1) */
-	{ 0x0039, 0x0180 },    /* R57   - AntiPOP (2) */
+	{ 0x0039, 0x0000 },    /* R57   - AntiPOP (2) */
 	{ 0x003B, 0x000D },    /* R59   - LDO 1 */
 	{ 0x003B, 0x000D },    /* R59   - LDO 1 */
 	{ 0x003C, 0x0003 },    /* R60   - LDO 2 */
 	{ 0x003C, 0x0003 },    /* R60   - LDO 2 */
 	{ 0x003D, 0x0039 },    /* R61   - MICBIAS1 */
 	{ 0x003D, 0x0039 },    /* R61   - MICBIAS1 */
@@ -69,16 +68,12 @@ static struct reg_default wm1811_defaults[] = {
 	{ 0x004C, 0x1F25 },    /* R76   - Charge Pump (1) */
 	{ 0x004C, 0x1F25 },    /* R76   - Charge Pump (1) */
 	{ 0x004D, 0xAB19 },    /* R77   - Charge Pump (2) */
 	{ 0x004D, 0xAB19 },    /* R77   - Charge Pump (2) */
 	{ 0x0051, 0x0004 },    /* R81   - Class W (1) */
 	{ 0x0051, 0x0004 },    /* R81   - Class W (1) */
-	{ 0x0054, 0x0000 },    /* R84   - DC Servo (1) */
 	{ 0x0055, 0x054A },    /* R85   - DC Servo (2) */
 	{ 0x0055, 0x054A },    /* R85   - DC Servo (2) */
-	{ 0x0058, 0x0000 },    /* R88   - DC Servo Readback */
 	{ 0x0059, 0x0000 },    /* R89   - DC Servo (4) */
 	{ 0x0059, 0x0000 },    /* R89   - DC Servo (4) */
 	{ 0x0060, 0x0000 },    /* R96   - Analogue HP (1) */
 	{ 0x0060, 0x0000 },    /* R96   - Analogue HP (1) */
 	{ 0x00C5, 0x0000 },    /* R197  - Class D Test (5) */
 	{ 0x00C5, 0x0000 },    /* R197  - Class D Test (5) */
 	{ 0x00D0, 0x7600 },    /* R208  - Mic Detect 1 */
 	{ 0x00D0, 0x7600 },    /* R208  - Mic Detect 1 */
 	{ 0x00D1, 0x007F },    /* R209  - Mic Detect 2 */
 	{ 0x00D1, 0x007F },    /* R209  - Mic Detect 2 */
-	{ 0x00D2, 0x0000 },    /* R210  - Mic Detect 3 */
-	{ 0x0100, 0x0100 },    /* R256  - Chip Revision */
 	{ 0x0101, 0x8004 },    /* R257  - Control Interface */
 	{ 0x0101, 0x8004 },    /* R257  - Control Interface */
 	{ 0x0200, 0x0000 },    /* R512  - AIF1 Clocking (1) */
 	{ 0x0200, 0x0000 },    /* R512  - AIF1 Clocking (1) */
 	{ 0x0201, 0x0000 },    /* R513  - AIF1 Clocking (2) */
 	{ 0x0201, 0x0000 },    /* R513  - AIF1 Clocking (2) */
@@ -88,7 +83,6 @@ static struct reg_default wm1811_defaults[] = {
 	{ 0x0209, 0x0000 },    /* R521  - Clocking (2) */
 	{ 0x0209, 0x0000 },    /* R521  - Clocking (2) */
 	{ 0x0210, 0x0083 },    /* R528  - AIF1 Rate */
 	{ 0x0210, 0x0083 },    /* R528  - AIF1 Rate */
 	{ 0x0211, 0x0083 },    /* R529  - AIF2 Rate */
 	{ 0x0211, 0x0083 },    /* R529  - AIF2 Rate */
-	{ 0x0212, 0x0000 },    /* R530  - Rate Status */
 	{ 0x0220, 0x0000 },    /* R544  - FLL1 Control (1) */
 	{ 0x0220, 0x0000 },    /* R544  - FLL1 Control (1) */
 	{ 0x0221, 0x0000 },    /* R545  - FLL1 Control (2) */
 	{ 0x0221, 0x0000 },    /* R545  - FLL1 Control (2) */
 	{ 0x0222, 0x0000 },    /* R546  - FLL1 Control (3) */
 	{ 0x0222, 0x0000 },    /* R546  - FLL1 Control (3) */
@@ -218,8 +212,6 @@ static struct reg_default wm1811_defaults[] = {
 	{ 0x070A, 0xA101 },    /* R1802 - GPIO 11 */
 	{ 0x070A, 0xA101 },    /* R1802 - GPIO 11 */
 	{ 0x0720, 0x0000 },    /* R1824 - Pull Control (1) */
 	{ 0x0720, 0x0000 },    /* R1824 - Pull Control (1) */
 	{ 0x0721, 0x0156 },    /* R1825 - Pull Control (2) */
 	{ 0x0721, 0x0156 },    /* R1825 - Pull Control (2) */
-	{ 0x0730, 0x0000 },    /* R1840 - Interrupt Status 1 */
-	{ 0x0731, 0x0000 },    /* R1841 - Interrupt Status 2 */
 	{ 0x0732, 0x0000 },    /* R1842 - Interrupt Raw Status 2 */
 	{ 0x0732, 0x0000 },    /* R1842 - Interrupt Raw Status 2 */
 	{ 0x0738, 0x07FF },    /* R1848 - Interrupt Status 1 Mask */
 	{ 0x0738, 0x07FF },    /* R1848 - Interrupt Status 1 Mask */
 	{ 0x0739, 0xDFEF },    /* R1849 - Interrupt Status 2 Mask */
 	{ 0x0739, 0xDFEF },    /* R1849 - Interrupt Status 2 Mask */
@@ -228,7 +220,6 @@ static struct reg_default wm1811_defaults[] = {
 };
 };
 
 
 static struct reg_default wm8994_defaults[] = {
 static struct reg_default wm8994_defaults[] = {
-	{ 0x0000, 0x8994 },    /* R0     - Software Reset */ 
 	{ 0x0001, 0x0000 },    /* R1     - Power Management (1) */ 
 	{ 0x0001, 0x0000 },    /* R1     - Power Management (1) */ 
 	{ 0x0002, 0x6000 },    /* R2     - Power Management (2) */ 
 	{ 0x0002, 0x6000 },    /* R2     - Power Management (2) */ 
 	{ 0x0003, 0x0000 },    /* R3     - Power Management (3) */ 
 	{ 0x0003, 0x0000 },    /* R3     - Power Management (3) */ 
@@ -275,12 +266,9 @@ static struct reg_default wm8994_defaults[] = {
 	{ 0x003C, 0x0003 },    /* R60    - LDO 2 */ 
 	{ 0x003C, 0x0003 },    /* R60    - LDO 2 */ 
 	{ 0x004C, 0x1F25 },    /* R76    - Charge Pump (1) */ 
 	{ 0x004C, 0x1F25 },    /* R76    - Charge Pump (1) */ 
 	{ 0x0051, 0x0004 },    /* R81    - Class W (1) */ 
 	{ 0x0051, 0x0004 },    /* R81    - Class W (1) */ 
-	{ 0x0054, 0x0000 },    /* R84    - DC Servo (1) */ 
 	{ 0x0055, 0x054A },    /* R85    - DC Servo (2) */ 
 	{ 0x0055, 0x054A },    /* R85    - DC Servo (2) */ 
 	{ 0x0057, 0x0000 },    /* R87    - DC Servo (4) */ 
 	{ 0x0057, 0x0000 },    /* R87    - DC Servo (4) */ 
-	{ 0x0058, 0x0000 },    /* R88    - DC Servo Readback */ 
 	{ 0x0060, 0x0000 },    /* R96    - Analogue HP (1) */ 
 	{ 0x0060, 0x0000 },    /* R96    - Analogue HP (1) */ 
-	{ 0x0100, 0x0003 },    /* R256   - Chip Revision */ 
 	{ 0x0101, 0x8004 },    /* R257   - Control Interface */ 
 	{ 0x0101, 0x8004 },    /* R257   - Control Interface */ 
 	{ 0x0110, 0x0000 },    /* R272   - Write Sequencer Ctrl (1) */ 
 	{ 0x0110, 0x0000 },    /* R272   - Write Sequencer Ctrl (1) */ 
 	{ 0x0111, 0x0000 },    /* R273   - Write Sequencer Ctrl (2) */ 
 	{ 0x0111, 0x0000 },    /* R273   - Write Sequencer Ctrl (2) */ 
@@ -292,7 +280,6 @@ static struct reg_default wm8994_defaults[] = {
 	{ 0x0209, 0x0000 },    /* R521   - Clocking (2) */ 
 	{ 0x0209, 0x0000 },    /* R521   - Clocking (2) */ 
 	{ 0x0210, 0x0083 },    /* R528   - AIF1 Rate */ 
 	{ 0x0210, 0x0083 },    /* R528   - AIF1 Rate */ 
 	{ 0x0211, 0x0083 },    /* R529   - AIF2 Rate */ 
 	{ 0x0211, 0x0083 },    /* R529   - AIF2 Rate */ 
-	{ 0x0212, 0x0000 },    /* R530   - Rate Status */ 
 	{ 0x0220, 0x0000 },    /* R544   - FLL1 Control (1) */ 
 	{ 0x0220, 0x0000 },    /* R544   - FLL1 Control (1) */ 
 	{ 0x0221, 0x0000 },    /* R545   - FLL1 Control (2) */ 
 	{ 0x0221, 0x0000 },    /* R545   - FLL1 Control (2) */ 
 	{ 0x0222, 0x0000 },    /* R546   - FLL1 Control (3) */ 
 	{ 0x0222, 0x0000 },    /* R546   - FLL1 Control (3) */ 
@@ -445,9 +432,6 @@ static struct reg_default wm8994_defaults[] = {
 	{ 0x070A, 0xA101 },    /* R1802  - GPIO 11 */ 
 	{ 0x070A, 0xA101 },    /* R1802  - GPIO 11 */ 
 	{ 0x0720, 0x0000 },    /* R1824  - Pull Control (1) */ 
 	{ 0x0720, 0x0000 },    /* R1824  - Pull Control (1) */ 
 	{ 0x0721, 0x0156 },    /* R1825  - Pull Control (2) */ 
 	{ 0x0721, 0x0156 },    /* R1825  - Pull Control (2) */ 
-	{ 0x0730, 0x0000 },    /* R1840  - Interrupt Status 1 */ 
-	{ 0x0731, 0x0000 },    /* R1841  - Interrupt Status 2 */ 
-	{ 0x0732, 0x0000 },    /* R1842  - Interrupt Raw Status 2 */ 
 	{ 0x0738, 0x07FF },    /* R1848  - Interrupt Status 1 Mask */ 
 	{ 0x0738, 0x07FF },    /* R1848  - Interrupt Status 1 Mask */ 
 	{ 0x0739, 0xFFFF },    /* R1849  - Interrupt Status 2 Mask */ 
 	{ 0x0739, 0xFFFF },    /* R1849  - Interrupt Status 2 Mask */ 
 	{ 0x0740, 0x0000 },    /* R1856  - Interrupt Control */ 
 	{ 0x0740, 0x0000 },    /* R1856  - Interrupt Control */ 
@@ -455,7 +439,6 @@ static struct reg_default wm8994_defaults[] = {
 };
 };
 
 
 static struct reg_default wm8958_defaults[] = {
 static struct reg_default wm8958_defaults[] = {
-	{ 0x0000, 0x8958 },    /* R0     - Software Reset */ 
 	{ 0x0001, 0x0000 },    /* R1     - Power Management (1) */
 	{ 0x0001, 0x0000 },    /* R1     - Power Management (1) */
 	{ 0x0002, 0x6000 },    /* R2     - Power Management (2) */
 	{ 0x0002, 0x6000 },    /* R2     - Power Management (2) */
 	{ 0x0003, 0x0000 },    /* R3     - Power Management (3) */
 	{ 0x0003, 0x0000 },    /* R3     - Power Management (3) */
@@ -970,6 +953,7 @@ static bool wm8994_readable_register(struct device *dev, unsigned int reg)
 {
 {
 	switch (reg) {
 	switch (reg) {
 	case WM8994_DC_SERVO_READBACK:
 	case WM8994_DC_SERVO_READBACK:
+	case WM8994_MICBIAS:
 	case WM8994_WRITE_SEQUENCER_CTRL_1:
 	case WM8994_WRITE_SEQUENCER_CTRL_1:
 	case WM8994_WRITE_SEQUENCER_CTRL_2:
 	case WM8994_WRITE_SEQUENCER_CTRL_2:
 	case WM8994_AIF1_ADC2_LEFT_VOLUME:
 	case WM8994_AIF1_ADC2_LEFT_VOLUME:

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

@@ -376,6 +376,9 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
 	INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
 	INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
 	schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
 	schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
 #endif	/* VRTC_CALIBRATION */
 #endif	/* VRTC_CALIBRATION */
+
+	device_init_wakeup(&pdev->dev, 1);
+
 	return 0;
 	return 0;
 out_rtc:
 out_rtc:
 	free_irq(info->irq, info);
 	free_irq(info->irq, info);
@@ -401,10 +404,34 @@ static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_rtc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag |= 1 << PM8607_IRQ_RTC;
+	return 0;
+}
+static int pm860x_rtc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+	if (device_may_wakeup(dev))
+		chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume);
+
 static struct platform_driver pm860x_rtc_driver = {
 static struct platform_driver pm860x_rtc_driver = {
 	.driver		= {
 	.driver		= {
 		.name	= "88pm860x-rtc",
 		.name	= "88pm860x-rtc",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
+		.pm	= &pm860x_rtc_pm_ops,
 	},
 	},
 	.probe		= pm860x_rtc_probe,
 	.probe		= pm860x_rtc_probe,
 	.remove		= __devexit_p(pm860x_rtc_remove),
 	.remove		= __devexit_p(pm860x_rtc_remove),

+ 28 - 21
drivers/video/backlight/88pm860x_bl.c

@@ -67,6 +67,28 @@ static inline int wled_idc(int port)
 	return ret;
 	return ret;
 }
 }
 
 
+static int backlight_power_set(struct pm860x_chip *chip, int port,
+		int on)
+{
+	int ret = -EINVAL;
+
+	switch (port) {
+	case PM8606_BACKLIGHT1:
+		ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) :
+			pm8606_osc_disable(chip, WLED1_DUTY);
+		break;
+	case PM8606_BACKLIGHT2:
+		ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) :
+			pm8606_osc_disable(chip, WLED2_DUTY);
+		break;
+	case PM8606_BACKLIGHT3:
+		ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) :
+			pm8606_osc_disable(chip, WLED3_DUTY);
+		break;
+	}
+	return ret;
+}
+
 static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
 static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
 {
 {
 	struct pm860x_backlight_data *data = bl_get_data(bl);
 	struct pm860x_backlight_data *data = bl_get_data(bl);
@@ -79,6 +101,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
 	else
 	else
 		value = brightness;
 		value = brightness;
 
 
+	if (brightness)
+		backlight_power_set(chip, data->port, 1);
+
 	ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
 	ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
@@ -115,6 +140,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
+	if (brightness == 0)
+		backlight_power_set(chip, data->port, 0);
+
 	dev_dbg(chip->dev, "set brightness %d\n", value);
 	dev_dbg(chip->dev, "set brightness %d\n", value);
 	data->current_brightness = value;
 	data->current_brightness = value;
 	return 0;
 	return 0;
@@ -170,7 +198,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 	struct backlight_device *bl;
 	struct backlight_device *bl;
 	struct resource *res;
 	struct resource *res;
 	struct backlight_properties props;
 	struct backlight_properties props;
-	unsigned char value;
 	char name[MFD_NAME_SIZE];
 	char name[MFD_NAME_SIZE];
 	int ret;
 	int ret;
 
 
@@ -217,26 +244,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 
 
 	platform_set_drvdata(pdev, bl);
 	platform_set_drvdata(pdev, bl);
 
 
-	/* Enable reference VSYS */
-	ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
-	if (ret < 0)
-		goto out;
-	if ((ret & PM8606_VSYS_EN) == 0) {
-		value = ret | PM8606_VSYS_EN;
-		ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
-		if (ret < 0)
-			goto out;
-	}
-	/* Enable reference OSC */
-	ret = pm860x_reg_read(data->i2c, PM8606_MISC);
-	if (ret < 0)
-		goto out;
-	if ((ret & PM8606_MISC_OSC_EN) == 0) {
-		value = ret | PM8606_MISC_OSC_EN;
-		ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
-		if (ret < 0)
-			goto out;
-	}
 	/* read current backlight */
 	/* read current backlight */
 	ret = pm860x_backlight_get_brightness(bl);
 	ret = pm860x_backlight_get_brightness(bl);
 	if (ret < 0)
 	if (ret < 0)

+ 1 - 1
include/linux/i2c/twl.h

@@ -761,7 +761,7 @@ struct twl_regulator_driver_data {
 
 
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
-int twl4030_sih_setup(int module);
+int twl4030_sih_setup(struct device *dev, int module, int irq_base);
 
 
 /* Offsets to Power Registers */
 /* Offsets to Power Registers */
 #define TWL4030_VDAC_DEV_GRP		0x3B
 #define TWL4030_VDAC_DEV_GRP		0x3B

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

@@ -263,6 +263,22 @@ enum {
 #define PM8607_PD_PREBIAS_MASK		(0x1F << 0)
 #define PM8607_PD_PREBIAS_MASK		(0x1F << 0)
 #define PM8607_PD_PRECHG_MASK		(7 << 5)
 #define PM8607_PD_PRECHG_MASK		(7 << 5)
 
 
+#define PM8606_REF_GP_OSC_OFF         0
+#define PM8606_REF_GP_OSC_ON          1
+#define PM8606_REF_GP_OSC_UNKNOWN     2
+
+/* Clients of reference group and 8MHz oscillator in 88PM8606 */
+enum pm8606_ref_gp_and_osc_clients {
+	REF_GP_NO_CLIENTS       = 0,
+	WLED1_DUTY              = (1<<0), /*PF 0x02.7:0*/
+	WLED2_DUTY              = (1<<1), /*PF 0x04.7:0*/
+	WLED3_DUTY              = (1<<2), /*PF 0x06.7:0*/
+	RGB1_ENABLE             = (1<<3), /*PF 0x07.1*/
+	RGB2_ENABLE             = (1<<4), /*PF 0x07.2*/
+	LDO_VBR_EN              = (1<<5), /*PF 0x12.0*/
+	REF_GP_MAX_CLIENT       = 0xFFFF
+};
+
 /* Interrupt Number in 88PM8607 */
 /* Interrupt Number in 88PM8607 */
 enum {
 enum {
 	PM8607_IRQ_ONKEY,
 	PM8607_IRQ_ONKEY,
@@ -298,6 +314,7 @@ enum {
 struct pm860x_chip {
 struct pm860x_chip {
 	struct device		*dev;
 	struct device		*dev;
 	struct mutex		irq_lock;
 	struct mutex		irq_lock;
+	struct mutex		osc_lock;
 	struct i2c_client	*client;
 	struct i2c_client	*client;
 	struct i2c_client	*companion;	/* companion chip client */
 	struct i2c_client	*companion;	/* companion chip client */
 	struct regmap           *regmap;
 	struct regmap           *regmap;
@@ -305,12 +322,15 @@ struct pm860x_chip {
 
 
 	int			buck3_double;	/* DVC ramp slope double */
 	int			buck3_double;	/* DVC ramp slope double */
 	unsigned short		companion_addr;
 	unsigned short		companion_addr;
+	unsigned short		osc_vote;
 	int			id;
 	int			id;
 	int			irq_mode;
 	int			irq_mode;
 	int			irq_base;
 	int			irq_base;
 	int			core_irq;
 	int			core_irq;
 	unsigned char		chip_version;
 	unsigned char		chip_version;
+	unsigned char		osc_status;
 
 
+	unsigned int            wakeup_flag;
 };
 };
 
 
 enum {
 enum {
@@ -369,6 +389,9 @@ struct pm860x_platform_data {
 	int		num_regulators;
 	int		num_regulators;
 };
 };
 
 
+extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short);
+extern int pm8606_osc_disable(struct pm860x_chip *, unsigned short);
+
 extern int pm860x_reg_read(struct i2c_client *, int);
 extern int pm860x_reg_read(struct i2c_client *, int);
 extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
 extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
 extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
 extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);

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

@@ -34,13 +34,6 @@ struct device;
 #define AB5500_1_1	0x21
 #define AB5500_1_1	0x21
 #define AB5500_2_0	0x24
 #define AB5500_2_0	0x24
 
 
-/* AB8500 CIDs*/
-#define AB8500_CUT1P0	0x10
-#define AB8500_CUT1P1	0x11
-#define AB8500_CUT2P0	0x20
-#define AB8500_CUT3P0	0x30
-#define AB8500_CUT3P3	0x33
-
 /*
 /*
  * 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

+ 3 - 1
include/linux/mfd/abx500/ab8500-gpio.h

@@ -10,12 +10,14 @@
 
 
 /*
 /*
  * Platform data to register a block: only the initial gpio/irq number.
  * Platform data to register a block: only the initial gpio/irq number.
+ * Array sizes are large enough to contain all AB8500 and AB9540 GPIO
+ * registers.
  */
  */
 
 
 struct ab8500_gpio_platform_data {
 struct ab8500_gpio_platform_data {
 	int gpio_base;
 	int gpio_base;
 	u32 irq_base;
 	u32 irq_base;
-	u8  config_reg[7];
+	u8  config_reg[8];
 };
 };
 
 
 #endif /* _AB8500_GPIO_H */
 #endif /* _AB8500_GPIO_H */

+ 43 - 0
include/linux/mfd/abx500/ab8500-sysctrl.h

@@ -71,6 +71,13 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
 #define AB8500_SWATCTRL			0x230
 #define AB8500_SWATCTRL			0x230
 #define AB8500_HIQCLKCTRL		0x232
 #define AB8500_HIQCLKCTRL		0x232
 #define AB8500_VSIMSYSCLKCTRL		0x233
 #define AB8500_VSIMSYSCLKCTRL		0x233
+#define AB9540_SYSCLK12BUFCTRL		0x234
+#define AB9540_SYSCLK12CONFCTRL		0x235
+#define AB9540_SYSCLK12BUFCTRL2		0x236
+#define AB9540_SYSCLK12BUF1VALID	0x237
+#define AB9540_SYSCLK12BUF2VALID	0x238
+#define AB9540_SYSCLK12BUF3VALID	0x239
+#define AB9540_SYSCLK12BUF4VALID	0x23A
 
 
 /* Bits */
 /* Bits */
 #define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
 #define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
@@ -251,4 +258,40 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
 
 
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1ENA BIT(0)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2ENA BIT(1)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3ENA BIT(2)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4ENA BIT(3)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFENA_MASK 0x0F
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1STRE BIT(4)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2STRE BIT(5)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3STRE BIT(6)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4STRE BIT(7)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFSTRE_MASK 0xF0
+
+#define AB9540_SYSCLK12CONFCTRL_PLL26TO38ENA BIT(0)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12USBMUXSEL BIT(1)
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_MASK 0x0C
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_SHIFT 2
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12BUFMUX BIT(4)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12PLLMUX BIT(5)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK2MUXVALID BIT(6)
+
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF1PDENA BIT(0)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF2PDENA BIT(1)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF3PDENA BIT(2)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF4PDENA BIT(3)
+
+#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_SHIFT 0
+
 #endif /* __AB8500_SYSCTRL_H */
 #endif /* __AB8500_SYSCTRL_H */

+ 166 - 42
include/linux/mfd/abx500/ab8500.h

@@ -11,6 +11,29 @@
 
 
 struct device;
 struct device;
 
 
+/*
+ * AB IC versions
+ *
+ * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
+ * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
+ * print of version string.
+ */
+enum ab8500_version {
+	AB8500_VERSION_AB8500 = 0x0,
+	AB8500_VERSION_AB8505 = 0x1,
+	AB8500_VERSION_AB9540 = 0x2,
+	AB8500_VERSION_AB8540 = 0x3,
+	AB8500_VERSION_UNDEFINED,
+};
+
+/* AB8500 CIDs*/
+#define AB8500_CUTEARLY	0x00
+#define AB8500_CUT1P0	0x10
+#define AB8500_CUT1P1	0x11
+#define AB8500_CUT2P0	0x20
+#define AB8500_CUT3P0	0x30
+#define AB8500_CUT3P3	0x33
+
 /*
 /*
  * AB8500 bank addresses
  * AB8500 bank addresses
  */
  */
@@ -37,30 +60,34 @@ struct device;
 
 
 /*
 /*
  * Interrupts
  * Interrupts
+ * Values used to index into array ab8500_irq_regoffset[] defined in
+ * drivers/mdf/ab8500-core.c
  */
  */
-
-#define AB8500_INT_MAIN_EXT_CH_NOT_OK	0
-#define AB8500_INT_UN_PLUG_TV_DET	1
-#define AB8500_INT_PLUG_TV_DET		2
+/* Definitions for AB8500 and AB9540 */
+/* ab8500_irq_regoffset[0] -> IT[Source|Latch|Mask]1 */
+#define AB8500_INT_MAIN_EXT_CH_NOT_OK	0 /* not 8505/9540 */
+#define AB8500_INT_UN_PLUG_TV_DET	1 /* not 8505/9540 */
+#define AB8500_INT_PLUG_TV_DET		2 /* not 8505/9540 */
 #define AB8500_INT_TEMP_WARM		3
 #define AB8500_INT_TEMP_WARM		3
 #define AB8500_INT_PON_KEY2DB_F		4
 #define AB8500_INT_PON_KEY2DB_F		4
 #define AB8500_INT_PON_KEY2DB_R		5
 #define AB8500_INT_PON_KEY2DB_R		5
 #define AB8500_INT_PON_KEY1DB_F		6
 #define AB8500_INT_PON_KEY1DB_F		6
 #define AB8500_INT_PON_KEY1DB_R		7
 #define AB8500_INT_PON_KEY1DB_R		7
+/* ab8500_irq_regoffset[1] -> IT[Source|Latch|Mask]2 */
 #define AB8500_INT_BATT_OVV		8
 #define AB8500_INT_BATT_OVV		8
-#define AB8500_INT_MAIN_CH_UNPLUG_DET	10
-#define AB8500_INT_MAIN_CH_PLUG_DET	11
-#define AB8500_INT_USB_ID_DET_F		12
-#define AB8500_INT_USB_ID_DET_R		13
+#define AB8500_INT_MAIN_CH_UNPLUG_DET	10 /* not 8505 */
+#define AB8500_INT_MAIN_CH_PLUG_DET	11 /* not 8505 */
 #define AB8500_INT_VBUS_DET_F		14
 #define AB8500_INT_VBUS_DET_F		14
 #define AB8500_INT_VBUS_DET_R		15
 #define AB8500_INT_VBUS_DET_R		15
+/* ab8500_irq_regoffset[2] -> IT[Source|Latch|Mask]3 */
 #define AB8500_INT_VBUS_CH_DROP_END	16
 #define AB8500_INT_VBUS_CH_DROP_END	16
 #define AB8500_INT_RTC_60S		17
 #define AB8500_INT_RTC_60S		17
 #define AB8500_INT_RTC_ALARM		18
 #define AB8500_INT_RTC_ALARM		18
 #define AB8500_INT_BAT_CTRL_INDB	20
 #define AB8500_INT_BAT_CTRL_INDB	20
 #define AB8500_INT_CH_WD_EXP		21
 #define AB8500_INT_CH_WD_EXP		21
 #define AB8500_INT_VBUS_OVV		22
 #define AB8500_INT_VBUS_OVV		22
-#define AB8500_INT_MAIN_CH_DROP_END	23
+#define AB8500_INT_MAIN_CH_DROP_END	23 /* not 8505/9540 */
+/* ab8500_irq_regoffset[3] -> IT[Source|Latch|Mask]4 */
 #define AB8500_INT_CCN_CONV_ACC		24
 #define AB8500_INT_CCN_CONV_ACC		24
 #define AB8500_INT_INT_AUD		25
 #define AB8500_INT_INT_AUD		25
 #define AB8500_INT_CCEOC		26
 #define AB8500_INT_CCEOC		26
@@ -69,7 +96,8 @@ struct device;
 #define AB8500_INT_LOW_BAT_R		29
 #define AB8500_INT_LOW_BAT_R		29
 #define AB8500_INT_BUP_CHG_NOT_OK	30
 #define AB8500_INT_BUP_CHG_NOT_OK	30
 #define AB8500_INT_BUP_CHG_OK		31
 #define AB8500_INT_BUP_CHG_OK		31
-#define AB8500_INT_GP_HW_ADC_CONV_END	32
+/* ab8500_irq_regoffset[4] -> IT[Source|Latch|Mask]5 */
+#define AB8500_INT_GP_HW_ADC_CONV_END	32 /* not 8505 */
 #define AB8500_INT_ACC_DETECT_1DB_F	33
 #define AB8500_INT_ACC_DETECT_1DB_F	33
 #define AB8500_INT_ACC_DETECT_1DB_R	34
 #define AB8500_INT_ACC_DETECT_1DB_R	34
 #define AB8500_INT_ACC_DETECT_22DB_F	35
 #define AB8500_INT_ACC_DETECT_22DB_F	35
@@ -77,38 +105,43 @@ struct device;
 #define AB8500_INT_ACC_DETECT_21DB_F	37
 #define AB8500_INT_ACC_DETECT_21DB_F	37
 #define AB8500_INT_ACC_DETECT_21DB_R	38
 #define AB8500_INT_ACC_DETECT_21DB_R	38
 #define AB8500_INT_GP_SW_ADC_CONV_END	39
 #define AB8500_INT_GP_SW_ADC_CONV_END	39
-#define AB8500_INT_GPIO6R		40
-#define AB8500_INT_GPIO7R		41
-#define AB8500_INT_GPIO8R		42
-#define AB8500_INT_GPIO9R		43
+/* ab8500_irq_regoffset[5] -> IT[Source|Latch|Mask]7 */
+#define AB8500_INT_GPIO6R		40 /* not 8505/9540 */
+#define AB8500_INT_GPIO7R		41 /* not 8505/9540 */
+#define AB8500_INT_GPIO8R		42 /* not 8505/9540 */
+#define AB8500_INT_GPIO9R		43 /* not 8505/9540 */
 #define AB8500_INT_GPIO10R		44
 #define AB8500_INT_GPIO10R		44
 #define AB8500_INT_GPIO11R		45
 #define AB8500_INT_GPIO11R		45
-#define AB8500_INT_GPIO12R		46
+#define AB8500_INT_GPIO12R		46 /* not 8505 */
 #define AB8500_INT_GPIO13R		47
 #define AB8500_INT_GPIO13R		47
-#define AB8500_INT_GPIO24R		48
-#define AB8500_INT_GPIO25R		49
-#define AB8500_INT_GPIO36R		50
-#define AB8500_INT_GPIO37R		51
-#define AB8500_INT_GPIO38R		52
-#define AB8500_INT_GPIO39R		53
+/* ab8500_irq_regoffset[6] -> IT[Source|Latch|Mask]8 */
+#define AB8500_INT_GPIO24R		48 /* not 8505 */
+#define AB8500_INT_GPIO25R		49 /* not 8505 */
+#define AB8500_INT_GPIO36R		50 /* not 8505/9540 */
+#define AB8500_INT_GPIO37R		51 /* not 8505/9540 */
+#define AB8500_INT_GPIO38R		52 /* not 8505/9540 */
+#define AB8500_INT_GPIO39R		53 /* not 8505/9540 */
 #define AB8500_INT_GPIO40R		54
 #define AB8500_INT_GPIO40R		54
 #define AB8500_INT_GPIO41R		55
 #define AB8500_INT_GPIO41R		55
-#define AB8500_INT_GPIO6F		56
-#define AB8500_INT_GPIO7F		57
-#define AB8500_INT_GPIO8F		58
-#define AB8500_INT_GPIO9F		59
+/* ab8500_irq_regoffset[7] -> IT[Source|Latch|Mask]9 */
+#define AB8500_INT_GPIO6F		56 /* not 8505/9540 */
+#define AB8500_INT_GPIO7F		57 /* not 8505/9540 */
+#define AB8500_INT_GPIO8F		58 /* not 8505/9540 */
+#define AB8500_INT_GPIO9F		59 /* not 8505/9540 */
 #define AB8500_INT_GPIO10F		60
 #define AB8500_INT_GPIO10F		60
 #define AB8500_INT_GPIO11F		61
 #define AB8500_INT_GPIO11F		61
-#define AB8500_INT_GPIO12F		62
+#define AB8500_INT_GPIO12F		62 /* not 8505 */
 #define AB8500_INT_GPIO13F		63
 #define AB8500_INT_GPIO13F		63
-#define AB8500_INT_GPIO24F		64
-#define AB8500_INT_GPIO25F		65
-#define AB8500_INT_GPIO36F		66
-#define AB8500_INT_GPIO37F		67
-#define AB8500_INT_GPIO38F		68
-#define AB8500_INT_GPIO39F		69
+/* ab8500_irq_regoffset[8] -> IT[Source|Latch|Mask]10 */
+#define AB8500_INT_GPIO24F		64 /* not 8505 */
+#define AB8500_INT_GPIO25F		65 /* not 8505 */
+#define AB8500_INT_GPIO36F		66 /* not 8505/9540 */
+#define AB8500_INT_GPIO37F		67 /* not 8505/9540 */
+#define AB8500_INT_GPIO38F		68 /* not 8505/9540 */
+#define AB8500_INT_GPIO39F		69 /* not 8505/9540 */
 #define AB8500_INT_GPIO40F		70
 #define AB8500_INT_GPIO40F		70
 #define AB8500_INT_GPIO41F		71
 #define AB8500_INT_GPIO41F		71
+/* ab8500_irq_regoffset[9] -> IT[Source|Latch|Mask]12 */
 #define AB8500_INT_ADP_SOURCE_ERROR	72
 #define AB8500_INT_ADP_SOURCE_ERROR	72
 #define AB8500_INT_ADP_SINK_ERROR	73
 #define AB8500_INT_ADP_SINK_ERROR	73
 #define AB8500_INT_ADP_PROBE_PLUG	74
 #define AB8500_INT_ADP_PROBE_PLUG	74
@@ -116,30 +149,67 @@ struct device;
 #define AB8500_INT_ADP_SENSE_OFF	76
 #define AB8500_INT_ADP_SENSE_OFF	76
 #define AB8500_INT_USB_PHY_POWER_ERR	78
 #define AB8500_INT_USB_PHY_POWER_ERR	78
 #define AB8500_INT_USB_LINK_STATUS	79
 #define AB8500_INT_USB_LINK_STATUS	79
+/* ab8500_irq_regoffset[10] -> IT[Source|Latch|Mask]19 */
 #define AB8500_INT_BTEMP_LOW		80
 #define AB8500_INT_BTEMP_LOW		80
 #define AB8500_INT_BTEMP_LOW_MEDIUM	81
 #define AB8500_INT_BTEMP_LOW_MEDIUM	81
 #define AB8500_INT_BTEMP_MEDIUM_HIGH	82
 #define AB8500_INT_BTEMP_MEDIUM_HIGH	82
 #define AB8500_INT_BTEMP_HIGH		83
 #define AB8500_INT_BTEMP_HIGH		83
-#define AB8500_INT_USB_CHARGER_NOT_OK	89
+/* ab8500_irq_regoffset[11] -> IT[Source|Latch|Mask]20 */
+#define AB8500_INT_SRP_DETECT		88
+#define AB8500_INT_USB_CHARGER_NOT_OKR	89
 #define AB8500_INT_ID_WAKEUP_R		90
 #define AB8500_INT_ID_WAKEUP_R		90
 #define AB8500_INT_ID_DET_R1R		92
 #define AB8500_INT_ID_DET_R1R		92
 #define AB8500_INT_ID_DET_R2R		93
 #define AB8500_INT_ID_DET_R2R		93
 #define AB8500_INT_ID_DET_R3R		94
 #define AB8500_INT_ID_DET_R3R		94
 #define AB8500_INT_ID_DET_R4R		95
 #define AB8500_INT_ID_DET_R4R		95
+/* ab8500_irq_regoffset[12] -> IT[Source|Latch|Mask]21 */
 #define AB8500_INT_ID_WAKEUP_F		96
 #define AB8500_INT_ID_WAKEUP_F		96
 #define AB8500_INT_ID_DET_R1F		98
 #define AB8500_INT_ID_DET_R1F		98
 #define AB8500_INT_ID_DET_R2F		99
 #define AB8500_INT_ID_DET_R2F		99
 #define AB8500_INT_ID_DET_R3F		100
 #define AB8500_INT_ID_DET_R3F		100
 #define AB8500_INT_ID_DET_R4F		101
 #define AB8500_INT_ID_DET_R4F		101
-#define AB8500_INT_USB_CHG_DET_DONE	102
+#define AB8500_INT_CHAUTORESTARTAFTSEC  102
+#define AB8500_INT_CHSTOPBYSEC		103
+/* ab8500_irq_regoffset[13] -> IT[Source|Latch|Mask]22 */
 #define AB8500_INT_USB_CH_TH_PROT_F	104
 #define AB8500_INT_USB_CH_TH_PROT_F	104
 #define AB8500_INT_USB_CH_TH_PROT_R    105
 #define AB8500_INT_USB_CH_TH_PROT_R    105
-#define AB8500_INT_MAIN_CH_TH_PROT_F   106
-#define AB8500_INT_MAIN_CH_TH_PROT_R	107
-#define AB8500_INT_USB_CHARGER_NOT_OKF	111
+#define AB8500_INT_MAIN_CH_TH_PROT_F	106 /* not 8505/9540 */
+#define AB8500_INT_MAIN_CH_TH_PROT_R	107 /* not 8505/9540 */
+#define AB8500_INT_CHCURLIMNOHSCHIRP	109
+#define AB8500_INT_CHCURLIMHSCHIRP	110
+#define AB8500_INT_XTAL32K_KO		111
+
+/* Definitions for AB9540 */
+/* ab8500_irq_regoffset[14] -> IT[Source|Latch|Mask]13 */
+#define AB9540_INT_GPIO50R		113
+#define AB9540_INT_GPIO51R		114 /* not 8505 */
+#define AB9540_INT_GPIO52R		115
+#define AB9540_INT_GPIO53R		116
+#define AB9540_INT_GPIO54R		117 /* not 8505 */
+#define AB9540_INT_IEXT_CH_RF_BFN_R	118
+#define AB9540_INT_IEXT_CH_RF_BFN_F	119
+/* ab8500_irq_regoffset[15] -> IT[Source|Latch|Mask]14 */
+#define AB9540_INT_GPIO50F		121
+#define AB9540_INT_GPIO51F		122 /* not 8505 */
+#define AB9540_INT_GPIO52F		123
+#define AB9540_INT_GPIO53F		124
+#define AB9540_INT_GPIO54F		125 /* not 8505 */
 
 
+/*
+ * AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
+ * entire platform. This is a "compile time" constant so this must be set to
+ * the largest possible value that may be encountered with different AB SOCs.
+ * Of the currently supported AB devices, AB8500 and AB9540, it is the AB9540
+ * which is larger.
+ */
 #define AB8500_NR_IRQS			112
 #define AB8500_NR_IRQS			112
+#define AB8505_NR_IRQS			128
+#define AB9540_NR_IRQS			128
+/* This is set to the roof of any AB8500 chip variant IRQ counts */
+#define AB8500_MAX_NR_IRQS		AB9540_NR_IRQS
+
 #define AB8500_NUM_IRQ_REGS		14
 #define AB8500_NUM_IRQ_REGS		14
+#define AB9540_NUM_IRQ_REGS		17
 
 
 /**
 /**
  * struct ab8500 - ab8500 internal structure
  * struct ab8500 - ab8500 internal structure
@@ -147,13 +217,18 @@ struct device;
  * @lock: read/write operations lock
  * @lock: read/write operations lock
  * @irq_lock: genirq bus lock
  * @irq_lock: genirq bus lock
  * @irq: irq line
  * @irq: irq line
+ * @version: chip version id (e.g. ab8500 or ab9540)
  * @chip_id: chip revision id
  * @chip_id: chip revision id
  * @write: register write
  * @write: register write
+ * @write_masked: masked register write
  * @read: register read
  * @read: register read
  * @rx_buf: rx buf for SPI
  * @rx_buf: rx buf for SPI
  * @tx_buf: tx buf for SPI
  * @tx_buf: tx buf for SPI
  * @mask: cache of IRQ regs for bus lock
  * @mask: cache of IRQ regs for bus lock
  * @oldmask: cache of previous IRQ regs for bus lock
  * @oldmask: cache of previous IRQ regs for bus lock
+ * @mask_size: Actual number of valid entries in mask[], oldmask[] and
+ * irq_reg_offset
+ * @irq_reg_offset: Array of offsets into IRQ registers
  */
  */
 struct ab8500 {
 struct ab8500 {
 	struct device	*dev;
 	struct device	*dev;
@@ -162,16 +237,20 @@ struct ab8500 {
 
 
 	int		irq_base;
 	int		irq_base;
 	int		irq;
 	int		irq;
+	enum ab8500_version version;
 	u8		chip_id;
 	u8		chip_id;
 
 
-	int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
-	int (*read) (struct ab8500 *a8500, u16 addr);
+	int (*write)(struct ab8500 *ab8500, u16 addr, u8 data);
+	int (*write_masked)(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data);
+	int (*read)(struct ab8500 *ab8500, u16 addr);
 
 
 	unsigned long	tx_buf[4];
 	unsigned long	tx_buf[4];
 	unsigned long	rx_buf[4];
 	unsigned long	rx_buf[4];
 
 
-	u8 mask[AB8500_NUM_IRQ_REGS];
-	u8 oldmask[AB8500_NUM_IRQ_REGS];
+	u8 *mask;
+	u8 *oldmask;
+	int mask_size;
+	const int *irq_reg_offset;
 };
 };
 
 
 struct regulator_reg_init;
 struct regulator_reg_init;
@@ -197,7 +276,52 @@ struct ab8500_platform_data {
 	struct ab8500_gpio_platform_data *gpio;
 	struct ab8500_gpio_platform_data *gpio;
 };
 };
 
 
-extern int __devinit ab8500_init(struct ab8500 *ab8500);
+extern int __devinit ab8500_init(struct ab8500 *ab8500,
+				 enum ab8500_version version);
 extern int __devexit ab8500_exit(struct ab8500 *ab8500);
 extern int __devexit ab8500_exit(struct ab8500 *ab8500);
 
 
+static inline int is_ab8500(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8500;
+}
+
+static inline int is_ab8505(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8505;
+}
+
+static inline int is_ab9540(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB9540;
+}
+
+static inline int is_ab8540(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8540;
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
 #endif /* MFD_AB8500_H */
 #endif /* MFD_AB8500_H */

+ 40 - 0
include/linux/mfd/anatop.h

@@ -0,0 +1,40 @@
+/*
+ * anatop.h - Anatop MFD driver
+ *
+ *  Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *  Copyright (C) 2012 Linaro
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MFD_ANATOP_H
+#define __LINUX_MFD_ANATOP_H
+
+#include <linux/spinlock.h>
+
+/**
+ * anatop - MFD data
+ * @ioreg: ioremap register
+ * @reglock: spinlock for register read/write
+ */
+struct anatop {
+	void *ioreg;
+	spinlock_t reglock;
+};
+
+extern u32 anatop_get_bits(struct anatop *, u32, int, int);
+extern void anatop_set_bits(struct anatop *, u32, int, int, u32);
+
+#endif /*  __LINUX_MFD_ANATOP_H */

+ 0 - 2
include/linux/mfd/da9052/da9052.h

@@ -76,8 +76,6 @@ enum da9052_chip_id {
 struct da9052_pdata;
 struct da9052_pdata;
 
 
 struct da9052 {
 struct da9052 {
-	struct mutex io_lock;
-
 	struct device *dev;
 	struct device *dev;
 	struct regmap *regmap;
 	struct regmap *regmap;
 
 

+ 102 - 81
include/linux/mfd/db8500-prcmu.h

@@ -11,6 +11,24 @@
 #define __MFD_DB8500_PRCMU_H
 #define __MFD_DB8500_PRCMU_H
 
 
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
+#include <linux/bitops.h>
+
+/*
+ * Registers
+ */
+#define DB8500_PRCM_GPIOCR 0x138
+#define DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0	BIT(0)
+#define DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD	BIT(9)
+#define DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1	BIT(11)
+#define DB8500_PRCM_GPIOCR_SPI2_SELECT		BIT(23)
+
+#define DB8500_PRCM_LINE_VALUE 0x170
+#define DB8500_PRCM_LINE_VALUE_HSI_CAWAKE0	BIT(3)
+
+#define DB8500_PRCM_DSI_SW_RESET 0x324
+#define DB8500_PRCM_DSI_SW_RESET_DSI0_SW_RESETN BIT(0)
+#define DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN BIT(1)
+#define DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN BIT(2)
 
 
 /* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
 /* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
 
 
@@ -421,40 +439,22 @@ enum auto_enable {
 /* End of file previously known as prcmu-fw-defs_v1.h */
 /* End of file previously known as prcmu-fw-defs_v1.h */
 
 
 /**
 /**
- * enum hw_acc_dev - enum for hw accelerators
- * @HW_ACC_SVAMMDSP: for SVAMMDSP
- * @HW_ACC_SVAPIPE:  for SVAPIPE
- * @HW_ACC_SIAMMDSP: for SIAMMDSP
- * @HW_ACC_SIAPIPE: for SIAPIPE
- * @HW_ACC_SGA: for SGA
- * @HW_ACC_B2R2: for B2R2
- * @HW_ACC_MCDE: for MCDE
- * @HW_ACC_ESRAM1: for ESRAM1
- * @HW_ACC_ESRAM2: for ESRAM2
- * @HW_ACC_ESRAM3: for ESRAM3
- * @HW_ACC_ESRAM4: for ESRAM4
- * @NUM_HW_ACC: number of hardware accelerators
- *
- * Different hw accelerators which can be turned ON/
- * OFF or put into retention (MMDSPs and ESRAMs).
- * Used with EPOD API.
+ * enum prcmu_power_status - results from set_power_state
+ * @PRCMU_SLEEP_OK: Sleep went ok
+ * @PRCMU_DEEP_SLEEP_OK: DeepSleep went ok
+ * @PRCMU_IDLE_OK: Idle went ok
+ * @PRCMU_DEEPIDLE_OK: DeepIdle went ok
+ * @PRCMU_PRCMU2ARMPENDINGIT_ER: Pending interrupt detected
+ * @PRCMU_ARMPENDINGIT_ER: Pending interrupt detected
  *
  *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator API.
  */
  */
-enum hw_acc_dev {
-	HW_ACC_SVAMMDSP,
-	HW_ACC_SVAPIPE,
-	HW_ACC_SIAMMDSP,
-	HW_ACC_SIAPIPE,
-	HW_ACC_SGA,
-	HW_ACC_B2R2,
-	HW_ACC_MCDE,
-	HW_ACC_ESRAM1,
-	HW_ACC_ESRAM2,
-	HW_ACC_ESRAM3,
-	HW_ACC_ESRAM4,
-	NUM_HW_ACC
+enum prcmu_power_status {
+	PRCMU_SLEEP_OK			= 0xf3,
+	PRCMU_DEEP_SLEEP_OK		= 0xf6,
+	PRCMU_IDLE_OK			= 0xf0,
+	PRCMU_DEEPIDLE_OK		= 0xe3,
+	PRCMU_PRCMU2ARMPENDINGIT_ER	= 0x91,
+	PRCMU_ARMPENDINGIT_ER		= 0x93,
 };
 };
 
 
 /*
 /*
@@ -493,6 +493,20 @@ struct prcmu_auto_pm_config {
 	u8 sva_policy;
 	u8 sva_policy;
 };
 };
 
 
+#define PRCMU_FW_PROJECT_U8500		2
+#define PRCMU_FW_PROJECT_U9500		4
+#define PRCMU_FW_PROJECT_U8500_C2	7
+#define PRCMU_FW_PROJECT_U9500_C2	11
+#define PRCMU_FW_PROJECT_U8520		13
+#define PRCMU_FW_PROJECT_U8420		14
+
+struct prcmu_fw_version {
+	u8 project;
+	u8 api_version;
+	u8 func_version;
+	u8 errata;
+};
+
 #ifdef CONFIG_MFD_DB8500_PRCMU
 #ifdef CONFIG_MFD_DB8500_PRCMU
 
 
 void db8500_prcmu_early_init(void);
 void db8500_prcmu_early_init(void);
@@ -500,42 +514,41 @@ int prcmu_set_rc_a2p(enum romcode_write);
 enum romcode_read prcmu_get_rc_p2a(void);
 enum romcode_read prcmu_get_rc_p2a(void);
 enum ap_pwrst prcmu_get_xp70_current_state(void);
 enum ap_pwrst prcmu_get_xp70_current_state(void);
 bool prcmu_has_arm_maxopp(void);
 bool prcmu_has_arm_maxopp(void);
-bool prcmu_is_u8400(void);
-int prcmu_set_ape_opp(u8 opp);
-int prcmu_get_ape_opp(void);
+struct prcmu_fw_version *prcmu_get_fw_version(void);
 int prcmu_request_ape_opp_100_voltage(bool enable);
 int prcmu_request_ape_opp_100_voltage(bool enable);
 int prcmu_release_usb_wakeup_state(void);
 int prcmu_release_usb_wakeup_state(void);
-int prcmu_set_ddr_opp(u8 opp);
-int prcmu_get_ddr_opp(void);
-/* NOTE! Use regulator framework instead */
-int prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
 void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
 void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
 	struct prcmu_auto_pm_config *idle);
 	struct prcmu_auto_pm_config *idle);
 bool prcmu_is_auto_pm_enabled(void);
 bool prcmu_is_auto_pm_enabled(void);
 
 
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 int prcmu_set_clock_divider(u8 clock, u8 divider);
 int prcmu_set_clock_divider(u8 clock, u8 divider);
-int prcmu_config_hotdog(u8 threshold);
-int prcmu_config_hotmon(u8 low, u8 high);
-int prcmu_start_temp_sense(u16 cycles32k);
-int prcmu_stop_temp_sense(void);
+int db8500_prcmu_config_hotdog(u8 threshold);
+int db8500_prcmu_config_hotmon(u8 low, u8 high);
+int db8500_prcmu_start_temp_sense(u16 cycles32k);
+int db8500_prcmu_stop_temp_sense(void);
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
 
 
 void prcmu_ac_wake_req(void);
 void prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
 void prcmu_ac_sleep_req(void);
-void prcmu_modem_reset(void);
-void prcmu_enable_spi2(void);
-void prcmu_disable_spi2(void);
+void db8500_prcmu_modem_reset(void);
 
 
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
-int prcmu_enable_a9wdog(u8 id);
-int prcmu_disable_a9wdog(u8 id);
-int prcmu_kick_a9wdog(u8 id);
-int prcmu_load_a9wdog(u8 id, u32 val);
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
+int db8500_prcmu_enable_a9wdog(u8 id);
+int db8500_prcmu_disable_a9wdog(u8 id);
+int db8500_prcmu_kick_a9wdog(u8 id);
+int db8500_prcmu_load_a9wdog(u8 id, u32 val);
 
 
 void db8500_prcmu_system_reset(u16 reset_code);
 void db8500_prcmu_system_reset(u16 reset_code);
 int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
 int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
+u8 db8500_prcmu_get_power_state_result(void);
+int db8500_prcmu_gic_decouple(void);
+int db8500_prcmu_gic_recouple(void);
+int db8500_prcmu_copy_gic_settings(void);
+bool db8500_prcmu_gic_pending_irq(void);
+bool db8500_prcmu_pending_irq(void);
+bool db8500_prcmu_is_cpu_in_wfi(int cpu);
 void db8500_prcmu_enable_wakeups(u32 wakeups);
 void db8500_prcmu_enable_wakeups(u32 wakeups);
 int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
 int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
 int db8500_prcmu_request_clock(u8 clock, bool enable);
 int db8500_prcmu_request_clock(u8 clock, bool enable);
@@ -549,6 +562,14 @@ u16 db8500_prcmu_get_reset_code(void);
 bool db8500_prcmu_is_ac_wake_requested(void);
 bool db8500_prcmu_is_ac_wake_requested(void);
 int db8500_prcmu_set_arm_opp(u8 opp);
 int db8500_prcmu_set_arm_opp(u8 opp);
 int db8500_prcmu_get_arm_opp(void);
 int db8500_prcmu_get_arm_opp(void);
+int db8500_prcmu_set_ape_opp(u8 opp);
+int db8500_prcmu_get_ape_opp(void);
+int db8500_prcmu_set_ddr_opp(u8 opp);
+int db8500_prcmu_get_ddr_opp(void);
+
+u32 db8500_prcmu_read(unsigned int reg);
+void db8500_prcmu_write(unsigned int reg, u32 value);
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value);
 
 
 #else /* !CONFIG_MFD_DB8500_PRCMU */
 #else /* !CONFIG_MFD_DB8500_PRCMU */
 
 
@@ -574,17 +595,17 @@ static inline bool prcmu_has_arm_maxopp(void)
 	return false;
 	return false;
 }
 }
 
 
-static inline bool prcmu_is_u8400(void)
+static inline struct prcmu_fw_version *prcmu_get_fw_version(void)
 {
 {
-	return false;
+	return NULL;
 }
 }
 
 
-static inline int prcmu_set_ape_opp(u8 opp)
+static inline int db8500_prcmu_set_ape_opp(u8 opp)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_get_ape_opp(void)
+static inline int db8500_prcmu_get_ape_opp(void)
 {
 {
 	return APE_100_OPP;
 	return APE_100_OPP;
 }
 }
@@ -599,21 +620,16 @@ static inline int prcmu_release_usb_wakeup_state(void)
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_set_ddr_opp(u8 opp)
+static inline int db8500_prcmu_set_ddr_opp(u8 opp)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_get_ddr_opp(void)
+static inline int db8500_prcmu_get_ddr_opp(void)
 {
 {
 	return DDR_100_OPP;
 	return DDR_100_OPP;
 }
 }
 
 
-static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
-{
-	return 0;
-}
-
 static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
 static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
 	struct prcmu_auto_pm_config *idle)
 	struct prcmu_auto_pm_config *idle)
 {
 {
@@ -634,22 +650,22 @@ static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_config_hotdog(u8 threshold)
+static inline int db8500_prcmu_config_hotdog(u8 threshold)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_config_hotmon(u8 low, u8 high)
+static inline int db8500_prcmu_config_hotmon(u8 low, u8 high)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_start_temp_sense(u16 cycles32k)
+static inline int db8500_prcmu_start_temp_sense(u16 cycles32k)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_stop_temp_sense(void)
+static inline int db8500_prcmu_stop_temp_sense(void)
 {
 {
 	return 0;
 	return 0;
 }
 }
@@ -668,22 +684,17 @@ static inline void prcmu_ac_wake_req(void) {}
 
 
 static inline void prcmu_ac_sleep_req(void) {}
 static inline void prcmu_ac_sleep_req(void) {}
 
 
-static inline void prcmu_modem_reset(void) {}
+static inline void db8500_prcmu_modem_reset(void) {}
 
 
-static inline int prcmu_enable_spi2(void)
-{
-	return 0;
-}
+static inline void db8500_prcmu_system_reset(u16 reset_code) {}
 
 
-static inline int prcmu_disable_spi2(void)
+static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
+	bool keep_ap_pll)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline void db8500_prcmu_system_reset(u16 reset_code) {}
-
-static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
-	bool keep_ap_pll)
+static inline u8 db8500_prcmu_get_power_state_result(void)
 {
 {
 	return 0;
 	return 0;
 }
 }
@@ -729,27 +740,27 @@ static inline u16 db8500_prcmu_get_reset_code(void)
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+static inline int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_enable_a9wdog(u8 id)
+static inline int db8500_prcmu_enable_a9wdog(u8 id)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_disable_a9wdog(u8 id)
+static inline int db8500_prcmu_disable_a9wdog(u8 id)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_kick_a9wdog(u8 id)
+static inline int db8500_prcmu_kick_a9wdog(u8 id)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int prcmu_load_a9wdog(u8 id, u32 val)
+static inline int db8500_prcmu_load_a9wdog(u8 id, u32 val)
 {
 {
 	return 0;
 	return 0;
 }
 }
@@ -769,6 +780,16 @@ static inline int db8500_prcmu_get_arm_opp(void)
 	return 0;
 	return 0;
 }
 }
 
 
+static inline u32 db8500_prcmu_read(unsigned int reg)
+{
+	return 0;
+}
+
+static inline void db8500_prcmu_write(unsigned int reg, u32 value) {}
+
+static inline void db8500_prcmu_write_masked(unsigned int reg, u32 mask,
+	u32 value) {}
+
 #endif /* !CONFIG_MFD_DB8500_PRCMU */
 #endif /* !CONFIG_MFD_DB8500_PRCMU */
 
 
 #endif /* __MFD_DB8500_PRCMU_H */
 #endif /* __MFD_DB8500_PRCMU_H */

+ 390 - 24
include/linux/mfd/dbx500-prcmu.h

@@ -10,7 +10,7 @@
 
 
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/notifier.h>
-#include <asm/mach-types.h>
+#include <linux/err.h>
 
 
 /* PRCMU Wakeup defines */
 /* PRCMU Wakeup defines */
 enum prcmu_wakeup_index {
 enum prcmu_wakeup_index {
@@ -80,6 +80,29 @@ enum prcmu_wakeup_index {
 #define EPOD_STATE_ON_CLK_OFF	0x03
 #define EPOD_STATE_ON_CLK_OFF	0x03
 #define EPOD_STATE_ON		0x04
 #define EPOD_STATE_ON		0x04
 
 
+/* DB5500 CLKOUT IDs */
+enum {
+	DB5500_CLKOUT0 = 0,
+	DB5500_CLKOUT1,
+};
+
+/* DB5500 CLKOUTx sources */
+enum {
+	DB5500_CLKOUT_REF_CLK_SEL0,
+	DB5500_CLKOUT_RTC_CLK0_SEL0,
+	DB5500_CLKOUT_ULP_CLK_SEL0,
+	DB5500_CLKOUT_STATIC0,
+	DB5500_CLKOUT_REFCLK,
+	DB5500_CLKOUT_ULPCLK,
+	DB5500_CLKOUT_ARMCLK,
+	DB5500_CLKOUT_SYSACC0CLK,
+	DB5500_CLKOUT_SOC0PLLCLK,
+	DB5500_CLKOUT_SOC1PLLCLK,
+	DB5500_CLKOUT_DDRPLLCLK,
+	DB5500_CLKOUT_TVCLK,
+	DB5500_CLKOUT_IRDACLK,
+};
+
 /*
 /*
  * CLKOUT sources
  * CLKOUT sources
  */
  */
@@ -111,6 +134,7 @@ enum prcmu_clock {
 	PRCMU_MSP1CLK,
 	PRCMU_MSP1CLK,
 	PRCMU_I2CCLK,
 	PRCMU_I2CCLK,
 	PRCMU_SDMMCCLK,
 	PRCMU_SDMMCCLK,
+	PRCMU_SPARE1CLK,
 	PRCMU_SLIMCLK,
 	PRCMU_SLIMCLK,
 	PRCMU_PER1CLK,
 	PRCMU_PER1CLK,
 	PRCMU_PER2CLK,
 	PRCMU_PER2CLK,
@@ -139,12 +163,20 @@ enum prcmu_clock {
 	PRCMU_IRRCCLK,
 	PRCMU_IRRCCLK,
 	PRCMU_SIACLK,
 	PRCMU_SIACLK,
 	PRCMU_SVACLK,
 	PRCMU_SVACLK,
+	PRCMU_ACLK,
 	PRCMU_NUM_REG_CLOCKS,
 	PRCMU_NUM_REG_CLOCKS,
 	PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
 	PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
+	PRCMU_CDCLK,
 	PRCMU_TIMCLK,
 	PRCMU_TIMCLK,
 	PRCMU_PLLSOC0,
 	PRCMU_PLLSOC0,
 	PRCMU_PLLSOC1,
 	PRCMU_PLLSOC1,
 	PRCMU_PLLDDR,
 	PRCMU_PLLDDR,
+	PRCMU_PLLDSI,
+	PRCMU_DSI0CLK,
+	PRCMU_DSI1CLK,
+	PRCMU_DSI0ESCCLK,
+	PRCMU_DSI1ESCCLK,
+	PRCMU_DSI2ESCCLK,
 };
 };
 
 
 /**
 /**
@@ -153,12 +185,14 @@ enum prcmu_clock {
  * @APE_NO_CHANGE: The APE operating point is unchanged
  * @APE_NO_CHANGE: The APE operating point is unchanged
  * @APE_100_OPP: The new APE operating point is ape100opp
  * @APE_100_OPP: The new APE operating point is ape100opp
  * @APE_50_OPP: 50%
  * @APE_50_OPP: 50%
+ * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
  */
  */
 enum ape_opp {
 enum ape_opp {
 	APE_OPP_INIT = 0x00,
 	APE_OPP_INIT = 0x00,
 	APE_NO_CHANGE = 0x01,
 	APE_NO_CHANGE = 0x01,
 	APE_100_OPP = 0x02,
 	APE_100_OPP = 0x02,
-	APE_50_OPP = 0x03
+	APE_50_OPP = 0x03,
+	APE_50_PARTLY_25_OPP = 0xFF,
 };
 };
 
 
 /**
 /**
@@ -218,9 +252,11 @@ enum ddr_pwrst {
 
 
 #if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
 #if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
 
 
+#include <mach/id.h>
+
 static inline void __init prcmu_early_init(void)
 static inline void __init prcmu_early_init(void)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_early_init();
 		return db5500_prcmu_early_init();
 	else
 	else
 		return db8500_prcmu_early_init();
 		return db8500_prcmu_early_init();
@@ -229,7 +265,7 @@ static inline void __init prcmu_early_init(void)
 static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
 static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
 		bool keep_ap_pll)
 		bool keep_ap_pll)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_set_power_state(state, keep_ulp_clk,
 		return db5500_prcmu_set_power_state(state, keep_ulp_clk,
 			keep_ap_pll);
 			keep_ap_pll);
 	else
 	else
@@ -237,9 +273,65 @@ static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
 			keep_ap_pll);
 			keep_ap_pll);
 }
 }
 
 
+static inline u8 prcmu_get_power_state_result(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_get_power_state_result();
+}
+
+static inline int prcmu_gic_decouple(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_gic_decouple();
+}
+
+static inline int prcmu_gic_recouple(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_gic_recouple();
+}
+
+static inline bool prcmu_gic_pending_irq(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_gic_pending_irq();
+}
+
+static inline bool prcmu_is_cpu_in_wfi(int cpu)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_is_cpu_in_wfi(cpu);
+}
+
+static inline int prcmu_copy_gic_settings(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_copy_gic_settings();
+}
+
+static inline bool prcmu_pending_irq(void)
+{
+        if (cpu_is_u5500())
+                return -EINVAL;
+        else
+                return db8500_prcmu_pending_irq();
+}
+
 static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 		return -EINVAL;
 	else
 	else
 		return db8500_prcmu_set_epod(epod_id, epod_state);
 		return db8500_prcmu_set_epod(epod_id, epod_state);
@@ -247,7 +339,7 @@ static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 
 
 static inline void prcmu_enable_wakeups(u32 wakeups)
 static inline void prcmu_enable_wakeups(u32 wakeups)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		db5500_prcmu_enable_wakeups(wakeups);
 		db5500_prcmu_enable_wakeups(wakeups);
 	else
 	else
 		db8500_prcmu_enable_wakeups(wakeups);
 		db8500_prcmu_enable_wakeups(wakeups);
@@ -260,7 +352,7 @@ static inline void prcmu_disable_wakeups(void)
 
 
 static inline void prcmu_config_abb_event_readout(u32 abb_events)
 static inline void prcmu_config_abb_event_readout(u32 abb_events)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		db5500_prcmu_config_abb_event_readout(abb_events);
 		db5500_prcmu_config_abb_event_readout(abb_events);
 	else
 	else
 		db8500_prcmu_config_abb_event_readout(abb_events);
 		db8500_prcmu_config_abb_event_readout(abb_events);
@@ -268,7 +360,7 @@ static inline void prcmu_config_abb_event_readout(u32 abb_events)
 
 
 static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		db5500_prcmu_get_abb_event_buffer(buf);
 		db5500_prcmu_get_abb_event_buffer(buf);
 	else
 	else
 		db8500_prcmu_get_abb_event_buffer(buf);
 		db8500_prcmu_get_abb_event_buffer(buf);
@@ -276,25 +368,40 @@ static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 
 
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size);
 
 
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 
 
 static inline int prcmu_request_clock(u8 clock, bool enable)
 static inline int prcmu_request_clock(u8 clock, bool enable)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_request_clock(clock, enable);
 		return db5500_prcmu_request_clock(clock, enable);
 	else
 	else
 		return db8500_prcmu_request_clock(clock, enable);
 		return db8500_prcmu_request_clock(clock, enable);
 }
 }
 
 
-int prcmu_set_ape_opp(u8 opp);
-int prcmu_get_ape_opp(void);
-int prcmu_set_ddr_opp(u8 opp);
-int prcmu_get_ddr_opp(void);
+unsigned long prcmu_clock_rate(u8 clock);
+long prcmu_round_clock_rate(u8 clock, unsigned long rate);
+int prcmu_set_clock_rate(u8 clock, unsigned long rate);
+
+static inline int prcmu_set_ddr_opp(u8 opp)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_set_ddr_opp(opp);
+}
+static inline int prcmu_get_ddr_opp(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_get_ddr_opp();
+}
 
 
 static inline int prcmu_set_arm_opp(u8 opp)
 static inline int prcmu_set_arm_opp(u8 opp)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 		return -EINVAL;
 	else
 	else
 		return db8500_prcmu_set_arm_opp(opp);
 		return db8500_prcmu_set_arm_opp(opp);
@@ -302,15 +409,31 @@ static inline int prcmu_set_arm_opp(u8 opp)
 
 
 static inline int prcmu_get_arm_opp(void)
 static inline int prcmu_get_arm_opp(void)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 		return -EINVAL;
 	else
 	else
 		return db8500_prcmu_get_arm_opp();
 		return db8500_prcmu_get_arm_opp();
 }
 }
 
 
+static inline int prcmu_set_ape_opp(u8 opp)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_set_ape_opp(opp);
+}
+
+static inline int prcmu_get_ape_opp(void)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_get_ape_opp();
+}
+
 static inline void prcmu_system_reset(u16 reset_code)
 static inline void prcmu_system_reset(u16 reset_code)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_system_reset(reset_code);
 		return db5500_prcmu_system_reset(reset_code);
 	else
 	else
 		return db8500_prcmu_system_reset(reset_code);
 		return db8500_prcmu_system_reset(reset_code);
@@ -318,7 +441,7 @@ static inline void prcmu_system_reset(u16 reset_code)
 
 
 static inline u16 prcmu_get_reset_code(void)
 static inline u16 prcmu_get_reset_code(void)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_get_reset_code();
 		return db5500_prcmu_get_reset_code();
 	else
 	else
 		return db8500_prcmu_get_reset_code();
 		return db8500_prcmu_get_reset_code();
@@ -326,10 +449,17 @@ static inline u16 prcmu_get_reset_code(void)
 
 
 void prcmu_ac_wake_req(void);
 void prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
 void prcmu_ac_sleep_req(void);
-void prcmu_modem_reset(void);
+static inline void prcmu_modem_reset(void)
+{
+	if (cpu_is_u5500())
+		return;
+	else
+		return db8500_prcmu_modem_reset();
+}
+
 static inline bool prcmu_is_ac_wake_requested(void)
 static inline bool prcmu_is_ac_wake_requested(void)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_is_ac_wake_requested();
 		return db5500_prcmu_is_ac_wake_requested();
 	else
 	else
 		return db8500_prcmu_is_ac_wake_requested();
 		return db8500_prcmu_is_ac_wake_requested();
@@ -337,7 +467,7 @@ static inline bool prcmu_is_ac_wake_requested(void)
 
 
 static inline int prcmu_set_display_clocks(void)
 static inline int prcmu_set_display_clocks(void)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_set_display_clocks();
 		return db5500_prcmu_set_display_clocks();
 	else
 	else
 		return db8500_prcmu_set_display_clocks();
 		return db8500_prcmu_set_display_clocks();
@@ -345,7 +475,7 @@ static inline int prcmu_set_display_clocks(void)
 
 
 static inline int prcmu_disable_dsipll(void)
 static inline int prcmu_disable_dsipll(void)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_disable_dsipll();
 		return db5500_prcmu_disable_dsipll();
 	else
 	else
 		return db8500_prcmu_disable_dsipll();
 		return db8500_prcmu_disable_dsipll();
@@ -353,7 +483,7 @@ static inline int prcmu_disable_dsipll(void)
 
 
 static inline int prcmu_enable_dsipll(void)
 static inline int prcmu_enable_dsipll(void)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return db5500_prcmu_enable_dsipll();
 		return db5500_prcmu_enable_dsipll();
 	else
 	else
 		return db8500_prcmu_enable_dsipll();
 		return db8500_prcmu_enable_dsipll();
@@ -361,11 +491,107 @@ static inline int prcmu_enable_dsipll(void)
 
 
 static inline int prcmu_config_esram0_deep_sleep(u8 state)
 static inline int prcmu_config_esram0_deep_sleep(u8 state)
 {
 {
-	if (machine_is_u5500())
+	if (cpu_is_u5500())
 		return -EINVAL;
 		return -EINVAL;
 	else
 	else
 		return db8500_prcmu_config_esram0_deep_sleep(state);
 		return db8500_prcmu_config_esram0_deep_sleep(state);
 }
 }
+
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_config_hotdog(threshold);
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_config_hotmon(low, high);
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+	if (cpu_is_u5500())
+		return  -EINVAL;
+	else
+		return  db8500_prcmu_start_temp_sense(cycles32k);
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+	if (cpu_is_u5500())
+		return  -EINVAL;
+	else
+		return  db8500_prcmu_stop_temp_sense();
+}
+
+static inline u32 prcmu_read(unsigned int reg)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_read(reg);
+}
+
+static inline void prcmu_write(unsigned int reg, u32 value)
+{
+	if (cpu_is_u5500())
+		return;
+	else
+		db8500_prcmu_write(reg, value);
+}
+
+static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
+{
+	if (cpu_is_u5500())
+		return;
+	else
+		db8500_prcmu_write_masked(reg, mask, value);
+}
+
+static inline int prcmu_enable_a9wdog(u8 id)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_enable_a9wdog(id);
+}
+
+static inline int prcmu_disable_a9wdog(u8 id)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_disable_a9wdog(id);
+}
+
+static inline int prcmu_kick_a9wdog(u8 id)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_kick_a9wdog(id);
+}
+
+static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_load_a9wdog(id, timeout);
+}
+
+static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+{
+	if (cpu_is_u5500())
+		return -EINVAL;
+	else
+		return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
+}
 #else
 #else
 
 
 static inline void __init prcmu_early_init(void) {}
 static inline void __init prcmu_early_init(void) {}
@@ -395,6 +621,12 @@ static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
 	return -ENOSYS;
 	return -ENOSYS;
 }
 }
 
 
+static inline int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
+	u8 size)
+{
+	return -ENOSYS;
+}
+
 static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
 static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
 {
 {
 	return 0;
 	return 0;
@@ -405,6 +637,21 @@ static inline int prcmu_request_clock(u8 clock, bool enable)
 	return 0;
 	return 0;
 }
 }
 
 
+static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+	return 0;
+}
+
+static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
+	return 0;
+}
+
+static inline unsigned long prcmu_clock_rate(u8 clock)
+{
+	return 0;
+}
+
 static inline int prcmu_set_ape_opp(u8 opp)
 static inline int prcmu_set_ape_opp(u8 opp)
 {
 {
 	return 0;
 	return 0;
@@ -480,14 +727,133 @@ static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 	*buf = NULL;
 	*buf = NULL;
 }
 }
 
 
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+	return 0;
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+	return 0;
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+	return 0;
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+	return 0;
+}
+
+static inline u32 prcmu_read(unsigned int reg)
+{
+	return 0;
+}
+
+static inline void prcmu_write(unsigned int reg, u32 value) {}
+
+static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
+
+#endif
+
+static inline void prcmu_set(unsigned int reg, u32 bits)
+{
+	prcmu_write_masked(reg, bits, bits);
+}
+
+static inline void prcmu_clear(unsigned int reg, u32 bits)
+{
+	prcmu_write_masked(reg, bits, 0);
+}
+
+#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
+
+/**
+ * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
+ */
+static inline void prcmu_enable_spi2(void)
+{
+	if (cpu_is_u8500())
+		prcmu_set(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
+}
+
+/**
+ * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
+ */
+static inline void prcmu_disable_spi2(void)
+{
+	if (cpu_is_u8500())
+		prcmu_clear(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
+}
+
+/**
+ * prcmu_enable_stm_mod_uart - Enables pin muxing for STMMOD
+ * and UARTMOD on OtherAlternateC3.
+ */
+static inline void prcmu_enable_stm_mod_uart(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_set(DB8500_PRCM_GPIOCR,
+			(DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
+			 DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
+	}
+}
+
+/**
+ * prcmu_disable_stm_mod_uart - Disables pin muxing for STMMOD
+ * and UARTMOD on OtherAlternateC3.
+ */
+static inline void prcmu_disable_stm_mod_uart(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_clear(DB8500_PRCM_GPIOCR,
+			(DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
+			 DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
+	}
+}
+
+/**
+ * prcmu_enable_stm_ape - Enables pin muxing for STM APE on OtherAlternateC1.
+ */
+static inline void prcmu_enable_stm_ape(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_set(DB8500_PRCM_GPIOCR,
+			DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
+	}
+}
+
+/**
+ * prcmu_disable_stm_ape - Disables pin muxing for STM APE on OtherAlternateC1.
+ */
+static inline void prcmu_disable_stm_ape(void)
+{
+	if (cpu_is_u8500()) {
+		prcmu_clear(DB8500_PRCM_GPIOCR,
+			DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
+	}
+}
+
+#else
+
+static inline void prcmu_enable_spi2(void) {}
+static inline void prcmu_disable_spi2(void) {}
+static inline void prcmu_enable_stm_mod_uart(void) {}
+static inline void prcmu_disable_stm_mod_uart(void) {}
+static inline void prcmu_enable_stm_ape(void) {}
+static inline void prcmu_disable_stm_ape(void) {}
+
 #endif
 #endif
 
 
 /* PRCMU QoS APE OPP class */
 /* PRCMU QoS APE OPP class */
 #define PRCMU_QOS_APE_OPP 1
 #define PRCMU_QOS_APE_OPP 1
 #define PRCMU_QOS_DDR_OPP 2
 #define PRCMU_QOS_DDR_OPP 2
+#define PRCMU_QOS_ARM_OPP 3
 #define PRCMU_QOS_DEFAULT_VALUE -1
 #define PRCMU_QOS_DEFAULT_VALUE -1
 
 
-#ifdef CONFIG_UX500_PRCMU_QOS_POWER
+#ifdef CONFIG_DBX500_PRCMU_QOS_POWER
 
 
 unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
 unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
 void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
 void prcmu_qos_set_cpufreq_opp_delay(unsigned long);

+ 15 - 1
include/linux/mfd/mc13xxx.h

@@ -38,7 +38,8 @@ int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq);
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
 
 
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,
-		unsigned int mode, unsigned int channel, unsigned int *sample);
+		unsigned int mode, unsigned int channel,
+		u8 ato, bool atox, unsigned int *sample);
 
 
 #define MC13XXX_IRQ_ADCDONE	0
 #define MC13XXX_IRQ_ADCDONE	0
 #define MC13XXX_IRQ_ADCBISDONE	1
 #define MC13XXX_IRQ_ADCBISDONE	1
@@ -157,6 +158,18 @@ struct mc13xxx_buttons_platform_data {
 	unsigned short b3on_key;
 	unsigned short b3on_key;
 };
 };
 
 
+struct mc13xxx_ts_platform_data {
+	/* Delay between Touchscreen polarization and ADC Conversion.
+	 * Given in clock ticks of a 32 kHz clock which gives a granularity of
+	 * about 30.5ms */
+	u8 ato;
+
+#define MC13783_TS_ATO_FIRST false
+#define MC13783_TS_ATO_EACH  true
+	/* Use the ATO delay only for the first conversion or for each one */
+	bool atox;
+};
+
 struct mc13xxx_platform_data {
 struct mc13xxx_platform_data {
 #define MC13XXX_USE_TOUCHSCREEN (1 << 0)
 #define MC13XXX_USE_TOUCHSCREEN (1 << 0)
 #define MC13XXX_USE_CODEC	(1 << 1)
 #define MC13XXX_USE_CODEC	(1 << 1)
@@ -167,6 +180,7 @@ struct mc13xxx_platform_data {
 	struct mc13xxx_regulator_platform_data regulators;
 	struct mc13xxx_regulator_platform_data regulators;
 	struct mc13xxx_leds_platform_data *leds;
 	struct mc13xxx_leds_platform_data *leds;
 	struct mc13xxx_buttons_platform_data *buttons;
 	struct mc13xxx_buttons_platform_data *buttons;
+	struct mc13xxx_ts_platform_data touch;
 };
 };
 
 
 #define MC13XXX_ADC_MODE_TS		1
 #define MC13XXX_ADC_MODE_TS		1

+ 295 - 0
include/linux/mfd/rc5t583.h

@@ -0,0 +1,295 @@
+/*
+ * Core driver interface to access RICOH_RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ *      Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __LINUX_MFD_RC5T583_H
+#define __LINUX_MFD_RC5T583_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#define RC5T583_MAX_REGS		0xF8
+
+/* Maximum number of main interrupts */
+#define MAX_MAIN_INTERRUPT		5
+#define RC5T583_MAX_GPEDGE_REG		2
+#define RC5T583_MAX_INTERRUPT_MASK_REGS	9
+
+/* Interrupt enable register */
+#define RC5T583_INT_EN_SYS1	0x19
+#define RC5T583_INT_EN_SYS2	0x1D
+#define RC5T583_INT_EN_DCDC	0x41
+#define RC5T583_INT_EN_RTC	0xED
+#define RC5T583_INT_EN_ADC1	0x90
+#define RC5T583_INT_EN_ADC2	0x91
+#define RC5T583_INT_EN_ADC3	0x92
+
+/* Interrupt status registers (monitor regs in Ricoh)*/
+#define RC5T583_INTC_INTPOL	0xAD
+#define RC5T583_INTC_INTEN	0xAE
+#define RC5T583_INTC_INTMON	0xAF
+
+#define RC5T583_INT_MON_GRP	0xAF
+#define RC5T583_INT_MON_SYS1	0x1B
+#define RC5T583_INT_MON_SYS2	0x1F
+#define RC5T583_INT_MON_DCDC	0x43
+#define RC5T583_INT_MON_RTC	0xEE
+
+/* Interrupt clearing registers */
+#define RC5T583_INT_IR_SYS1	0x1A
+#define RC5T583_INT_IR_SYS2	0x1E
+#define RC5T583_INT_IR_DCDC	0x42
+#define RC5T583_INT_IR_RTC	0xEE
+#define RC5T583_INT_IR_ADCL	0x94
+#define RC5T583_INT_IR_ADCH	0x95
+#define RC5T583_INT_IR_ADCEND	0x96
+#define RC5T583_INT_IR_GPIOR	0xA9
+#define RC5T583_INT_IR_GPIOF	0xAA
+
+/* Sleep sequence registers */
+#define RC5T583_SLPSEQ1		0x21
+#define RC5T583_SLPSEQ2		0x22
+#define RC5T583_SLPSEQ3		0x23
+#define RC5T583_SLPSEQ4		0x24
+#define RC5T583_SLPSEQ5		0x25
+#define RC5T583_SLPSEQ6		0x26
+#define RC5T583_SLPSEQ7		0x27
+#define RC5T583_SLPSEQ8		0x28
+#define RC5T583_SLPSEQ9		0x29
+#define RC5T583_SLPSEQ10	0x2A
+#define RC5T583_SLPSEQ11	0x2B
+
+/* Regulator registers */
+#define RC5T583_REG_DC0CTL	0x30
+#define RC5T583_REG_DC0DAC	0x31
+#define RC5T583_REG_DC0LATCTL	0x32
+#define RC5T583_REG_SR0CTL	0x33
+
+#define RC5T583_REG_DC1CTL	0x34
+#define RC5T583_REG_DC1DAC	0x35
+#define RC5T583_REG_DC1LATCTL	0x36
+#define RC5T583_REG_SR1CTL	0x37
+
+#define RC5T583_REG_DC2CTL	0x38
+#define RC5T583_REG_DC2DAC	0x39
+#define RC5T583_REG_DC2LATCTL	0x3A
+#define RC5T583_REG_SR2CTL	0x3B
+
+#define RC5T583_REG_DC3CTL	0x3C
+#define RC5T583_REG_DC3DAC	0x3D
+#define RC5T583_REG_DC3LATCTL	0x3E
+#define RC5T583_REG_SR3CTL	0x3F
+
+
+#define RC5T583_REG_LDOEN1	0x50
+#define RC5T583_REG_LDOEN2	0x51
+#define RC5T583_REG_LDODIS1	0x52
+#define RC5T583_REG_LDODIS2	0x53
+
+#define RC5T583_REG_LDO0DAC	0x54
+#define RC5T583_REG_LDO1DAC	0x55
+#define RC5T583_REG_LDO2DAC	0x56
+#define RC5T583_REG_LDO3DAC	0x57
+#define RC5T583_REG_LDO4DAC	0x58
+#define RC5T583_REG_LDO5DAC	0x59
+#define RC5T583_REG_LDO6DAC	0x5A
+#define RC5T583_REG_LDO7DAC	0x5B
+#define RC5T583_REG_LDO8DAC	0x5C
+#define RC5T583_REG_LDO9DAC	0x5D
+
+#define RC5T583_REG_DC0DAC_DS	0x60
+#define RC5T583_REG_DC1DAC_DS	0x61
+#define RC5T583_REG_DC2DAC_DS	0x62
+#define RC5T583_REG_DC3DAC_DS	0x63
+
+#define RC5T583_REG_LDO0DAC_DS	0x64
+#define RC5T583_REG_LDO1DAC_DS	0x65
+#define RC5T583_REG_LDO2DAC_DS	0x66
+#define RC5T583_REG_LDO3DAC_DS	0x67
+#define RC5T583_REG_LDO4DAC_DS	0x68
+#define RC5T583_REG_LDO5DAC_DS	0x69
+#define RC5T583_REG_LDO6DAC_DS	0x6A
+#define RC5T583_REG_LDO7DAC_DS	0x6B
+#define RC5T583_REG_LDO8DAC_DS	0x6C
+#define RC5T583_REG_LDO9DAC_DS	0x6D
+
+/* GPIO register base address */
+#define RC5T583_GPIO_IOSEL	0xA0
+#define RC5T583_GPIO_PDEN	0xA1
+#define RC5T583_GPIO_IOOUT	0xA2
+#define RC5T583_GPIO_PGSEL	0xA3
+#define RC5T583_GPIO_GPINV	0xA4
+#define RC5T583_GPIO_GPDEB	0xA5
+#define RC5T583_GPIO_GPEDGE1	0xA6
+#define RC5T583_GPIO_GPEDGE2	0xA7
+#define RC5T583_GPIO_EN_INT	0xA8
+#define RC5T583_GPIO_MON_IOIN	0xAB
+#define RC5T583_GPIO_GPOFUNC	0xAC
+
+/* RICOH_RC5T583 IRQ definitions */
+enum {
+	RC5T583_IRQ_ONKEY,
+	RC5T583_IRQ_ACOK,
+	RC5T583_IRQ_LIDOPEN,
+	RC5T583_IRQ_PREOT,
+	RC5T583_IRQ_CLKSTP,
+	RC5T583_IRQ_ONKEY_OFF,
+	RC5T583_IRQ_WD,
+	RC5T583_IRQ_EN_PWRREQ1,
+	RC5T583_IRQ_EN_PWRREQ2,
+	RC5T583_IRQ_PRE_VINDET,
+
+	RC5T583_IRQ_DC0LIM,
+	RC5T583_IRQ_DC1LIM,
+	RC5T583_IRQ_DC2LIM,
+	RC5T583_IRQ_DC3LIM,
+
+	RC5T583_IRQ_CTC,
+	RC5T583_IRQ_YALE,
+	RC5T583_IRQ_DALE,
+	RC5T583_IRQ_WALE,
+
+	RC5T583_IRQ_AIN1L,
+	RC5T583_IRQ_AIN2L,
+	RC5T583_IRQ_AIN3L,
+	RC5T583_IRQ_VBATL,
+	RC5T583_IRQ_VIN3L,
+	RC5T583_IRQ_VIN8L,
+	RC5T583_IRQ_AIN1H,
+	RC5T583_IRQ_AIN2H,
+	RC5T583_IRQ_AIN3H,
+	RC5T583_IRQ_VBATH,
+	RC5T583_IRQ_VIN3H,
+	RC5T583_IRQ_VIN8H,
+	RC5T583_IRQ_ADCEND,
+
+	RC5T583_IRQ_GPIO0,
+	RC5T583_IRQ_GPIO1,
+	RC5T583_IRQ_GPIO2,
+	RC5T583_IRQ_GPIO3,
+	RC5T583_IRQ_GPIO4,
+	RC5T583_IRQ_GPIO5,
+	RC5T583_IRQ_GPIO6,
+	RC5T583_IRQ_GPIO7,
+
+	/* Should be last entry */
+	RC5T583_MAX_IRQS,
+};
+
+/* Ricoh583 gpio definitions */
+enum {
+	RC5T583_GPIO0,
+	RC5T583_GPIO1,
+	RC5T583_GPIO2,
+	RC5T583_GPIO3,
+	RC5T583_GPIO4,
+	RC5T583_GPIO5,
+	RC5T583_GPIO6,
+	RC5T583_GPIO7,
+
+	/* Should be last entry */
+	RC5T583_MAX_GPIO,
+};
+
+enum {
+	RC5T583_DS_NONE,
+	RC5T583_DS_DC0,
+	RC5T583_DS_DC1,
+	RC5T583_DS_DC2,
+	RC5T583_DS_DC3,
+	RC5T583_DS_LDO0,
+	RC5T583_DS_LDO1,
+	RC5T583_DS_LDO2,
+	RC5T583_DS_LDO3,
+	RC5T583_DS_LDO4,
+	RC5T583_DS_LDO5,
+	RC5T583_DS_LDO6,
+	RC5T583_DS_LDO7,
+	RC5T583_DS_LDO8,
+	RC5T583_DS_LDO9,
+	RC5T583_DS_PSO0,
+	RC5T583_DS_PSO1,
+	RC5T583_DS_PSO2,
+	RC5T583_DS_PSO3,
+	RC5T583_DS_PSO4,
+	RC5T583_DS_PSO5,
+	RC5T583_DS_PSO6,
+	RC5T583_DS_PSO7,
+
+	/* Should be last entry */
+	RC5T583_DS_MAX,
+};
+
+/*
+ * Ricoh pmic RC5T583 supports sleep through two external controls.
+ * The output of gpios and regulator can be enable/disable through
+ * this external signals.
+ */
+enum {
+	RC5T583_EXT_PWRREQ1_CONTROL = 0x1,
+	RC5T583_EXT_PWRREQ2_CONTROL = 0x2,
+};
+
+struct rc5t583 {
+	struct device	*dev;
+	struct regmap	*regmap;
+	int		chip_irq;
+	int		irq_base;
+	struct mutex	irq_lock;
+	unsigned long	group_irq_en[MAX_MAIN_INTERRUPT];
+
+	/* For main interrupt bits in INTC */
+	uint8_t		intc_inten_reg;
+
+	/* For group interrupt bits and address */
+	uint8_t		irq_en_reg[RC5T583_MAX_INTERRUPT_MASK_REGS];
+
+	/* For gpio edge */
+	uint8_t		gpedge_reg[RC5T583_MAX_GPEDGE_REG];
+};
+
+/*
+ * rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
+ * The board specific data is provided through this structure.
+ * @irq_base: Irq base number on which this device registers their interrupts.
+ * @enable_shutdown: Enable shutdown through the input pin "shutdown".
+ */
+
+struct rc5t583_platform_data {
+	int		irq_base;
+	bool		enable_shutdown;
+};
+
+int rc5t583_write(struct device *dev, u8 reg, uint8_t val);
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val);
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+		unsigned int bit_mask);
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+		unsigned int bit_mask);
+int rc5t583_update(struct device *dev, unsigned int reg,
+		unsigned int val, unsigned int mask);
+int rc5t583_ext_power_req_config(struct device *dev, int deepsleep_id,
+	int ext_pwr_req, int deepsleep_slot_nr);
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base);
+int rc5t583_irq_exit(struct rc5t583 *rc5t583);
+
+#endif

+ 1 - 0
include/linux/mfd/stmpe.h

@@ -28,6 +28,7 @@ enum stmpe_partnum {
 	STMPE1601,
 	STMPE1601,
 	STMPE2401,
 	STMPE2401,
 	STMPE2403,
 	STMPE2403,
+	STMPE_NBR_PARTS
 };
 };
 
 
 /*
 /*

+ 46 - 0
include/linux/mfd/tps65090.h

@@ -0,0 +1,46 @@
+/*
+ * Core driver interface for TI TPS65090 PMIC family
+ *
+ * Copyright (C) 2012 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_TPS65090_H
+#define __LINUX_MFD_TPS65090_H
+
+struct tps65090_subdev_info {
+	int		id;
+	const char	*name;
+	void		*platform_data;
+};
+
+struct tps65090_platform_data {
+	int irq_base;
+	int num_subdevs;
+	struct tps65090_subdev_info *subdevs;
+};
+
+/*
+ * NOTE: the functions below are not intended for use outside
+ * of the TPS65090 sub-device drivers
+ */
+extern int tps65090_write(struct device *dev, int reg, uint8_t val);
+extern int tps65090_read(struct device *dev, int reg, uint8_t *val);
+extern int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num);
+extern int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num);
+
+#endif /*__LINUX_MFD_TPS65090_H */

+ 283 - 0
include/linux/mfd/tps65217.h

@@ -0,0 +1,283 @@
+/*
+ * linux/mfd/tps65217.h
+ *
+ * Functions to access TPS65217 power management chip.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_MFD_TPS65217_H
+#define __LINUX_MFD_TPS65217_H
+
+#include <linux/i2c.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* I2C ID for TPS65217 part */
+#define TPS65217_I2C_ID			0x24
+
+/* All register addresses */
+#define TPS65217_REG_CHIPID		0X00
+#define TPS65217_REG_PPATH		0X01
+#define TPS65217_REG_INT		0X02
+#define TPS65217_REG_CHGCONFIG0		0X03
+#define TPS65217_REG_CHGCONFIG1		0X04
+#define TPS65217_REG_CHGCONFIG2		0X05
+#define TPS65217_REG_CHGCONFIG3		0X06
+#define TPS65217_REG_WLEDCTRL1		0X07
+#define TPS65217_REG_WLEDCTRL2		0X08
+#define TPS65217_REG_MUXCTRL		0X09
+#define TPS65217_REG_STATUS		0X0A
+#define TPS65217_REG_PASSWORD		0X0B
+#define TPS65217_REG_PGOOD		0X0C
+#define TPS65217_REG_DEFPG		0X0D
+#define TPS65217_REG_DEFDCDC1		0X0E
+#define TPS65217_REG_DEFDCDC2		0X0F
+#define TPS65217_REG_DEFDCDC3		0X10
+#define TPS65217_REG_DEFSLEW		0X11
+#define TPS65217_REG_DEFLDO1		0X12
+#define TPS65217_REG_DEFLDO2		0X13
+#define TPS65217_REG_DEFLS1		0X14
+#define TPS65217_REG_DEFLS2		0X15
+#define TPS65217_REG_ENABLE		0X16
+#define TPS65217_REG_DEFUVLO		0X18
+#define TPS65217_REG_SEQ1		0X19
+#define TPS65217_REG_SEQ2		0X1A
+#define TPS65217_REG_SEQ3		0X1B
+#define TPS65217_REG_SEQ4		0X1C
+#define TPS65217_REG_SEQ5		0X1D
+#define TPS65217_REG_SEQ6		0X1E
+
+/* Register field definitions */
+#define TPS65217_CHIPID_CHIP_MASK	0xF0
+#define TPS65217_CHIPID_REV_MASK	0x0F
+
+#define TPS65217_PPATH_ACSINK_ENABLE	BIT(7)
+#define TPS65217_PPATH_USBSINK_ENABLE	BIT(6)
+#define TPS65217_PPATH_AC_PW_ENABLE	BIT(5)
+#define TPS65217_PPATH_USB_PW_ENABLE	BIT(4)
+#define TPS65217_PPATH_AC_CURRENT_MASK	0x0C
+#define TPS65217_PPATH_USB_CURRENT_MASK	0x03
+
+#define TPS65217_INT_PBM		BIT(6)
+#define TPS65217_INT_ACM		BIT(5)
+#define TPS65217_INT_USBM		BIT(4)
+#define TPS65217_INT_PBI		BIT(2)
+#define TPS65217_INT_ACI		BIT(1)
+#define TPS65217_INT_USBI		BIT(0)
+
+#define TPS65217_CHGCONFIG0_TREG	BIT(7)
+#define TPS65217_CHGCONFIG0_DPPM	BIT(6)
+#define TPS65217_CHGCONFIG0_TSUSP	BIT(5)
+#define TPS65217_CHGCONFIG0_TERMI	BIT(4)
+#define TPS65217_CHGCONFIG0_ACTIVE	BIT(3)
+#define TPS65217_CHGCONFIG0_CHGTOUT	BIT(2)
+#define TPS65217_CHGCONFIG0_PCHGTOUT	BIT(1)
+#define TPS65217_CHGCONFIG0_BATTEMP	BIT(0)
+
+#define TPS65217_CHGCONFIG1_TMR_MASK	0xC0
+#define TPS65217_CHGCONFIG1_TMR_ENABLE	BIT(5)
+#define TPS65217_CHGCONFIG1_NTC_TYPE	BIT(4)
+#define TPS65217_CHGCONFIG1_RESET	BIT(3)
+#define TPS65217_CHGCONFIG1_TERM	BIT(2)
+#define TPS65217_CHGCONFIG1_SUSP	BIT(1)
+#define TPS65217_CHGCONFIG1_CHG_EN	BIT(0)
+
+#define TPS65217_CHGCONFIG2_DYNTMR	BIT(7)
+#define TPS65217_CHGCONFIG2_VPREGHG	BIT(6)
+#define TPS65217_CHGCONFIG2_VOREG_MASK	0x30
+
+#define TPS65217_CHGCONFIG3_ICHRG_MASK	0xC0
+#define TPS65217_CHGCONFIG3_DPPMTH_MASK	0x30
+#define TPS65217_CHGCONFIG2_PCHRGT	BIT(3)
+#define TPS65217_CHGCONFIG2_TERMIF	0x06
+#define TPS65217_CHGCONFIG2_TRANGE	BIT(0)
+
+#define TPS65217_WLEDCTRL1_ISINK_ENABLE	BIT(3)
+#define TPS65217_WLEDCTRL1_ISEL		BIT(2)
+#define TPS65217_WLEDCTRL1_FDIM_MASK	0x03
+
+#define TPS65217_WLEDCTRL2_DUTY_MASK	0x7F
+
+#define TPS65217_MUXCTRL_MUX_MASK	0x07
+
+#define TPS65217_STATUS_OFF		BIT(7)
+#define TPS65217_STATUS_ACPWR		BIT(3)
+#define TPS65217_STATUS_USBPWR		BIT(2)
+#define TPS65217_STATUS_PB		BIT(0)
+
+#define TPS65217_PASSWORD_REGS_UNLOCK	0x7D
+
+#define TPS65217_PGOOD_LDO3_PG		BIT(6)
+#define TPS65217_PGOOD_LDO4_PG		BIT(5)
+#define TPS65217_PGOOD_DC1_PG		BIT(4)
+#define TPS65217_PGOOD_DC2_PG		BIT(3)
+#define TPS65217_PGOOD_DC3_PG		BIT(2)
+#define TPS65217_PGOOD_LDO1_PG		BIT(1)
+#define TPS65217_PGOOD_LDO2_PG		BIT(0)
+
+#define TPS65217_DEFPG_LDO1PGM		BIT(3)
+#define TPS65217_DEFPG_LDO2PGM		BIT(2)
+#define TPS65217_DEFPG_PGDLY_MASK	0x03
+
+#define TPS65217_DEFDCDCX_XADJX		BIT(7)
+#define TPS65217_DEFDCDCX_DCDC_MASK	0x3F
+
+#define TPS65217_DEFSLEW_GO		BIT(7)
+#define TPS65217_DEFSLEW_GODSBL		BIT(6)
+#define TPS65217_DEFSLEW_PFM_EN1	BIT(5)
+#define TPS65217_DEFSLEW_PFM_EN2	BIT(4)
+#define TPS65217_DEFSLEW_PFM_EN3	BIT(3)
+#define TPS65217_DEFSLEW_SLEW_MASK	0x07
+
+#define TPS65217_DEFLDO1_LDO1_MASK	0x0F
+
+#define TPS65217_DEFLDO2_TRACK		BIT(6)
+#define TPS65217_DEFLDO2_LDO2_MASK	0x3F
+
+#define TPS65217_DEFLDO3_LDO3_EN	BIT(5)
+#define TPS65217_DEFLDO3_LDO3_MASK	0x1F
+
+#define TPS65217_DEFLDO4_LDO4_EN	BIT(5)
+#define TPS65217_DEFLDO4_LDO4_MASK	0x1F
+
+#define TPS65217_ENABLE_LS1_EN		BIT(6)
+#define TPS65217_ENABLE_LS2_EN		BIT(5)
+#define TPS65217_ENABLE_DC1_EN		BIT(4)
+#define TPS65217_ENABLE_DC2_EN		BIT(3)
+#define TPS65217_ENABLE_DC3_EN		BIT(2)
+#define TPS65217_ENABLE_LDO1_EN		BIT(1)
+#define TPS65217_ENABLE_LDO2_EN		BIT(0)
+
+#define TPS65217_DEFUVLO_UVLOHYS	BIT(2)
+#define TPS65217_DEFUVLO_UVLO_MASK	0x03
+
+#define TPS65217_SEQ1_DC1_SEQ_MASK	0xF0
+#define TPS65217_SEQ1_DC2_SEQ_MASK	0x0F
+
+#define TPS65217_SEQ2_DC3_SEQ_MASK	0xF0
+#define TPS65217_SEQ2_LDO1_SEQ_MASK	0x0F
+
+#define TPS65217_SEQ3_LDO2_SEQ_MASK	0xF0
+#define TPS65217_SEQ3_LDO3_SEQ_MASK	0x0F
+
+#define TPS65217_SEQ4_LDO4_SEQ_MASK	0xF0
+
+#define TPS65217_SEQ5_DLY1_MASK		0xC0
+#define TPS65217_SEQ5_DLY2_MASK		0x30
+#define TPS65217_SEQ5_DLY3_MASK		0x0C
+#define TPS65217_SEQ5_DLY4_MASK		0x03
+
+#define TPS65217_SEQ6_DLY5_MASK		0xC0
+#define TPS65217_SEQ6_DLY6_MASK		0x30
+#define TPS65217_SEQ6_SEQUP		BIT(2)
+#define TPS65217_SEQ6_SEQDWN		BIT(1)
+#define TPS65217_SEQ6_INSTDWN		BIT(0)
+
+#define TPS65217_MAX_REGISTER		0x1E
+#define TPS65217_PROTECT_NONE		0
+#define TPS65217_PROTECT_L1		1
+#define TPS65217_PROTECT_L2		2
+
+
+enum tps65217_regulator_id {
+	/* DCDC's */
+	TPS65217_DCDC_1,
+	TPS65217_DCDC_2,
+	TPS65217_DCDC_3,
+	/* LDOs */
+	TPS65217_LDO_1,
+	TPS65217_LDO_2,
+	TPS65217_LDO_3,
+	TPS65217_LDO_4,
+};
+
+#define TPS65217_MAX_REG_ID		TPS65217_LDO_4
+
+/* Number of step-down converters available */
+#define TPS65217_NUM_DCDC		3
+/* Number of LDO voltage regulators available */
+#define TPS65217_NUM_LDO		4
+/* Number of total regulators available */
+#define TPS65217_NUM_REGULATOR		(TPS65217_NUM_DCDC + TPS65217_NUM_LDO)
+
+/**
+ * struct tps65217_board - packages regulator init data
+ * @tps65217_regulator_data: regulator initialization values
+ *
+ * Board data may be used to initialize regulator.
+ */
+struct tps65217_board {
+	struct regulator_init_data *tps65217_init_data;
+};
+
+/**
+ * struct tps_info - packages regulator constraints
+ * @name:		Voltage regulator name
+ * @min_uV:		minimum micro volts
+ * @max_uV:		minimum micro volts
+ * @vsel_to_uv:		Function pointer to get voltage from selector
+ * @uv_to_vsel:		Function pointer to get selector from voltage
+ * @table:		Table for non-uniform voltage step-size
+ * @table_len:		Length of the voltage table
+ * @enable_mask:	Regulator enable mask bits
+ * @set_vout_reg:	Regulator output voltage set register
+ * @set_vout_mask:	Regulator output voltage set mask
+ *
+ * This data is used to check the regualtor voltage limits while setting.
+ */
+struct tps_info {
+	const char *name;
+	int min_uV;
+	int max_uV;
+	int (*vsel_to_uv)(unsigned int vsel);
+	int (*uv_to_vsel)(int uV, unsigned int *vsel);
+	const int *table;
+	unsigned int table_len;
+	unsigned int enable_mask;
+	unsigned int set_vout_reg;
+	unsigned int set_vout_mask;
+};
+
+/**
+ * struct tps65217 - tps65217 sub-driver chip access routines
+ *
+ * Device data may be used to access the TPS65217 chip
+ */
+
+struct tps65217 {
+	struct device *dev;
+	struct tps65217_board *pdata;
+	struct regulator_desc desc[TPS65217_NUM_REGULATOR];
+	struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
+	struct tps_info *info[TPS65217_NUM_REGULATOR];
+	struct regmap *regmap;
+
+	/* Client devices */
+	struct platform_device *regulator_pdev[TPS65217_NUM_REGULATOR];
+};
+
+static inline struct tps65217 *dev_to_tps65217(struct device *dev)
+{
+	return dev_get_drvdata(dev);
+}
+
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+					unsigned int *val);
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+			unsigned int val, unsigned int level);
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int val, unsigned int level);
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+		unsigned int mask, unsigned int level);
+
+#endif /*  __LINUX_MFD_TPS65217_H */

+ 3 - 0
include/linux/mfd/tps65910.h

@@ -17,6 +17,8 @@
 #ifndef __LINUX_MFD_TPS65910_H
 #ifndef __LINUX_MFD_TPS65910_H
 #define __LINUX_MFD_TPS65910_H
 #define __LINUX_MFD_TPS65910_H
 
 
+#include <linux/gpio.h>
+
 /* TPS chip id list */
 /* TPS chip id list */
 #define TPS65910			0
 #define TPS65910			0
 #define TPS65911			1
 #define TPS65911			1
@@ -796,6 +798,7 @@ struct tps65910_board {
 struct tps65910 {
 struct tps65910 {
 	struct device *dev;
 	struct device *dev;
 	struct i2c_client *i2c_client;
 	struct i2c_client *i2c_client;
+	struct regmap *regmap;
 	struct mutex io_mutex;
 	struct mutex io_mutex;
 	unsigned int id;
 	unsigned int id;
 	int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
 	int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);

+ 0 - 1
include/linux/mfd/wm8994/pdata.h

@@ -22,7 +22,6 @@ struct wm8994_ldo_pdata {
 	/** GPIOs to enable regulator, 0 or less if not available */
 	/** GPIOs to enable regulator, 0 or less if not available */
 	int enable;
 	int enable;
 
 
-	const char *supply;
 	const struct regulator_init_data *init_data;
 	const struct regulator_init_data *init_data;
 };
 };
 
 

+ 69 - 1
include/linux/regulator/ab8500.h

@@ -26,7 +26,26 @@ enum ab8500_regulator_id {
 	AB8500_NUM_REGULATORS,
 	AB8500_NUM_REGULATORS,
 };
 };
 
 
-/* AB8500 register initialization */
+/* AB9450 regulators */
+enum ab9540_regulator_id {
+	AB9540_LDO_AUX1,
+	AB9540_LDO_AUX2,
+	AB9540_LDO_AUX3,
+	AB9540_LDO_AUX4,
+	AB9540_LDO_INTCORE,
+	AB9540_LDO_TVOUT,
+	AB9540_LDO_USB,
+	AB9540_LDO_AUDIO,
+	AB9540_LDO_ANAMIC1,
+	AB9540_LDO_ANAMIC2,
+	AB9540_LDO_DMIC,
+	AB9540_LDO_ANA,
+	AB9540_SYSCLKREQ_2,
+	AB9540_SYSCLKREQ_4,
+	AB9540_NUM_REGULATORS,
+};
+
+/* AB8500 and AB9540 register initialization */
 struct ab8500_regulator_reg_init {
 struct ab8500_regulator_reg_init {
 	int id;
 	int id;
 	u8 value;
 	u8 value;
@@ -71,4 +90,53 @@ enum ab8500_regulator_reg {
 	AB8500_NUM_REGULATOR_REGISTERS,
 	AB8500_NUM_REGULATOR_REGISTERS,
 };
 };
 
 
+
+/* AB9540 registers */
+enum ab9540_regulator_reg {
+	AB9540_REGUREQUESTCTRL1,
+	AB9540_REGUREQUESTCTRL2,
+	AB9540_REGUREQUESTCTRL3,
+	AB9540_REGUREQUESTCTRL4,
+	AB9540_REGUSYSCLKREQ1HPVALID1,
+	AB9540_REGUSYSCLKREQ1HPVALID2,
+	AB9540_REGUHWHPREQ1VALID1,
+	AB9540_REGUHWHPREQ1VALID2,
+	AB9540_REGUHWHPREQ2VALID1,
+	AB9540_REGUHWHPREQ2VALID2,
+	AB9540_REGUSWHPREQVALID1,
+	AB9540_REGUSWHPREQVALID2,
+	AB9540_REGUSYSCLKREQVALID1,
+	AB9540_REGUSYSCLKREQVALID2,
+	AB9540_REGUVAUX4REQVALID,
+	AB9540_REGUMISC1,
+	AB9540_VAUDIOSUPPLY,
+	AB9540_REGUCTRL1VAMIC,
+	AB9540_VSMPS1REGU,
+	AB9540_VSMPS2REGU,
+	AB9540_VSMPS3REGU, /* NOTE! PRCMU register */
+	AB9540_VPLLVANAREGU,
+	AB9540_EXTSUPPLYREGU,
+	AB9540_VAUX12REGU,
+	AB9540_VRF1VAUX3REGU,
+	AB9540_VSMPS1SEL1,
+	AB9540_VSMPS1SEL2,
+	AB9540_VSMPS1SEL3,
+	AB9540_VSMPS2SEL1,
+	AB9540_VSMPS2SEL2,
+	AB9540_VSMPS2SEL3,
+	AB9540_VSMPS3SEL1, /* NOTE! PRCMU register */
+	AB9540_VSMPS3SEL2, /* NOTE! PRCMU register */
+	AB9540_VAUX1SEL,
+	AB9540_VAUX2SEL,
+	AB9540_VRF1VAUX3SEL,
+	AB9540_REGUCTRL2SPARE,
+	AB9540_VAUX4REQCTRL,
+	AB9540_VAUX4REGU,
+	AB9540_VAUX4SEL,
+	AB9540_REGUCTRLDISCH,
+	AB9540_REGUCTRLDISCH2,
+	AB9540_REGUCTRLDISCH3,
+	AB9540_NUM_REGULATOR_REGISTERS,
+};
+
 #endif
 #endif