Browse Source

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (73 commits)
  power: Revert "power_supply: Mark twl4030_charger as broken"
  mfd: Fix a memory leak when unload mc13xxx-core module
  mfd: Fix resource reclaim for max8998
  mfd: Remove unneeded ret value checking for max8998 register updates
  mfd: Add free max8998->ono irq in max8998_irq_exit()
  mfd: Fix resource reclaim in pcf50633_remove()
  omap4: pandaboard: fix up mmc card detect logic
  mfd: Fix ezx_pcap_probe error path
  mfd: Fix off-by-one value range checking for tps6507x
  mfd: Remove __devinitdata from tc6393xb_mmc_resources
  mfd: Add WM831x SPI support
  mfd: Factor out WM831x I2C I/O from the core driver
  mfd: Remove DEBUG defines from mc13xxx-core
  mfd: Fix jz4740_adc_set_enabled
  mfd: Add TPS658621C device ID
  mfd: Fix twl-irq function declaration warnings
  regulator: max8998 BUCK1/2 voltage change with use of GPIOs
  mfd: Voltages and GPIOs platform_data definitions for max8998
  regulator: max8998 BUCK1/2 internal voltages and indexes defined
  mfd: Support for ICs compliant with max8998
  ...
Linus Torvalds 14 years ago
parent
commit
b779b332d0
77 changed files with 5648 additions and 2033 deletions
  1. 6 1
      arch/arm/mach-omap2/board-4430sdp.c
  2. 12 3
      arch/arm/mach-omap2/board-omap4panda.c
  3. 1 0
      arch/arm/mach-s3c64xx/Kconfig
  4. 19 0
      arch/arm/mach-shmobile/board-ap4evb.c
  5. 12 0
      drivers/gpio/Kconfig
  6. 1 0
      drivers/gpio/Makefile
  7. 9 4
      drivers/gpio/stmpe-gpio.c
  8. 332 0
      drivers/gpio/vx855_gpio.c
  9. 1 0
      drivers/gpio/wm8994-gpio.c
  10. 54 18
      drivers/input/misc/max8925_onkey.c
  11. 26 93
      drivers/leds/leds-88pm860x.c
  12. 49 2
      drivers/mfd/88pm860x-core.c
  13. 71 20
      drivers/mfd/Kconfig
  14. 7 2
      drivers/mfd/Makefile
  15. 75 68
      drivers/mfd/ab3100-core.c
  16. 183 116
      drivers/mfd/ab8500-core.c
  17. 652 0
      drivers/mfd/ab8500-debugfs.c
  18. 105 0
      drivers/mfd/ab8500-i2c.c
  19. 1 1
      drivers/mfd/ab8500-spi.c
  20. 7 1
      drivers/mfd/da903x.c
  21. 10 1
      drivers/mfd/ezx-pcap.c
  22. 0 7
      drivers/mfd/htc-pasic3.c
  23. 1 1
      drivers/mfd/jz4740-adc.c
  24. 8 3
      drivers/mfd/max8925-core.c
  25. 258 0
      drivers/mfd/max8998-irq.c
  26. 69 21
      drivers/mfd/max8998.c
  27. 0 752
      drivers/mfd/mc13783-core.c
  28. 840 0
      drivers/mfd/mc13xxx-core.c
  29. 11 7
      drivers/mfd/mfd-core.c
  30. 2 7
      drivers/mfd/pcf50633-core.c
  31. 19 0
      drivers/mfd/sh_mobile_sdhi.c
  32. 32 0
      drivers/mfd/stmpe.c
  33. 1 1
      drivers/mfd/tc6393xb.c
  34. 14 0
      drivers/mfd/timberdale.c
  35. 1 1
      drivers/mfd/tps6507x.c
  36. 223 2
      drivers/mfd/tps6586x.c
  37. 27 13
      drivers/mfd/twl-core.c
  38. 10 0
      drivers/mfd/twl-core.h
  39. 3 1
      drivers/mfd/twl4030-irq.c
  40. 16 14
      drivers/mfd/twl4030-power.c
  41. 75 0
      drivers/mfd/twl6030-irq.c
  42. 147 0
      drivers/mfd/vx855.c
  43. 16 132
      drivers/mfd/wm831x-core.c
  44. 143 0
      drivers/mfd/wm831x-i2c.c
  45. 232 0
      drivers/mfd/wm831x-spi.c
  46. 9 0
      drivers/misc/Kconfig
  47. 1 0
      drivers/misc/Makefile
  48. 168 0
      drivers/misc/ab8500-pwm.c
  49. 2 2
      drivers/mmc/host/omap_hsmmc.c
  50. 12 0
      drivers/mmc/host/sh_mmcif.c
  51. 25 5
      drivers/mmc/host/tmio_mmc.c
  52. 0 1
      drivers/power/Kconfig
  53. 50 36
      drivers/regulator/ab8500.c
  54. 245 25
      drivers/regulator/max8998.c
  55. 15 4
      drivers/rtc/Kconfig
  56. 2 1
      drivers/rtc/Makefile
  57. 53 50
      drivers/rtc/rtc-ab8500.c
  58. 300 0
      drivers/rtc/rtc-max8998.c
  59. 0 428
      drivers/rtc/rtc-mc13783.c
  60. 437 0
      drivers/rtc/rtc-mc13xxx.c
  61. 9 4
      drivers/usb/otg/twl4030-usb.c
  62. 77 0
      include/linux/i2c/twl.h
  63. 1 1
      include/linux/mfd/88pm860x.h
  64. 24 4
      include/linux/mfd/ab8500.h
  65. 2 2
      include/linux/mfd/abx500.h
  66. 3 0
      include/linux/mfd/core.h
  67. 96 33
      include/linux/mfd/max8998-private.h
  68. 19 4
      include/linux/mfd/max8998.h
  69. 98 141
      include/linux/mfd/mc13783.h
  70. 154 0
      include/linux/mfd/mc13xxx.h
  71. 7 0
      include/linux/mfd/pcf50633/core.h
  72. 2 0
      include/linux/mfd/sh_mobile_sdhi.h
  73. 6 0
      include/linux/mfd/stmpe.h
  74. 6 0
      include/linux/mfd/tmio.h
  75. 31 0
      include/linux/mfd/tps6586x.h
  76. 12 0
      include/linux/mfd/wm831x/core.h
  77. 1 0
      include/linux/mmc/sh_mmcif.h

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

@@ -269,9 +269,14 @@ static int omap4_twl6030_hsmmc_late_init(struct 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)
+			pr_err("Failed configuring MMC1 card detect\n");
 		pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
 		pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
 						MMCDETECT_INTR_OFFSET;
 						MMCDETECT_INTR_OFFSET;
+		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+	}
 	return ret;
 	return ret;
 }
 }
 
 

+ 12 - 3
arch/arm/mach-omap2/board-omap4panda.c

@@ -160,10 +160,19 @@ static int omap4_twl6030_hsmmc_late_init(struct device *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;
 
 
+	if (!pdata) {
+		dev_err(dev, "%s: NULL platform data\n", __func__);
+		return -EINVAL;
+	}
 	/* Setting MMC1 Card detect Irq */
 	/* Setting MMC1 Card detect Irq */
-	if (pdev->id == 0)
-		pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
-						MMCDETECT_INTR_OFFSET;
+	if (pdev->id == 0) {
+		ret = twl6030_mmc_card_detect_config();
+		 if (ret)
+			dev_err(dev, "%s: Error card detect config(%d)\n",
+				__func__, ret);
+		 else
+			pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+	}
 	return ret;
 	return ret;
 }
 }
 
 

+ 1 - 0
arch/arm/mach-s3c64xx/Kconfig

@@ -185,6 +185,7 @@ config SMDK6410_WM1192_EV1
 	select REGULATOR_WM831X
 	select REGULATOR_WM831X
 	select S3C24XX_GPIO_EXTRA64
 	select S3C24XX_GPIO_EXTRA64
 	select MFD_WM831X
 	select MFD_WM831X
+	select MFD_WM831X_I2C
 	help
 	help
 	  The Wolfson Microelectronics 1192-EV1 is a WM831x based PMIC
 	  The Wolfson Microelectronics 1192-EV1 is a WM831x based PMIC
 	  daughtercard for the Samsung SMDK6410 reference platform.
 	  daughtercard for the Samsung SMDK6410 reference platform.

+ 19 - 0
arch/arm/mach-shmobile/board-ap4evb.c

@@ -235,6 +235,18 @@ static struct platform_device smc911x_device = {
 	},
 	},
 };
 };
 
 
+/*
+ * The card detect pin of the top SD/MMC slot (CN7) is active low and is
+ * connected to GPIO A22 of SH7372 (GPIO_PORT41).
+ */
+static int slot_cn7_get_cd(struct platform_device *pdev)
+{
+	if (gpio_is_valid(GPIO_PORT41))
+		return !gpio_get_value(GPIO_PORT41);
+	else
+		return -ENXIO;
+}
+
 /* SH_MMCIF */
 /* SH_MMCIF */
 static struct resource sh_mmcif_resources[] = {
 static struct resource sh_mmcif_resources[] = {
 	[0] = {
 	[0] = {
@@ -261,6 +273,7 @@ static struct sh_mmcif_plat_data sh_mmcif_plat = {
 	.caps		= MMC_CAP_4_BIT_DATA |
 	.caps		= MMC_CAP_4_BIT_DATA |
 			  MMC_CAP_8_BIT_DATA |
 			  MMC_CAP_8_BIT_DATA |
 			  MMC_CAP_NEEDS_POLL,
 			  MMC_CAP_NEEDS_POLL,
+	.get_cd		= slot_cn7_get_cd,
 };
 };
 
 
 static struct platform_device sh_mmcif_device = {
 static struct platform_device sh_mmcif_device = {
@@ -310,6 +323,8 @@ static struct sh_mobile_sdhi_info sdhi1_info = {
 	.dma_slave_rx	= SHDMA_SLAVE_SDHI1_RX,
 	.dma_slave_rx	= SHDMA_SLAVE_SDHI1_RX,
 	.tmio_ocr_mask	= MMC_VDD_165_195,
 	.tmio_ocr_mask	= MMC_VDD_165_195,
 	.tmio_flags	= TMIO_MMC_WRPROTECT_DISABLE,
 	.tmio_flags	= TMIO_MMC_WRPROTECT_DISABLE,
+	.tmio_caps	= MMC_CAP_NEEDS_POLL,
+	.get_cd		= slot_cn7_get_cd,
 };
 };
 
 
 static struct resource sdhi1_resources[] = {
 static struct resource sdhi1_resources[] = {
@@ -948,6 +963,10 @@ static void __init ap4evb_init(void)
 	gpio_no_direction(GPIO_PORT9CR);  /* FSIAOBT needs no direction */
 	gpio_no_direction(GPIO_PORT9CR);  /* FSIAOBT needs no direction */
 	gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */
 	gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */
 
 
+	/* card detect pin for MMC slot (CN7) */
+	gpio_request(GPIO_PORT41, NULL);
+	gpio_direction_input(GPIO_PORT41);
+
 	/* set SPU2 clock to 119.6 MHz */
 	/* set SPU2 clock to 119.6 MHz */
 	clk = clk_get(NULL, "spu_clk");
 	clk = clk_get(NULL, "spu_clk");
 	if (!IS_ERR(clk)) {
 	if (!IS_ERR(clk)) {

+ 12 - 0
drivers/gpio/Kconfig

@@ -116,6 +116,18 @@ config GPIO_SCH
 	  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 sch-gpio.
 	  will be called sch-gpio.
 
 
+config GPIO_VX855
+	tristate "VIA VX855/VX875 GPIO"
+	depends on GPIOLIB
+	select MFD_CORE
+	select MFD_VX855
+	help
+	  Support access to the VX855/VX875 GPIO lines through the gpio library.
+
+	  This driver provides common support for accessing the device,
+	  additional drivers must be enabled in order to use the
+	  functionality of the device.
+
 comment "I2C GPIO expanders:"
 comment "I2C GPIO expanders:"
 
 
 config GPIO_MAX7300
 config GPIO_MAX7300

+ 1 - 0
drivers/gpio/Makefile

@@ -40,3 +40,4 @@ obj-$(CONFIG_GPIO_SCH)		+= sch_gpio.o
 obj-$(CONFIG_GPIO_RDC321X)	+= rdc321x-gpio.o
 obj-$(CONFIG_GPIO_RDC321X)	+= rdc321x-gpio.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= janz-ttl.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= janz-ttl.o
 obj-$(CONFIG_GPIO_SX150X)	+= sx150x.o
 obj-$(CONFIG_GPIO_SX150X)	+= sx150x.o
+obj-$(CONFIG_GPIO_VX855)	+= vx855_gpio.o

+ 9 - 4
drivers/gpio/stmpe-gpio.c

@@ -30,6 +30,7 @@ struct stmpe_gpio {
 	struct mutex irq_lock;
 	struct mutex irq_lock;
 
 
 	int irq_base;
 	int irq_base;
+	unsigned norequest_mask;
 
 
 	/* Caches of interrupt control registers for bus_lock */
 	/* Caches of interrupt control registers for bus_lock */
 	u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
 	u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
@@ -103,6 +104,9 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
 	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
 	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 
 
+	if (stmpe_gpio->norequest_mask & (1 << offset))
+		return -EINVAL;
+
 	return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
 	return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
 }
 }
 
 
@@ -287,8 +291,6 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
 	int irq;
 	int irq;
 
 
 	pdata = stmpe->pdata->gpio;
 	pdata = stmpe->pdata->gpio;
-	if (!pdata)
-		return -ENODEV;
 
 
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
 	if (irq < 0)
@@ -302,6 +304,7 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
 
 
 	stmpe_gpio->dev = &pdev->dev;
 	stmpe_gpio->dev = &pdev->dev;
 	stmpe_gpio->stmpe = stmpe;
 	stmpe_gpio->stmpe = stmpe;
+	stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0;
 
 
 	stmpe_gpio->chip = template_chip;
 	stmpe_gpio->chip = template_chip;
 	stmpe_gpio->chip.ngpio = stmpe->num_gpios;
 	stmpe_gpio->chip.ngpio = stmpe->num_gpios;
@@ -312,11 +315,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
 
 
 	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
 	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
 	if (ret)
 	if (ret)
-		return ret;
+		goto out_free;
 
 
 	ret = stmpe_gpio_irq_init(stmpe_gpio);
 	ret = stmpe_gpio_irq_init(stmpe_gpio);
 	if (ret)
 	if (ret)
-		goto out_free;
+		goto out_disable;
 
 
 	ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
 	ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
 				   "stmpe-gpio", stmpe_gpio);
 				   "stmpe-gpio", stmpe_gpio);
@@ -342,6 +345,8 @@ out_freeirq:
 	free_irq(irq, stmpe_gpio);
 	free_irq(irq, stmpe_gpio);
 out_removeirq:
 out_removeirq:
 	stmpe_gpio_irq_remove(stmpe_gpio);
 	stmpe_gpio_irq_remove(stmpe_gpio);
+out_disable:
+	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 out_free:
 out_free:
 	kfree(stmpe_gpio);
 	kfree(stmpe_gpio);
 	return ret;
 	return ret;

+ 332 - 0
drivers/gpio/vx855_gpio.c

@@ -0,0 +1,332 @@
+/*
+ * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO
+ *
+ * Copyright (C) 2009 VIA Technologies, Inc.
+ * Copyright (C) 2010 One Laptop per Child
+ * Author: Harald Welte <HaraldWelte@viatech.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#define MODULE_NAME "vx855_gpio"
+
+/* The VX855 south bridge has the following GPIO pins:
+ *	GPI 0...13	General Purpose Input
+ *	GPO 0...12	General Purpose Output
+ *	GPIO 0...14	General Purpose I/O (Open-Drain)
+ */
+
+#define NR_VX855_GPI	14
+#define NR_VX855_GPO	13
+#define NR_VX855_GPIO	15
+
+#define NR_VX855_GPInO	(NR_VX855_GPI + NR_VX855_GPO)
+#define NR_VX855_GP	(NR_VX855_GPI + NR_VX855_GPO + NR_VX855_GPIO)
+
+struct vx855_gpio {
+	struct gpio_chip gpio;
+	spinlock_t lock;
+	u32 io_gpi;
+	u32 io_gpo;
+	bool gpi_reserved;
+	bool gpo_reserved;
+};
+
+/* resolve a GPIx into the corresponding bit position */
+static inline u_int32_t gpi_i_bit(int i)
+{
+	if (i < 10)
+		return 1 << i;
+	else
+		return 1 << (i + 14);
+}
+
+static inline u_int32_t gpo_o_bit(int i)
+{
+	if (i < 11)
+		return 1 << i;
+	else
+		return 1 << (i + 14);
+}
+
+static inline u_int32_t gpio_i_bit(int i)
+{
+	if (i < 14)
+		return 1 << (i + 10);
+	else
+		return 1 << (i + 14);
+}
+
+static inline u_int32_t gpio_o_bit(int i)
+{
+	if (i < 14)
+		return 1 << (i + 11);
+	else
+		return 1 << (i + 13);
+}
+
+/* Mapping betwee numeric GPIO ID and the actual GPIO hardware numbering:
+ * 0..13	GPI 0..13
+ * 14..26	GPO 0..12
+ * 27..41	GPIO 0..14
+ */
+
+static int vx855gpio_direction_input(struct gpio_chip *gpio,
+				     unsigned int nr)
+{
+	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	unsigned long flags;
+	u_int32_t reg_out;
+
+	/* Real GPI bits are always in input direction */
+	if (nr < NR_VX855_GPI)
+		return 0;
+
+	/* Real GPO bits cannot be put in output direction */
+	if (nr < NR_VX855_GPInO)
+		return -EINVAL;
+
+	/* Open Drain GPIO have to be set to one */
+	spin_lock_irqsave(&vg->lock, flags);
+	reg_out = inl(vg->io_gpo);
+	reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
+	outl(reg_out, vg->io_gpo);
+	spin_unlock_irqrestore(&vg->lock, flags);
+
+	return 0;
+}
+
+static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr)
+{
+	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	u_int32_t reg_in;
+	int ret = 0;
+
+	if (nr < NR_VX855_GPI) {
+		reg_in = inl(vg->io_gpi);
+		if (reg_in & gpi_i_bit(nr))
+			ret = 1;
+	} else if (nr < NR_VX855_GPInO) {
+		/* GPO don't have an input bit, we need to read it
+		 * back from the output register */
+		reg_in = inl(vg->io_gpo);
+		if (reg_in & gpo_o_bit(nr - NR_VX855_GPI))
+			ret = 1;
+	} else {
+		reg_in = inl(vg->io_gpi);
+		if (reg_in & gpio_i_bit(nr - NR_VX855_GPInO))
+			ret = 1;
+	}
+
+	return ret;
+}
+
+static void vx855gpio_set(struct gpio_chip *gpio, unsigned int nr,
+			  int val)
+{
+	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	unsigned long flags;
+	u_int32_t reg_out;
+
+	/* True GPI cannot be switched to output mode */
+	if (nr < NR_VX855_GPI)
+		return;
+
+	spin_lock_irqsave(&vg->lock, flags);
+	reg_out = inl(vg->io_gpo);
+	if (nr < NR_VX855_GPInO) {
+		if (val)
+			reg_out |= gpo_o_bit(nr - NR_VX855_GPI);
+		else
+			reg_out &= ~gpo_o_bit(nr - NR_VX855_GPI);
+	} else {
+		if (val)
+			reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
+		else
+			reg_out &= ~gpio_o_bit(nr - NR_VX855_GPInO);
+	}
+	outl(reg_out, vg->io_gpo);
+	spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static int vx855gpio_direction_output(struct gpio_chip *gpio,
+				      unsigned int nr, int val)
+{
+	/* True GPI cannot be switched to output mode */
+	if (nr < NR_VX855_GPI)
+		return -EINVAL;
+
+	/* True GPO don't need to be switched to output mode,
+	 * and GPIO are open-drain, i.e. also need no switching,
+	 * so all we do is set the level */
+	vx855gpio_set(gpio, nr, val);
+
+	return 0;
+}
+
+static const char *vx855gpio_names[NR_VX855_GP] = {
+	"VX855_GPI0", "VX855_GPI1", "VX855_GPI2", "VX855_GPI3", "VX855_GPI4",
+	"VX855_GPI5", "VX855_GPI6", "VX855_GPI7", "VX855_GPI8", "VX855_GPI9",
+	"VX855_GPI10", "VX855_GPI11", "VX855_GPI12", "VX855_GPI13",
+	"VX855_GPO0", "VX855_GPO1", "VX855_GPO2", "VX855_GPO3", "VX855_GPO4",
+	"VX855_GPO5", "VX855_GPO6", "VX855_GPO7", "VX855_GPO8", "VX855_GPO9",
+	"VX855_GPO10", "VX855_GPO11", "VX855_GPO12",
+	"VX855_GPIO0", "VX855_GPIO1", "VX855_GPIO2", "VX855_GPIO3",
+	"VX855_GPIO4", "VX855_GPIO5", "VX855_GPIO6", "VX855_GPIO7",
+	"VX855_GPIO8", "VX855_GPIO9", "VX855_GPIO10", "VX855_GPIO11",
+	"VX855_GPIO12", "VX855_GPIO13", "VX855_GPIO14"
+};
+
+static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
+{
+	struct gpio_chip *c = &vg->gpio;
+
+	c->label = "VX855 South Bridge";
+	c->owner = THIS_MODULE;
+	c->direction_input = vx855gpio_direction_input;
+	c->direction_output = vx855gpio_direction_output;
+	c->get = vx855gpio_get;
+	c->set = vx855gpio_set;
+	c->dbg_show = NULL;
+	c->base = 0;
+	c->ngpio = NR_VX855_GP;
+	c->can_sleep = 0;
+	c->names = vx855gpio_names;
+}
+
+/* This platform device is ordinarily registered by the vx855 mfd driver */
+static __devinit int vx855gpio_probe(struct platform_device *pdev)
+{
+	struct resource *res_gpi;
+	struct resource *res_gpo;
+	struct vx855_gpio *vg;
+	int ret;
+
+	res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1);
+	if (!res_gpi || !res_gpo)
+		return -EBUSY;
+
+	vg = kzalloc(sizeof(*vg), GFP_KERNEL);
+	if (!vg)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, vg);
+
+	dev_info(&pdev->dev, "found VX855 GPIO controller\n");
+	vg->io_gpi = res_gpi->start;
+	vg->io_gpo = res_gpo->start;
+	spin_lock_init(&vg->lock);
+
+	/*
+	 * A single byte is used to control various GPIO ports on the VX855,
+	 * and in the case of the OLPC XO-1.5, some of those ports are used
+	 * for switches that are interpreted and exposed through ACPI. ACPI
+	 * will have reserved the region, so our own reservation will not
+	 * succeed. Ignore and continue.
+	 */
+
+	if (!request_region(res_gpi->start, resource_size(res_gpi),
+			MODULE_NAME "_gpi"))
+		dev_warn(&pdev->dev,
+			"GPI I/O resource busy, probably claimed by ACPI\n");
+	else
+		vg->gpi_reserved = true;
+
+	if (!request_region(res_gpo->start, resource_size(res_gpo),
+			MODULE_NAME "_gpo"))
+		dev_warn(&pdev->dev,
+			"GPO I/O resource busy, probably claimed by ACPI\n");
+	else
+		vg->gpo_reserved = true;
+
+	vx855gpio_gpio_setup(vg);
+
+	ret = gpiochip_add(&vg->gpio);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register GPIOs\n");
+		goto out_release;
+	}
+
+	return 0;
+
+out_release:
+	if (vg->gpi_reserved)
+		release_region(res_gpi->start, resource_size(res_gpi));
+	if (vg->gpo_reserved)
+		release_region(res_gpi->start, resource_size(res_gpo));
+	platform_set_drvdata(pdev, NULL);
+	kfree(vg);
+	return ret;
+}
+
+static int __devexit vx855gpio_remove(struct platform_device *pdev)
+{
+	struct vx855_gpio *vg = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	if (gpiochip_remove(&vg->gpio))
+		dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+
+	if (vg->gpi_reserved) {
+		res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+		release_region(res->start, resource_size(res));
+	}
+	if (vg->gpo_reserved) {
+		res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+		release_region(res->start, resource_size(res));
+	}
+
+	platform_set_drvdata(pdev, NULL);
+	kfree(vg);
+	return 0;
+}
+
+static struct platform_driver vx855gpio_driver = {
+	.driver = {
+		.name	= MODULE_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= vx855gpio_probe,
+	.remove		= __devexit_p(vx855gpio_remove),
+};
+
+static int vx855gpio_init(void)
+{
+	return platform_driver_register(&vx855gpio_driver);
+}
+module_init(vx855gpio_init);
+
+static void vx855gpio_exit(void)
+{
+	platform_driver_unregister(&vx855gpio_driver);
+}
+module_exit(vx855gpio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
+MODULE_DESCRIPTION("GPIO driver for the VIA VX855 chipset");
+MODULE_ALIAS("platform:vx855_gpio");

+ 1 - 0
drivers/gpio/wm8994-gpio.c

@@ -140,6 +140,7 @@ static struct gpio_chip template_chip = {
 	.get			= wm8994_gpio_get,
 	.get			= wm8994_gpio_get,
 	.direction_output	= wm8994_gpio_direction_out,
 	.direction_output	= wm8994_gpio_direction_out,
 	.set			= wm8994_gpio_set,
 	.set			= wm8994_gpio_set,
+	.to_irq			= wm8994_gpio_to_irq,
 	.dbg_show		= wm8994_gpio_dbg_show,
 	.dbg_show		= wm8994_gpio_dbg_show,
 	.can_sleep		= 1,
 	.can_sleep		= 1,
 };
 };

+ 54 - 18
drivers/input/misc/max8925_onkey.c

@@ -27,27 +27,37 @@
 #include <linux/mfd/max8925.h>
 #include <linux/mfd/max8925.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
+#define SW_INPUT		(1 << 7)	/* 0/1 -- up/down */
 #define HARDRESET_EN		(1 << 7)
 #define HARDRESET_EN		(1 << 7)
 #define PWREN_EN		(1 << 7)
 #define PWREN_EN		(1 << 7)
 
 
 struct max8925_onkey_info {
 struct max8925_onkey_info {
 	struct input_dev	*idev;
 	struct input_dev	*idev;
 	struct i2c_client	*i2c;
 	struct i2c_client	*i2c;
-	int			irq;
+	struct device		*dev;
+	int			irq[2];
 };
 };
 
 
 /*
 /*
- * MAX8925 gives us an interrupt when ONKEY is held for 3 seconds.
+ * MAX8925 gives us an interrupt when ONKEY is pressed or released.
  * max8925_set_bits() operates I2C bus and may sleep. So implement
  * max8925_set_bits() operates I2C bus and may sleep. So implement
  * it in thread IRQ handler.
  * it in thread IRQ handler.
  */
  */
 static irqreturn_t max8925_onkey_handler(int irq, void *data)
 static irqreturn_t max8925_onkey_handler(int irq, void *data)
 {
 {
 	struct max8925_onkey_info *info = data;
 	struct max8925_onkey_info *info = data;
-
-	input_report_key(info->idev, KEY_POWER, 1);
+	int ret, event;
+
+	ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
+	if (ret & SW_INPUT)
+		event = 1;
+	else
+		event = 0;
+	input_report_key(info->idev, KEY_POWER, event);
 	input_sync(info->idev);
 	input_sync(info->idev);
 
 
+	dev_dbg(info->dev, "onkey event:%d\n", event);
+
 	/* Enable hardreset to halt if system isn't shutdown on time */
 	/* Enable hardreset to halt if system isn't shutdown on time */
 	max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
 	max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
 			 HARDRESET_EN, HARDRESET_EN);
 			 HARDRESET_EN, HARDRESET_EN);
@@ -59,14 +69,42 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
 {
 {
 	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct max8925_onkey_info *info;
 	struct max8925_onkey_info *info;
-	int error;
+	int irq[2], error;
+
+	irq[0] = platform_get_irq(pdev, 0);
+	if (irq[0] < 0) {
+		dev_err(&pdev->dev, "No IRQ resource!\n");
+		return -EINVAL;
+	}
+	irq[1] = platform_get_irq(pdev, 1);
+	if (irq[1] < 0) {
+		dev_err(&pdev->dev, "No IRQ resource!\n");
+		return -EINVAL;
+	}
 
 
 	info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
 	info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
 	if (!info)
 	if (!info)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	info->i2c = chip->i2c;
 	info->i2c = chip->i2c;
-	info->irq = chip->irq_base + MAX8925_IRQ_GPM_SW_3SEC;
+	info->dev = &pdev->dev;
+	irq[0] += chip->irq_base;
+	irq[1] += chip->irq_base;
+
+	error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
+				     IRQF_ONESHOT, "onkey-down", info);
+	if (error < 0) {
+		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+			irq[0], error);
+		goto out;
+	}
+	error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
+				     IRQF_ONESHOT, "onkey-up", info);
+	if (error < 0) {
+		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+			irq[1], error);
+		goto out_irq;
+	}
 
 
 	info->idev = input_allocate_device();
 	info->idev = input_allocate_device();
 	if (!info->idev) {
 	if (!info->idev) {
@@ -79,32 +117,29 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
 	info->idev->phys = "max8925_on/input0";
 	info->idev->phys = "max8925_on/input0";
 	info->idev->id.bustype = BUS_I2C;
 	info->idev->id.bustype = BUS_I2C;
 	info->idev->dev.parent = &pdev->dev;
 	info->idev->dev.parent = &pdev->dev;
+	info->irq[0] = irq[0];
+	info->irq[1] = irq[1];
 	info->idev->evbit[0] = BIT_MASK(EV_KEY);
 	info->idev->evbit[0] = BIT_MASK(EV_KEY);
 	info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
 	info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
 
 
-	error = request_threaded_irq(info->irq, NULL, max8925_onkey_handler,
-				     IRQF_ONESHOT, "onkey", info);
-	if (error < 0) {
-		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
-			info->irq, error);
-		goto out_irq;
-	}
 
 
 	error = input_register_device(info->idev);
 	error = input_register_device(info->idev);
 	if (error) {
 	if (error) {
 		dev_err(chip->dev, "Can't register input device: %d\n", error);
 		dev_err(chip->dev, "Can't register input device: %d\n", error);
-		goto out;
+		goto out_reg;
 	}
 	}
 
 
 	platform_set_drvdata(pdev, info);
 	platform_set_drvdata(pdev, info);
 
 
 	return 0;
 	return 0;
 
 
-out:
-	free_irq(info->irq, info);
-out_irq:
+out_reg:
 	input_free_device(info->idev);
 	input_free_device(info->idev);
 out_input:
 out_input:
+	free_irq(info->irq[1], info);
+out_irq:
+	free_irq(info->irq[0], info);
+out:
 	kfree(info);
 	kfree(info);
 	return error;
 	return error;
 }
 }
@@ -113,7 +148,8 @@ static int __devexit max8925_onkey_remove(struct platform_device *pdev)
 {
 {
 	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
 	struct max8925_onkey_info *info = platform_get_drvdata(pdev);
 
 
-	free_irq(info->irq, info);
+	free_irq(info->irq[0], info);
+	free_irq(info->irq[1], info);
 	input_unregister_device(info->idev);
 	input_unregister_device(info->idev);
 	kfree(info);
 	kfree(info);
 
 

+ 26 - 93
drivers/leds/leds-88pm860x.c

@@ -24,26 +24,17 @@
 #define LED_CURRENT_MASK	(0x07 << 5)
 #define LED_CURRENT_MASK	(0x07 << 5)
 
 
 #define LED_BLINK_ON_MASK	(0x07)
 #define LED_BLINK_ON_MASK	(0x07)
-#define LED_BLINK_PERIOD_MASK	(0x0F << 3)
 #define LED_BLINK_MASK		(0x7F)
 #define LED_BLINK_MASK		(0x7F)
 
 
 #define LED_BLINK_ON(x)		((x & 0x7) * 66 + 66)
 #define LED_BLINK_ON(x)		((x & 0x7) * 66 + 66)
-#define LED_BLINK_PERIOD(x)	((x & 0xF) * 530 + 930)
 #define LED_BLINK_ON_MIN	LED_BLINK_ON(0)
 #define LED_BLINK_ON_MIN	LED_BLINK_ON(0)
 #define LED_BLINK_ON_MAX	LED_BLINK_ON(0x7)
 #define LED_BLINK_ON_MAX	LED_BLINK_ON(0x7)
-#define LED_BLINK_PERIOD_MIN	LED_BLINK_PERIOD(0)
-#define LED_BLINK_PERIOD_MAX	LED_BLINK_PERIOD(0xE)
+#define LED_ON_CONTINUOUS	(0x0F << 3)
 #define LED_TO_ON(x)		((x - 66) / 66)
 #define LED_TO_ON(x)		((x - 66) / 66)
-#define LED_TO_PERIOD(x)	((x - 930) / 530)
 
 
 #define LED1_BLINK_EN		(1 << 1)
 #define LED1_BLINK_EN		(1 << 1)
 #define LED2_BLINK_EN		(1 << 2)
 #define LED2_BLINK_EN		(1 << 2)
 
 
-enum {
-	SET_BRIGHTNESS,
-	SET_BLINK,
-};
-
 struct pm860x_led {
 struct pm860x_led {
 	struct led_classdev cdev;
 	struct led_classdev cdev;
 	struct i2c_client *i2c;
 	struct i2c_client *i2c;
@@ -54,8 +45,6 @@ struct pm860x_led {
 
 
 	int port;
 	int port;
 	int iset;
 	int iset;
-	int command;
-	int offset;
 	unsigned char brightness;
 	unsigned char brightness;
 	unsigned char current_brightness;
 	unsigned char current_brightness;
 
 
@@ -95,10 +84,12 @@ static inline int __blink_off(int port)
 	case PM8606_LED1_GREEN:
 	case PM8606_LED1_GREEN:
 	case PM8606_LED1_BLUE:
 	case PM8606_LED1_BLUE:
 		ret = PM8606_RGB1A;
 		ret = PM8606_RGB1A;
+		break;
 	case PM8606_LED2_RED:
 	case PM8606_LED2_RED:
 	case PM8606_LED2_GREEN:
 	case PM8606_LED2_GREEN:
 	case PM8606_LED2_BLUE:
 	case PM8606_LED2_BLUE:
 		ret = PM8606_RGB2A;
 		ret = PM8606_RGB2A;
+		break;
 	}
 	}
 	return ret;
 	return ret;
 }
 }
@@ -122,60 +113,35 @@ static inline int __blink_ctl_mask(int port)
 	return ret;
 	return ret;
 }
 }
 
 
-static int __led_set(struct pm860x_led *led, int command)
+static void pm860x_led_work(struct work_struct *work)
 {
 {
-	struct pm860x_chip *chip = led->chip;
-	int mask, ret;
 
 
+	struct pm860x_led *led;
+	struct pm860x_chip *chip;
+	int mask;
+
+	led = container_of(work, struct pm860x_led, work);
+	chip = led->chip;
 	mutex_lock(&led->lock);
 	mutex_lock(&led->lock);
-	switch (command) {
-	case SET_BRIGHTNESS:
-		if ((led->current_brightness == 0) && led->brightness) {
-			if (led->iset) {
-				ret = pm860x_set_bits(led->i2c, led->offset,
-						LED_CURRENT_MASK, led->iset);
-				if (ret < 0)
-					goto out;
-			}
-		} else if (led->brightness == 0) {
-			ret = pm860x_set_bits(led->i2c, led->offset,
-						LED_CURRENT_MASK, 0);
-			if (ret < 0)
-				goto out;
+	if ((led->current_brightness == 0) && led->brightness) {
+		if (led->iset) {
+			pm860x_set_bits(led->i2c, __led_off(led->port),
+					LED_CURRENT_MASK, led->iset);
 		}
 		}
-		ret = pm860x_set_bits(led->i2c, led->offset, LED_PWM_MASK,
-					led->brightness);
-		if (ret < 0)
-			goto out;
-		led->current_brightness = led->brightness;
-		dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
-			led->offset, led->brightness);
-		break;
-	case SET_BLINK:
-		ret = pm860x_set_bits(led->i2c, led->offset,
-				LED_BLINK_MASK, led->blink_data);
-		if (ret < 0)
-			goto out;
-
 		mask = __blink_ctl_mask(led->port);
 		mask = __blink_ctl_mask(led->port);
-		ret = pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask);
-		if (ret < 0)
-			goto out;
-		dev_dbg(chip->dev, "LED blink delay on:%dms, delay off:%dms\n",
-			led->blink_on, led->blink_off);
-		break;
+		pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask);
+	} else if (led->brightness == 0) {
+		pm860x_set_bits(led->i2c, __led_off(led->port),
+				LED_CURRENT_MASK, 0);
+		mask = __blink_ctl_mask(led->port);
+		pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
 	}
 	}
-out:
+	pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK,
+			led->brightness);
+	led->current_brightness = led->brightness;
+	dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
+		__led_off(led->port), led->brightness);
 	mutex_unlock(&led->lock);
 	mutex_unlock(&led->lock);
-	return 0;
-}
-
-static void pm860x_led_work(struct work_struct *work)
-{
-	struct pm860x_led *led;
-
-	led = container_of(work, struct pm860x_led, work);
-	__led_set(led, led->command);
 }
 }
 
 
 static void pm860x_led_set(struct led_classdev *cdev,
 static void pm860x_led_set(struct led_classdev *cdev,
@@ -183,42 +149,10 @@ static void pm860x_led_set(struct led_classdev *cdev,
 {
 {
 	struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
 	struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
 
 
-	data->offset = __led_off(data->port);
 	data->brightness = value >> 3;
 	data->brightness = value >> 3;
-	data->command = SET_BRIGHTNESS;
 	schedule_work(&data->work);
 	schedule_work(&data->work);
 }
 }
 
 
-static int pm860x_led_blink(struct led_classdev *cdev,
-			    unsigned long *delay_on,
-			    unsigned long *delay_off)
-{
-	struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
-	int period, on;
-
-	on = *delay_on;
-	if ((on < LED_BLINK_ON_MIN) || (on > LED_BLINK_ON_MAX))
-		return -EINVAL;
-
-	on = LED_TO_ON(on);
-	on = LED_BLINK_ON(on);
-
-	period = on + *delay_off;
-	if ((period < LED_BLINK_PERIOD_MIN) || (period > LED_BLINK_PERIOD_MAX))
-		return -EINVAL;
-	period = LED_TO_PERIOD(period);
-	period = LED_BLINK_PERIOD(period);
-
-	data->offset = __blink_off(data->port);
-	data->blink_on = on;
-	data->blink_off = period - data->blink_on;
-	data->blink_data = (period << 3) | data->blink_on;
-	data->command = SET_BLINK;
-	schedule_work(&data->work);
-
-	return 0;
-}
-
 static int __check_device(struct pm860x_led_pdata *pdata, char *name)
 static int __check_device(struct pm860x_led_pdata *pdata, char *name)
 {
 {
 	struct pm860x_led_pdata *p = pdata;
 	struct pm860x_led_pdata *p = pdata;
@@ -257,7 +191,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
 		pm860x_pdata = pdev->dev.parent->platform_data;
 		pm860x_pdata = pdev->dev.parent->platform_data;
 		pdata = pm860x_pdata->led;
 		pdata = pm860x_pdata->led;
 	} else {
 	} else {
-		dev_err(&pdev->dev, "missing platform data\n");
+		dev_err(&pdev->dev, "No platform data!\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -279,7 +213,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
 	data->current_brightness = 0;
 	data->current_brightness = 0;
 	data->cdev.name = data->name;
 	data->cdev.name = data->name;
 	data->cdev.brightness_set = pm860x_led_set;
 	data->cdev.brightness_set = pm860x_led_set;
-	data->cdev.blink_set = pm860x_led_blink;
 	mutex_init(&data->lock);
 	mutex_init(&data->lock);
 	INIT_WORK(&data->work, pm860x_led_work);
 	INIT_WORK(&data->work, pm860x_led_work);
 
 

+ 49 - 2
drivers/mfd/88pm860x-core.c

@@ -158,6 +158,43 @@ static struct mfd_cell onkey_devs[] = {
 	},
 	},
 };
 };
 
 
+static struct resource codec_resources[] = {
+	{
+		/* Headset microphone insertion or removal */
+		.name		= "micin",
+		.start		= PM8607_IRQ_MICIN,
+		.end		= PM8607_IRQ_MICIN,
+		.flags		= IORESOURCE_IRQ,
+	}, {
+		/* Hook-switch press or release */
+		.name		= "hook",
+		.start		= PM8607_IRQ_HOOK,
+		.end		= PM8607_IRQ_HOOK,
+		.flags		= IORESOURCE_IRQ,
+	}, {
+		/* Headset insertion or removal */
+		.name		= "headset",
+		.start		= PM8607_IRQ_HEADSET,
+		.end		= PM8607_IRQ_HEADSET,
+		.flags		= IORESOURCE_IRQ,
+	}, {
+		/* Audio short */
+		.name		= "audio-short",
+		.start		= PM8607_IRQ_AUDIO_SHORT,
+		.end		= PM8607_IRQ_AUDIO_SHORT,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell codec_devs[] = {
+	{
+		.name		= "88pm860x-codec",
+		.num_resources	= ARRAY_SIZE(codec_resources),
+		.resources	= &codec_resources[0],
+		.id		= -1,
+	},
+};
+
 static struct resource regulator_resources[] = {
 static struct resource regulator_resources[] = {
 	PM8607_REG_RESOURCE(BUCK1, BUCK1),
 	PM8607_REG_RESOURCE(BUCK1, BUCK1),
 	PM8607_REG_RESOURCE(BUCK2, BUCK2),
 	PM8607_REG_RESOURCE(BUCK2, BUCK2),
@@ -608,10 +645,13 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
 		goto out;
 		goto out;
 	}
 	}
-	if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION)
+	switch (ret & PM8607_VERSION_MASK) {
+	case 0x40:
+	case 0x50:
 		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
 		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
 			 ret);
 			 ret);
-	else {
+		break;
+	default:
 		dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
 		dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
 			"Chip ID: %02x\n", ret);
 			"Chip ID: %02x\n", ret);
 		goto out;
 		goto out;
@@ -687,6 +727,13 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
 		goto out_dev;
 		goto out_dev;
 	}
 	}
 
 
+	ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
+			      ARRAY_SIZE(codec_devs),
+			      &codec_resources[0], 0);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to add codec subdev\n");
+		goto out_dev;
+	}
 	return;
 	return;
 out_dev:
 out_dev:
 	mfd_remove_devices(chip->dev);
 	mfd_remove_devices(chip->dev);

+ 71 - 20
drivers/mfd/Kconfig

@@ -75,7 +75,7 @@ config MFD_DAVINCI_VOICECODEC
 
 
 config MFD_DM355EVM_MSP
 config MFD_DM355EVM_MSP
 	bool "DaVinci DM355 EVM microcontroller"
 	bool "DaVinci DM355 EVM microcontroller"
-	depends on I2C && MACH_DAVINCI_DM355_EVM
+	depends on I2C=y && MACH_DAVINCI_DM355_EVM
 	help
 	help
 	  This driver supports the MSP430 microcontroller used on these
 	  This driver supports the MSP430 microcontroller used on these
 	  boards.  MSP430 firmware manages resets and power sequencing,
 	  boards.  MSP430 firmware manages resets and power sequencing,
@@ -294,14 +294,15 @@ config MFD_MAX8925
 	  to use the functionality of the device.
 	  to use the functionality of the device.
 
 
 config MFD_MAX8998
 config MFD_MAX8998
-	bool "Maxim Semiconductor MAX8998 PMIC Support"
-	depends on I2C=y
+	bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
+	depends on I2C=y && GENERIC_HARDIRQS
 	select MFD_CORE
 	select MFD_CORE
 	help
 	help
-	  Say yes here to support for Maxim Semiconductor MAX8998. This is
-	  a Power Management IC. This driver provies common support for
-	  accessing the device, additional drivers must be enabled in order
-	  to use the functionality of the device.
+	  Say yes here to support for Maxim Semiconductor MAX8998 and
+	  National Semiconductor LP3974. This is a Power Management IC.
+	  This driver provies common support for accessing the device,
+	  additional drivers must be enabled in order to use the functionality
+	  of the device.
 
 
 config MFD_WM8400
 config MFD_WM8400
 	tristate "Support Wolfson Microelectronics WM8400"
 	tristate "Support Wolfson Microelectronics WM8400"
@@ -314,14 +315,30 @@ config MFD_WM8400
 	  the functionality of the device.
 	  the functionality of the device.
 
 
 config MFD_WM831X
 config MFD_WM831X
-	bool "Support Wolfson Microelectronics WM831x/2x PMICs"
+	bool
+	depends on GENERIC_HARDIRQS
+
+config MFD_WM831X_I2C
+	bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C"
 	select MFD_CORE
 	select MFD_CORE
+	select MFD_WM831X
 	depends on I2C=y && GENERIC_HARDIRQS
 	depends on I2C=y && GENERIC_HARDIRQS
 	help
 	help
-	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
-	  This driver provides common support for accessing the device,
-	  additional drivers must be enabled in order to use the
-	  functionality of the device.
+	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
+	  when controlled using I2C.  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_WM831X_SPI
+	bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI"
+	select MFD_CORE
+	select MFD_WM831X
+	depends on SPI_MASTER && GENERIC_HARDIRQS
+	help
+	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
+	  when controlled using SPI.  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_WM8350
 config MFD_WM8350
 	bool
 	bool
@@ -408,11 +425,16 @@ config MFD_PCF50633
 	  so that function-specific drivers can bind to them.
 	  so that function-specific drivers can bind to them.
 
 
 config MFD_MC13783
 config MFD_MC13783
-	tristate "Support Freescale MC13783"
+	tristate
+
+config MFD_MC13XXX
+	tristate "Support Freescale MC13783 and MC13892"
 	depends on SPI_MASTER
 	depends on SPI_MASTER
 	select MFD_CORE
 	select MFD_CORE
+	select MFD_MC13783
 	help
 	help
-	  Support for the Freescale (Atlas) MC13783 PMIC and audio CODEC.
+	  Support for the Freescale (Atlas) PMIC and audio CODECs
+	  MC13783 and MC13892.
 	  This driver provides common support for accessing  the device,
 	  This driver provides common support for accessing  the device,
 	  additional drivers must be enabled in order to use the
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 	  functionality of the device.
@@ -433,7 +455,7 @@ config PCF50633_GPIO
 
 
 config ABX500_CORE
 config ABX500_CORE
 	bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
 	bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
-	default y if ARCH_U300
+	default y if ARCH_U300 || ARCH_U8500
 	help
 	help
 	  Say yes here if you have the ABX500 Mixed Signal IC family
 	  Say yes here if you have the ABX500 Mixed Signal IC family
 	  chips. This core driver expose register access functions.
 	  chips. This core driver expose register access functions.
@@ -444,6 +466,7 @@ config ABX500_CORE
 config AB3100_CORE
 config AB3100_CORE
 	bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
 	bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
 	depends on I2C=y && ABX500_CORE
 	depends on I2C=y && ABX500_CORE
+	select MFD_CORE
 	default y if ARCH_U300
 	default y if ARCH_U300
 	help
 	help
 	  Select this to enable the AB3100 Mixed Signal IC core
 	  Select this to enable the AB3100 Mixed Signal IC core
@@ -473,14 +496,33 @@ config EZX_PCAP
 
 
 config AB8500_CORE
 config AB8500_CORE
 	bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
 	bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
-	depends on SPI=y && GENERIC_HARDIRQS
+	depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500
 	select MFD_CORE
 	select MFD_CORE
 	help
 	help
 	  Select this option to enable access to AB8500 power management
 	  Select this option to enable access to AB8500 power management
-	  chip. This connects to U8500 on the SSP/SPI bus and exports
-	  read/write functions for the devices to get access to this chip.
+	  chip. This connects to U8500 either on the SSP/SPI bus
+	  or the I2C bus via PRCMU. It also adds the irq_chip
+	  parts for handling the Mixed Signal chip events.
 	  This chip embeds various other multimedia funtionalities as well.
 	  This chip embeds various other multimedia funtionalities as well.
 
 
+config AB8500_I2C_CORE
+	bool "AB8500 register access via PRCMU I2C"
+	depends on AB8500_CORE && UX500_SOC_DB8500
+	default y
+	help
+	  This enables register access to the AB8500 chip via PRCMU I2C.
+	  The AB8500 chip can be accessed via SPI or I2C. On DB8500 hardware
+	  the I2C bus is connected to the Power Reset
+	  and Mangagement Unit, PRCMU.
+
+config AB8500_DEBUG
+       bool "Enable debug info via debugfs"
+       depends on AB8500_CORE && DEBUG_FS
+       default y if DEBUG_FS
+       help
+         Select this option if you want debug information using the debug
+         filesystem, debugfs.
+
 config AB3550_CORE
 config AB3550_CORE
         bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions"
         bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions"
 	select MFD_CORE
 	select MFD_CORE
@@ -542,8 +584,8 @@ config MFD_JZ4740_ADC
 	  This driver is necessary for jz4740-battery and jz4740-hwmon driver.
 	  This driver is necessary for jz4740-battery and jz4740-hwmon driver.
 
 
 config MFD_TPS6586X
 config MFD_TPS6586X
-	tristate "TPS6586x Power Management chips"
-	depends on I2C && GPIOLIB
+	bool "TPS6586x Power Management chips"
+	depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
 	select MFD_CORE
 	select MFD_CORE
 	help
 	help
 	  If you say yes here you get support for the TPS6586X series of
 	  If you say yes here you get support for the TPS6586X series of
@@ -555,6 +597,15 @@ config MFD_TPS6586X
 	  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 tps6586x.
 	  will be called tps6586x.
 
 
+config MFD_VX855
+	tristate "Support for VIA VX855/VX875 integrated south bridge"
+	depends on PCI
+	select MFD_CORE
+	help
+	  Say yes here to enable support for various functions of the
+	  VIA VX855/VX875 south bridge. You will need to enable the vx855_spi
+	  and/or vx855_gpio drivers for this to do anything useful.
+
 endif # MFD_SUPPORT
 endif # MFD_SUPPORT
 
 
 menu "Multimedia Capabilities Port drivers"
 menu "Multimedia Capabilities Port drivers"

+ 7 - 2
drivers/mfd/Makefile

@@ -24,6 +24,8 @@ obj-$(CONFIG_MFD_TC6393XB)	+= tc6393xb.o tmio_core.o
 obj-$(CONFIG_MFD_WM8400)	+= wm8400-core.o
 obj-$(CONFIG_MFD_WM8400)	+= wm8400-core.o
 wm831x-objs			:= wm831x-core.o wm831x-irq.o wm831x-otp.o
 wm831x-objs			:= wm831x-core.o wm831x-irq.o wm831x-otp.o
 obj-$(CONFIG_MFD_WM831X)	+= wm831x.o
 obj-$(CONFIG_MFD_WM831X)	+= wm831x.o
+obj-$(CONFIG_MFD_WM831X_I2C)	+= wm831x-i2c.o
+obj-$(CONFIG_MFD_WM831X_SPI)	+= wm831x-spi.o
 wm8350-objs			:= wm8350-core.o wm8350-regmap.o wm8350-gpio.o
 wm8350-objs			:= wm8350-core.o wm8350-regmap.o wm8350-gpio.o
 wm8350-objs			+= wm8350-irq.o
 wm8350-objs			+= wm8350-irq.o
 obj-$(CONFIG_MFD_WM8350)	+= wm8350.o
 obj-$(CONFIG_MFD_WM8350)	+= wm8350.o
@@ -39,7 +41,7 @@ obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 obj-$(CONFIG_TWL4030_CODEC)	+= twl4030-codec.o
 obj-$(CONFIG_TWL4030_CODEC)	+= twl4030-codec.o
 obj-$(CONFIG_TWL6030_PWM)	+= twl6030-pwm.o
 obj-$(CONFIG_TWL6030_PWM)	+= twl6030-pwm.o
 
 
-obj-$(CONFIG_MFD_MC13783)	+= mc13783-core.o
+obj-$(CONFIG_MFD_MC13XXX)	+= mc13xxx-core.o
 
 
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 
@@ -58,7 +60,7 @@ obj-$(CONFIG_UCB1400_CORE)	+= ucb1400_core.o
 obj-$(CONFIG_PMIC_DA903X)	+= da903x.o
 obj-$(CONFIG_PMIC_DA903X)	+= da903x.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
-obj-$(CONFIG_MFD_MAX8998)	+= max8998.o
+obj-$(CONFIG_MFD_MAX8998)	+= max8998.o max8998-irq.o
 
 
 pcf50633-objs			:= pcf50633-core.o pcf50633-irq.o
 pcf50633-objs			:= pcf50633-core.o pcf50633-irq.o
 obj-$(CONFIG_MFD_PCF50633)	+= pcf50633.o
 obj-$(CONFIG_MFD_PCF50633)	+= pcf50633.o
@@ -69,6 +71,8 @@ obj-$(CONFIG_AB3100_CORE)	+= ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o
 obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o
 obj-$(CONFIG_AB3550_CORE)	+= ab3550-core.o
 obj-$(CONFIG_AB3550_CORE)	+= ab3550-core.o
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-spi.o
 obj-$(CONFIG_AB8500_CORE)	+= ab8500-core.o ab8500-spi.o
+obj-$(CONFIG_AB8500_I2C_CORE)	+= ab8500-i2c.o
+obj-$(CONFIG_AB8500_DEBUG)	+= ab8500-debugfs.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_PMIC_ADP5520)	+= adp5520.o
 obj-$(CONFIG_PMIC_ADP5520)	+= adp5520.o
 obj-$(CONFIG_LPC_SCH)		+= lpc_sch.o
 obj-$(CONFIG_LPC_SCH)		+= lpc_sch.o
@@ -76,3 +80,4 @@ obj-$(CONFIG_MFD_RDC321X)	+= rdc321x-southbridge.o
 obj-$(CONFIG_MFD_JANZ_CMODIO)	+= janz-cmodio.o
 obj-$(CONFIG_MFD_JANZ_CMODIO)	+= janz-cmodio.o
 obj-$(CONFIG_MFD_JZ4740_ADC)	+= jz4740-adc.o
 obj-$(CONFIG_MFD_JZ4740_ADC)	+= jz4740-adc.o
 obj-$(CONFIG_MFD_TPS6586X)	+= tps6586x.o
 obj-$(CONFIG_MFD_TPS6586X)	+= tps6586x.o
+obj-$(CONFIG_MFD_VX855)		+= vx855.o

+ 75 - 68
drivers/mfd/ab3100-core.c

@@ -19,6 +19,7 @@
 #include <linux/debugfs.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500.h>
 
 
 /* These are the only registers inside AB3100 used in this main file */
 /* These are the only registers inside AB3100 used in this main file */
@@ -146,7 +147,7 @@ static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100,
 }
 }
 
 
 static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
 static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
-	u8 reg, u8 *regval)
+					     u8 reg, u8 *regval)
 {
 {
 	int err;
 	int err;
 
 
@@ -202,7 +203,7 @@ static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
 }
 }
 
 
 static int get_register_interruptible(struct device *dev, u8 bank, u8 reg,
 static int get_register_interruptible(struct device *dev, u8 bank, u8 reg,
-	u8 *value)
+				      u8 *value)
 {
 {
 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
 
 
@@ -666,7 +667,7 @@ struct ab3100_init_setting {
 	u8 setting;
 	u8 setting;
 };
 };
 
 
-static const struct ab3100_init_setting __initconst
+static const struct ab3100_init_setting __devinitconst
 ab3100_init_settings[] = {
 ab3100_init_settings[] = {
 	{
 	{
 		.abreg = AB3100_MCA,
 		.abreg = AB3100_MCA,
@@ -713,7 +714,7 @@ ab3100_init_settings[] = {
 	},
 	},
 };
 };
 
 
-static int __init ab3100_setup(struct ab3100 *ab3100)
+static int __devinit ab3100_setup(struct ab3100 *ab3100)
 {
 {
 	int err = 0;
 	int err = 0;
 	int i;
 	int i;
@@ -743,52 +744,64 @@ static int __init ab3100_setup(struct ab3100 *ab3100)
 	return err;
 	return err;
 }
 }
 
 
-/*
- * Here we define all the platform devices that appear
- * as children of the AB3100. These are regular platform
- * devices with the IORESOURCE_IO .start and .end set
- * to correspond to the internal AB3100 register range
- * mapping to the corresponding subdevice.
- */
-
-#define AB3100_DEVICE(devname, devid)				\
-static struct platform_device ab3100_##devname##_device = {	\
-	.name		= devid,				\
-	.id		= -1,					\
-}
-
-/* This lists all the subdevices */
-AB3100_DEVICE(dac, "ab3100-dac");
-AB3100_DEVICE(leds, "ab3100-leds");
-AB3100_DEVICE(power, "ab3100-power");
-AB3100_DEVICE(regulators, "ab3100-regulators");
-AB3100_DEVICE(sim, "ab3100-sim");
-AB3100_DEVICE(uart, "ab3100-uart");
-AB3100_DEVICE(rtc, "ab3100-rtc");
-AB3100_DEVICE(charger, "ab3100-charger");
-AB3100_DEVICE(boost, "ab3100-boost");
-AB3100_DEVICE(adc, "ab3100-adc");
-AB3100_DEVICE(fuelgauge, "ab3100-fuelgauge");
-AB3100_DEVICE(vibrator, "ab3100-vibrator");
-AB3100_DEVICE(otp, "ab3100-otp");
-AB3100_DEVICE(codec, "ab3100-codec");
-
-static struct platform_device *
-ab3100_platform_devs[] = {
-	&ab3100_dac_device,
-	&ab3100_leds_device,
-	&ab3100_power_device,
-	&ab3100_regulators_device,
-	&ab3100_sim_device,
-	&ab3100_uart_device,
-	&ab3100_rtc_device,
-	&ab3100_charger_device,
-	&ab3100_boost_device,
-	&ab3100_adc_device,
-	&ab3100_fuelgauge_device,
-	&ab3100_vibrator_device,
-	&ab3100_otp_device,
-	&ab3100_codec_device,
+/* The subdevices of the AB3100 */
+static struct mfd_cell ab3100_devs[] = {
+	{
+		.name = "ab3100-dac",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-leds",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-power",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-regulators",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-sim",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-uart",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-rtc",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-charger",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-boost",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-adc",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-fuelgauge",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-vibrator",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-otp",
+		.id = -1,
+	},
+	{
+		.name = "ab3100-codec",
+		.id = -1,
+	},
 };
 };
 
 
 struct ab_family_id {
 struct ab_family_id {
@@ -796,7 +809,7 @@ struct ab_family_id {
 	char	*name;
 	char	*name;
 };
 };
 
 
-static const struct ab_family_id ids[] __initdata = {
+static const struct ab_family_id ids[] __devinitdata = {
 	/* AB3100 */
 	/* AB3100 */
 	{
 	{
 		.id = 0xc0,
 		.id = 0xc0,
@@ -850,8 +863,8 @@ static const struct ab_family_id ids[] __initdata = {
 	},
 	},
 };
 };
 
 
-static int __init ab3100_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
+static int __devinit ab3100_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
 {
 {
 	struct ab3100 *ab3100;
 	struct ab3100 *ab3100;
 	struct ab3100_platform_data *ab3100_plf_data =
 	struct ab3100_platform_data *ab3100_plf_data =
@@ -935,18 +948,14 @@ static int __init ab3100_probe(struct i2c_client *client,
 	if (err)
 	if (err)
 		goto exit_no_ops;
 		goto exit_no_ops;
 
 
-	/* Set parent and a pointer back to the container in device data */
-	for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) {
-		ab3100_platform_devs[i]->dev.parent =
-			&client->dev;
-		ab3100_platform_devs[i]->dev.platform_data =
-			ab3100_plf_data;
-		platform_set_drvdata(ab3100_platform_devs[i], ab3100);
+	/* Set up and register the platform devices. */
+	for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
+		ab3100_devs[i].platform_data = ab3100_plf_data;
+		ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data);
 	}
 	}
 
 
-	/* Register the platform devices */
-	platform_add_devices(ab3100_platform_devs,
-			     ARRAY_SIZE(ab3100_platform_devs));
+	err = mfd_add_devices(&client->dev, 0, ab3100_devs,
+		ARRAY_SIZE(ab3100_devs), NULL, 0);
 
 
 	ab3100_setup_debugfs(ab3100);
 	ab3100_setup_debugfs(ab3100);
 
 
@@ -962,14 +971,12 @@ static int __init ab3100_probe(struct i2c_client *client,
 	return err;
 	return err;
 }
 }
 
 
-static int __exit ab3100_remove(struct i2c_client *client)
+static int __devexit ab3100_remove(struct i2c_client *client)
 {
 {
 	struct ab3100 *ab3100 = i2c_get_clientdata(client);
 	struct ab3100 *ab3100 = i2c_get_clientdata(client);
-	int i;
 
 
 	/* Unregister subdevices */
 	/* Unregister subdevices */
-	for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++)
-		platform_device_unregister(ab3100_platform_devs[i]);
+	mfd_remove_devices(&client->dev);
 
 
 	ab3100_remove_debugfs();
 	ab3100_remove_debugfs();
 	i2c_unregister_device(ab3100->testreg_client);
 	i2c_unregister_device(ab3100->testreg_client);
@@ -996,7 +1003,7 @@ static struct i2c_driver ab3100_driver = {
 	},
 	},
 	.id_table	= ab3100_id,
 	.id_table	= ab3100_id,
 	.probe		= ab3100_probe,
 	.probe		= ab3100_probe,
-	.remove		= __exit_p(ab3100_remove),
+	.remove		= __devexit_p(ab3100_remove),
 };
 };
 
 
 static int __init ab3100_i2c_init(void)
 static int __init ab3100_i2c_init(void)

+ 183 - 116
drivers/mfd/ab8500-core.c

@@ -4,6 +4,7 @@
  * License Terms: GNU General Public License v2
  * License Terms: GNU General Public License v2
  * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
  * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
  * Author: Rabin Vincent <rabin.vincent@stericsson.com>
  * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ * Changes: Mattias Wallin <mattias.wallin@stericsson.com>
  */
  */
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -15,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/core.h>
+#include <linux/mfd/abx500.h>
 #include <linux/mfd/ab8500.h>
 #include <linux/mfd/ab8500.h>
 #include <linux/regulator/ab8500.h>
 #include <linux/regulator/ab8500.h>
 
 
@@ -22,71 +24,71 @@
  * Interrupt register offsets
  * Interrupt register offsets
  * Bank : 0x0E
  * Bank : 0x0E
  */
  */
-#define AB8500_IT_SOURCE1_REG		0x0E00
-#define AB8500_IT_SOURCE2_REG		0x0E01
-#define AB8500_IT_SOURCE3_REG		0x0E02
-#define AB8500_IT_SOURCE4_REG		0x0E03
-#define AB8500_IT_SOURCE5_REG		0x0E04
-#define AB8500_IT_SOURCE6_REG		0x0E05
-#define AB8500_IT_SOURCE7_REG		0x0E06
-#define AB8500_IT_SOURCE8_REG		0x0E07
-#define AB8500_IT_SOURCE19_REG		0x0E12
-#define AB8500_IT_SOURCE20_REG		0x0E13
-#define AB8500_IT_SOURCE21_REG		0x0E14
-#define AB8500_IT_SOURCE22_REG		0x0E15
-#define AB8500_IT_SOURCE23_REG		0x0E16
-#define AB8500_IT_SOURCE24_REG		0x0E17
+#define AB8500_IT_SOURCE1_REG		0x00
+#define AB8500_IT_SOURCE2_REG		0x01
+#define AB8500_IT_SOURCE3_REG		0x02
+#define AB8500_IT_SOURCE4_REG		0x03
+#define AB8500_IT_SOURCE5_REG		0x04
+#define AB8500_IT_SOURCE6_REG		0x05
+#define AB8500_IT_SOURCE7_REG		0x06
+#define AB8500_IT_SOURCE8_REG		0x07
+#define AB8500_IT_SOURCE19_REG		0x12
+#define AB8500_IT_SOURCE20_REG		0x13
+#define AB8500_IT_SOURCE21_REG		0x14
+#define AB8500_IT_SOURCE22_REG		0x15
+#define AB8500_IT_SOURCE23_REG		0x16
+#define AB8500_IT_SOURCE24_REG		0x17
 
 
 /*
 /*
  * latch registers
  * latch registers
  */
  */
-#define AB8500_IT_LATCH1_REG		0x0E20
-#define AB8500_IT_LATCH2_REG		0x0E21
-#define AB8500_IT_LATCH3_REG		0x0E22
-#define AB8500_IT_LATCH4_REG		0x0E23
-#define AB8500_IT_LATCH5_REG		0x0E24
-#define AB8500_IT_LATCH6_REG		0x0E25
-#define AB8500_IT_LATCH7_REG		0x0E26
-#define AB8500_IT_LATCH8_REG		0x0E27
-#define AB8500_IT_LATCH9_REG		0x0E28
-#define AB8500_IT_LATCH10_REG		0x0E29
-#define AB8500_IT_LATCH19_REG		0x0E32
-#define AB8500_IT_LATCH20_REG		0x0E33
-#define AB8500_IT_LATCH21_REG		0x0E34
-#define AB8500_IT_LATCH22_REG		0x0E35
-#define AB8500_IT_LATCH23_REG		0x0E36
-#define AB8500_IT_LATCH24_REG		0x0E37
+#define AB8500_IT_LATCH1_REG		0x20
+#define AB8500_IT_LATCH2_REG		0x21
+#define AB8500_IT_LATCH3_REG		0x22
+#define AB8500_IT_LATCH4_REG		0x23
+#define AB8500_IT_LATCH5_REG		0x24
+#define AB8500_IT_LATCH6_REG		0x25
+#define AB8500_IT_LATCH7_REG		0x26
+#define AB8500_IT_LATCH8_REG		0x27
+#define AB8500_IT_LATCH9_REG		0x28
+#define AB8500_IT_LATCH10_REG		0x29
+#define AB8500_IT_LATCH19_REG		0x32
+#define AB8500_IT_LATCH20_REG		0x33
+#define AB8500_IT_LATCH21_REG		0x34
+#define AB8500_IT_LATCH22_REG		0x35
+#define AB8500_IT_LATCH23_REG		0x36
+#define AB8500_IT_LATCH24_REG		0x37
 
 
 /*
 /*
  * mask registers
  * mask registers
  */
  */
 
 
-#define AB8500_IT_MASK1_REG		0x0E40
-#define AB8500_IT_MASK2_REG		0x0E41
-#define AB8500_IT_MASK3_REG		0x0E42
-#define AB8500_IT_MASK4_REG		0x0E43
-#define AB8500_IT_MASK5_REG		0x0E44
-#define AB8500_IT_MASK6_REG		0x0E45
-#define AB8500_IT_MASK7_REG		0x0E46
-#define AB8500_IT_MASK8_REG		0x0E47
-#define AB8500_IT_MASK9_REG		0x0E48
-#define AB8500_IT_MASK10_REG		0x0E49
-#define AB8500_IT_MASK11_REG		0x0E4A
-#define AB8500_IT_MASK12_REG		0x0E4B
-#define AB8500_IT_MASK13_REG		0x0E4C
-#define AB8500_IT_MASK14_REG		0x0E4D
-#define AB8500_IT_MASK15_REG		0x0E4E
-#define AB8500_IT_MASK16_REG		0x0E4F
-#define AB8500_IT_MASK17_REG		0x0E50
-#define AB8500_IT_MASK18_REG		0x0E51
-#define AB8500_IT_MASK19_REG		0x0E52
-#define AB8500_IT_MASK20_REG		0x0E53
-#define AB8500_IT_MASK21_REG		0x0E54
-#define AB8500_IT_MASK22_REG		0x0E55
-#define AB8500_IT_MASK23_REG		0x0E56
-#define AB8500_IT_MASK24_REG		0x0E57
-
-#define AB8500_REV_REG			0x1080
+#define AB8500_IT_MASK1_REG		0x40
+#define AB8500_IT_MASK2_REG		0x41
+#define AB8500_IT_MASK3_REG		0x42
+#define AB8500_IT_MASK4_REG		0x43
+#define AB8500_IT_MASK5_REG		0x44
+#define AB8500_IT_MASK6_REG		0x45
+#define AB8500_IT_MASK7_REG		0x46
+#define AB8500_IT_MASK8_REG		0x47
+#define AB8500_IT_MASK9_REG		0x48
+#define AB8500_IT_MASK10_REG		0x49
+#define AB8500_IT_MASK11_REG		0x4A
+#define AB8500_IT_MASK12_REG		0x4B
+#define AB8500_IT_MASK13_REG		0x4C
+#define AB8500_IT_MASK14_REG		0x4D
+#define AB8500_IT_MASK15_REG		0x4E
+#define AB8500_IT_MASK16_REG		0x4F
+#define AB8500_IT_MASK17_REG		0x50
+#define AB8500_IT_MASK18_REG		0x51
+#define AB8500_IT_MASK19_REG		0x52
+#define AB8500_IT_MASK20_REG		0x53
+#define AB8500_IT_MASK21_REG		0x54
+#define AB8500_IT_MASK22_REG		0x55
+#define AB8500_IT_MASK23_REG		0x56
+#define AB8500_IT_MASK24_REG		0x57
+
+#define AB8500_REV_REG			0x80
 
 
 /*
 /*
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
@@ -99,96 +101,132 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
 	0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
 	0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
 };
 };
 
 
-static int __ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data)
+static int ab8500_get_chip_id(struct device *dev)
+{
+	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+	return (int)ab8500->chip_id;
+}
+
+static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
+	u8 reg, u8 data)
 {
 {
 	int ret;
 	int ret;
+	/*
+	 * Put the u8 bank and u8 register together into a an u16.
+	 * The bank on higher 8 bits and register in lower 8 bits.
+	 * */
+	u16 addr = ((u16)bank) << 8 | reg;
 
 
 	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;
+
 	ret = ab8500->write(ab8500, addr, data);
 	ret = ab8500->write(ab8500, addr, data);
 	if (ret < 0)
 	if (ret < 0)
 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
 			addr, ret);
 			addr, ret);
+	mutex_unlock(&ab8500->lock);
 
 
 	return ret;
 	return ret;
 }
 }
 
 
-/**
- * ab8500_write() - write an AB8500 register
- * @ab8500: device to write to
- * @addr: address of the register
- * @data: value to write
- */
-int ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data)
+static int ab8500_set_register(struct device *dev, u8 bank,
+	u8 reg, u8 value)
 {
 {
-	int ret;
+	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
 
 
-	mutex_lock(&ab8500->lock);
-	ret = __ab8500_write(ab8500, addr, data);
-	mutex_unlock(&ab8500->lock);
-
-	return ret;
+	return set_register_interruptible(ab8500, bank, reg, value);
 }
 }
-EXPORT_SYMBOL_GPL(ab8500_write);
 
 
-static int __ab8500_read(struct ab8500 *ab8500, u16 addr)
+static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
+	u8 reg, u8 *value)
 {
 {
 	int ret;
 	int ret;
+	/* put the u8 bank and u8 reg together into a an u16.
+	 * bank on higher 8 bits and reg in lower */
+	u16 addr = ((u16)bank) << 8 | reg;
+
+	ret = mutex_lock_interruptible(&ab8500->lock);
+	if (ret)
+		return ret;
 
 
 	ret = ab8500->read(ab8500, addr);
 	ret = ab8500->read(ab8500, addr);
 	if (ret < 0)
 	if (ret < 0)
 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
 			addr, ret);
 			addr, ret);
+	else
+		*value = ret;
 
 
+	mutex_unlock(&ab8500->lock);
 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
 
 
 	return ret;
 	return ret;
 }
 }
 
 
-/**
- * ab8500_read() - read an AB8500 register
- * @ab8500: device to read from
- * @addr: address of the register
- */
-int ab8500_read(struct ab8500 *ab8500, u16 addr)
+static int ab8500_get_register(struct device *dev, u8 bank,
+	u8 reg, u8 *value)
 {
 {
-	int ret;
-
-	mutex_lock(&ab8500->lock);
-	ret = __ab8500_read(ab8500, addr);
-	mutex_unlock(&ab8500->lock);
+	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
 
 
-	return ret;
+	return get_register_interruptible(ab8500, bank, reg, value);
 }
 }
-EXPORT_SYMBOL_GPL(ab8500_read);
-
-/**
- * ab8500_set_bits() - set a bitfield in an AB8500 register
- * @ab8500: device to read from
- * @addr: address of the register
- * @mask: mask of the bitfield to modify
- * @data: value to set to the bitfield
- */
-int ab8500_set_bits(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data)
+
+static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
+	u8 reg, u8 bitmask, u8 bitvalues)
 {
 {
 	int ret;
 	int ret;
+	u8 data;
+	/* put the u8 bank and u8 reg together into a an u16.
+	 * bank on higher 8 bits and reg in lower */
+	u16 addr = ((u16)bank) << 8 | reg;
 
 
-	mutex_lock(&ab8500->lock);
+	ret = mutex_lock_interruptible(&ab8500->lock);
+	if (ret)
+		return ret;
 
 
-	ret = __ab8500_read(ab8500, addr);
-	if (ret < 0)
+	ret = ab8500->read(ab8500, addr);
+	if (ret < 0) {
+		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
+			addr, ret);
 		goto out;
 		goto out;
+	}
 
 
-	ret &= ~mask;
-	ret |= data;
+	data = (u8)ret;
+	data = (~bitmask & data) | (bitmask & bitvalues);
 
 
-	ret = __ab8500_write(ab8500, addr, ret);
+	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);
 out:
 out:
 	mutex_unlock(&ab8500->lock);
 	mutex_unlock(&ab8500->lock);
 	return ret;
 	return ret;
 }
 }
-EXPORT_SYMBOL_GPL(ab8500_set_bits);
+
+static int ab8500_mask_and_set_register(struct device *dev,
+	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
+{
+	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+
+	return mask_and_set_register_interruptible(ab8500, bank, reg,
+		bitmask, bitvalues);
+
+}
+
+static struct abx500_ops ab8500_ops = {
+	.get_chip_id = ab8500_get_chip_id,
+	.get_register = ab8500_get_register,
+	.set_register = ab8500_set_register,
+	.get_register_page = NULL,
+	.set_register_page = NULL,
+	.mask_and_set_register = ab8500_mask_and_set_register,
+	.event_registers_startup_state_get = NULL,
+	.startup_irq_enabled = NULL,
+};
 
 
 static void ab8500_irq_lock(unsigned int irq)
 static void ab8500_irq_lock(unsigned int irq)
 {
 {
@@ -213,7 +251,7 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
 		ab8500->oldmask[i] = new;
 		ab8500->oldmask[i] = new;
 
 
 		reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
 		reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
-		ab8500_write(ab8500, reg, new);
+		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
 	}
 	}
 
 
 	mutex_unlock(&ab8500->irq_lock);
 	mutex_unlock(&ab8500->irq_lock);
@@ -257,9 +295,11 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
 		int regoffset = ab8500_irq_regoffset[i];
 		int regoffset = ab8500_irq_regoffset[i];
 		int status;
 		int status;
+		u8 value;
 
 
-		status = ab8500_read(ab8500, AB8500_IT_LATCH1_REG + regoffset);
-		if (status <= 0)
+		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
+			AB8500_IT_LATCH1_REG + regoffset, &value);
+		if (status < 0 || value == 0)
 			continue;
 			continue;
 
 
 		do {
 		do {
@@ -267,8 +307,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
 			int line = i * 8 + bit;
 			int line = i * 8 + bit;
 
 
 			handle_nested_irq(ab8500->irq_base + line);
 			handle_nested_irq(ab8500->irq_base + line);
-			status &= ~(1 << bit);
-		} while (status);
+			value &= ~(1 << bit);
+		} while (value);
 	}
 	}
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
@@ -354,6 +394,11 @@ static struct resource ab8500_poweronkey_db_resources[] = {
 };
 };
 
 
 static struct mfd_cell ab8500_devs[] = {
 static struct mfd_cell ab8500_devs[] = {
+#ifdef CONFIG_DEBUG_FS
+	{
+		.name = "ab8500-debug",
+	},
+#endif
 	{
 	{
 		.name = "ab8500-gpadc",
 		.name = "ab8500-gpadc",
 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
@@ -364,10 +409,21 @@ static struct mfd_cell ab8500_devs[] = {
 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
 		.resources = ab8500_rtc_resources,
 		.resources = ab8500_rtc_resources,
 	},
 	},
+	{
+		.name = "ab8500-pwm",
+		.id = 1,
+	},
+	{
+		.name = "ab8500-pwm",
+		.id = 2,
+	},
+	{
+		.name = "ab8500-pwm",
+		.id = 3,
+	},
 	{ .name = "ab8500-charger", },
 	{ .name = "ab8500-charger", },
 	{ .name = "ab8500-audio", },
 	{ .name = "ab8500-audio", },
 	{ .name = "ab8500-usb", },
 	{ .name = "ab8500-usb", },
-	{ .name = "ab8500-pwm", },
 	{ .name = "ab8500-regulator", },
 	{ .name = "ab8500-regulator", },
 	{
 	{
 		.name = "ab8500-poweron-key",
 		.name = "ab8500-poweron-key",
@@ -381,6 +437,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 	struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
 	struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
 	int ret;
 	int ret;
 	int i;
 	int i;
+	u8 value;
 
 
 	if (plat)
 	if (plat)
 		ab8500->irq_base = plat->irq_base;
 		ab8500->irq_base = plat->irq_base;
@@ -388,7 +445,8 @@ 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);
 
 
-	ret = ab8500_read(ab8500, AB8500_REV_REG);
+	ret = get_register_interruptible(ab8500, AB8500_MISC,
+		AB8500_REV_REG, &value);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
@@ -397,28 +455,37 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
 	 * 0x10 - Cut 1.0
 	 * 0x10 - Cut 1.0
 	 * 0x11 - Cut 1.1
 	 * 0x11 - Cut 1.1
 	 */
 	 */
-	if (ret == 0x0 || ret == 0x10 || ret == 0x11) {
-		ab8500->revision = ret;
-		dev_info(ab8500->dev, "detected chip, revision: %#x\n", ret);
+	if (value == 0x0 || value == 0x10 || value == 0x11) {
+		ab8500->revision = value;
+		dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
 	} else {
 	} else {
-		dev_err(ab8500->dev, "unknown chip, revision: %#x\n", ret);
+		dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
+	ab8500->chip_id = value;
 
 
 	if (plat && plat->init)
 	if (plat && plat->init)
 		plat->init(ab8500);
 		plat->init(ab8500);
 
 
 	/* Clear and mask all interrupts */
 	/* Clear and mask all interrupts */
 	for (i = 0; i < 10; i++) {
 	for (i = 0; i < 10; i++) {
-		ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i);
-		ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff);
+		get_register_interruptible(ab8500, AB8500_INTERRUPT,
+			AB8500_IT_LATCH1_REG + i, &value);
+		set_register_interruptible(ab8500, AB8500_INTERRUPT,
+			AB8500_IT_MASK1_REG + i, 0xff);
 	}
 	}
 
 
 	for (i = 18; i < 24; i++) {
 	for (i = 18; i < 24; i++) {
-		ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i);
-		ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff);
+		get_register_interruptible(ab8500, AB8500_INTERRUPT,
+			AB8500_IT_LATCH1_REG + i, &value);
+		set_register_interruptible(ab8500, AB8500_INTERRUPT,
+			AB8500_IT_MASK1_REG + i, 0xff);
 	}
 	}
 
 
+	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
 
 

+ 652 - 0
drivers/mfd/ab8500-debugfs.c

@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
+ * License Terms: GNU General Public License v2
+ */
+
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500.h>
+
+static u32 debug_bank;
+static u32 debug_address;
+
+/**
+ * struct ab8500_reg_range
+ * @first: the first address of the range
+ * @last: the last address of the range
+ * @perm: access permissions for the range
+ */
+struct ab8500_reg_range {
+       u8 first;
+       u8 last;
+       u8 perm;
+};
+
+/**
+ * struct ab8500_i2c_ranges
+ * @num_ranges: the number of ranges in the list
+ * @bankid: bank identifier
+ * @range: the list of register ranges
+ */
+struct ab8500_i2c_ranges {
+       u8 num_ranges;
+       u8 bankid;
+       const struct ab8500_reg_range *range;
+};
+
+#define AB8500_NAME_STRING "ab8500"
+#define AB8500_NUM_BANKS 22
+
+#define AB8500_REV_REG 0x80
+
+static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
+       [0x0] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [AB8500_SYS_CTRL1_BLOCK] = {
+               .num_ranges = 3,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x02,
+                       },
+                       {
+                               .first = 0x42,
+                               .last = 0x42,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x81,
+                       },
+               },
+       },
+       [AB8500_SYS_CTRL2_BLOCK] = {
+               .num_ranges = 4,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x0D,
+                       },
+                       {
+                               .first = 0x0F,
+                               .last = 0x17,
+                       },
+                       {
+                               .first = 0x30,
+                               .last = 0x30,
+                       },
+                       {
+                               .first = 0x32,
+                               .last = 0x33,
+                       },
+               },
+       },
+       [AB8500_REGU_CTRL1] = {
+               .num_ranges = 3,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x00,
+                       },
+                       {
+                               .first = 0x03,
+                               .last = 0x10,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x84,
+                       },
+               },
+       },
+       [AB8500_REGU_CTRL2] = {
+               .num_ranges = 5,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x15,
+                       },
+                       {
+                               .first = 0x17,
+                               .last = 0x19,
+                       },
+                       {
+                               .first = 0x1B,
+                               .last = 0x1D,
+                       },
+                       {
+                               .first = 0x1F,
+                               .last = 0x22,
+                       },
+                       {
+                               .first = 0x40,
+                               .last = 0x44,
+                       },
+                       /* 0x80-0x8B is SIM registers and should
+                        * not be accessed from here */
+               },
+       },
+       [AB8500_USB] = {
+               .num_ranges = 2,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x80,
+                               .last = 0x83,
+                       },
+                       {
+                               .first = 0x87,
+                               .last = 0x8A,
+                       },
+               },
+       },
+       [AB8500_TVOUT] = {
+               .num_ranges = 9,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x12,
+                       },
+                       {
+                               .first = 0x15,
+                               .last = 0x17,
+                       },
+                       {
+                               .first = 0x19,
+                               .last = 0x21,
+                       },
+                       {
+                               .first = 0x27,
+                               .last = 0x2C,
+                       },
+                       {
+                               .first = 0x41,
+                               .last = 0x41,
+                       },
+                       {
+                               .first = 0x45,
+                               .last = 0x5B,
+                       },
+                       {
+                               .first = 0x5D,
+                               .last = 0x5D,
+                       },
+                       {
+                               .first = 0x69,
+                               .last = 0x69,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x81,
+                       },
+               },
+       },
+       [AB8500_DBI] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [AB8500_ECI_AV_ACC] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x80,
+                               .last = 0x82,
+                       },
+               },
+       },
+       [0x9] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [AB8500_GPADC] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x08,
+                       },
+               },
+       },
+       [AB8500_CHARGER] = {
+               .num_ranges = 8,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x03,
+                       },
+                       {
+                               .first = 0x05,
+                               .last = 0x05,
+                       },
+                       {
+                               .first = 0x40,
+                               .last = 0x40,
+                       },
+                       {
+                               .first = 0x42,
+                               .last = 0x42,
+                       },
+                       {
+                               .first = 0x44,
+                               .last = 0x44,
+                       },
+                       {
+                               .first = 0x50,
+                               .last = 0x55,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x82,
+                       },
+                       {
+                               .first = 0xC0,
+                               .last = 0xC2,
+                       },
+               },
+       },
+       [AB8500_GAS_GAUGE] = {
+               .num_ranges = 3,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x00,
+                       },
+                       {
+                               .first = 0x07,
+                               .last = 0x0A,
+                       },
+                       {
+                               .first = 0x10,
+                               .last = 0x14,
+                       },
+               },
+       },
+       [AB8500_AUDIO] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x6F,
+                       },
+               },
+       },
+       [AB8500_INTERRUPT] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [AB8500_RTC] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x0F,
+                       },
+               },
+       },
+       [AB8500_MISC] = {
+               .num_ranges = 8,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x05,
+                       },
+                       {
+                               .first = 0x10,
+                               .last = 0x15,
+                       },
+                       {
+                               .first = 0x20,
+                               .last = 0x25,
+                       },
+                       {
+                               .first = 0x30,
+                               .last = 0x35,
+                       },
+                       {
+                               .first = 0x40,
+                               .last = 0x45,
+                       },
+                       {
+                               .first = 0x50,
+                               .last = 0x50,
+                       },
+                       {
+                               .first = 0x60,
+                               .last = 0x67,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x80,
+                       },
+               },
+       },
+       [0x11] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [0x12] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [0x13] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [0x14] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [AB8500_OTP_EMUL] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x01,
+                               .last = 0x0F,
+                       },
+               },
+       },
+};
+
+static int ab8500_registers_print(struct seq_file *s, void *p)
+{
+       struct device *dev = s->private;
+       unsigned int i;
+       u32 bank = debug_bank;
+
+       seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+       seq_printf(s, " bank %u:\n", bank);
+       for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+               u32 reg;
+
+               for (reg = debug_ranges[bank].range[i].first;
+                       reg <= debug_ranges[bank].range[i].last;
+                       reg++) {
+                       u8 value;
+                       int err;
+
+                       err = abx500_get_register_interruptible(dev,
+                               (u8)bank, (u8)reg, &value);
+                       if (err < 0) {
+                               dev_err(dev, "ab->read fail %d\n", err);
+                               return err;
+                       }
+
+                       err = seq_printf(s, "  [%u/0x%02X]: 0x%02X\n", bank,
+                               reg, value);
+                       if (err < 0) {
+                               dev_err(dev, "seq_printf overflow\n");
+                               /* Error is not returned here since
+                                * the output is wanted in any case */
+                               return 0;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int ab8500_registers_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_registers_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_registers_fops = {
+       .open = ab8500_registers_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static int ab8500_bank_print(struct seq_file *s, void *p)
+{
+       return seq_printf(s, "%d\n", debug_bank);
+}
+
+static int ab8500_bank_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_bank_print, inode->i_private);
+}
+
+static ssize_t ab8500_bank_write(struct file *file,
+       const char __user *user_buf,
+       size_t count, loff_t *ppos)
+{
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_bank;
+       int err;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_bank);
+       if (err)
+               return -EINVAL;
+
+       if (user_bank >= AB8500_NUM_BANKS) {
+               dev_err(dev, "debugfs error input > number of banks\n");
+               return -EINVAL;
+       }
+
+       debug_bank = user_bank;
+
+       return buf_size;
+}
+
+static int ab8500_address_print(struct seq_file *s, void *p)
+{
+       return seq_printf(s, "0x%02X\n", debug_address);
+}
+
+static int ab8500_address_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_address_print, inode->i_private);
+}
+
+static ssize_t ab8500_address_write(struct file *file,
+       const char __user *user_buf,
+       size_t count, loff_t *ppos)
+{
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_address;
+       int err;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_address);
+       if (err)
+               return -EINVAL;
+       if (user_address > 0xff) {
+               dev_err(dev, "debugfs error input > 0xff\n");
+               return -EINVAL;
+       }
+       debug_address = user_address;
+       return buf_size;
+}
+
+static int ab8500_val_print(struct seq_file *s, void *p)
+{
+       struct device *dev = s->private;
+       int ret;
+       u8 regvalue;
+
+       ret = abx500_get_register_interruptible(dev,
+               (u8)debug_bank, (u8)debug_address, &regvalue);
+       if (ret < 0) {
+               dev_err(dev, "abx500_get_reg fail %d, %d\n",
+                       ret, __LINE__);
+               return -EINVAL;
+       }
+       seq_printf(s, "0x%02X\n", regvalue);
+
+       return 0;
+}
+
+static int ab8500_val_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ab8500_val_print, inode->i_private);
+}
+
+static ssize_t ab8500_val_write(struct file *file,
+       const char __user *user_buf,
+       size_t count, loff_t *ppos)
+{
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_val;
+       int err;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_val);
+       if (err)
+               return -EINVAL;
+       if (user_val > 0xff) {
+               dev_err(dev, "debugfs error input > 0xff\n");
+               return -EINVAL;
+       }
+       err = abx500_set_register_interruptible(dev,
+               (u8)debug_bank, debug_address, (u8)user_val);
+       if (err < 0) {
+               printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
+               return -EINVAL;
+       }
+
+       return buf_size;
+}
+
+static const struct file_operations ab8500_bank_fops = {
+       .open = ab8500_bank_open,
+       .write = ab8500_bank_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_address_fops = {
+       .open = ab8500_address_open,
+       .write = ab8500_address_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_val_fops = {
+       .open = ab8500_val_open,
+       .write = ab8500_val_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+};
+
+static struct dentry *ab8500_dir;
+static struct dentry *ab8500_reg_file;
+static struct dentry *ab8500_bank_file;
+static struct dentry *ab8500_address_file;
+static struct dentry *ab8500_val_file;
+
+static int __devinit ab8500_debug_probe(struct platform_device *plf)
+{
+       debug_bank = AB8500_MISC;
+       debug_address = AB8500_REV_REG & 0x00FF;
+
+       ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
+       if (!ab8500_dir)
+               goto exit_no_debugfs;
+
+       ab8500_reg_file = debugfs_create_file("all-bank-registers",
+               S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
+       if (!ab8500_reg_file)
+               goto exit_destroy_dir;
+
+       ab8500_bank_file = debugfs_create_file("register-bank",
+               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+       if (!ab8500_bank_file)
+               goto exit_destroy_reg;
+
+       ab8500_address_file = debugfs_create_file("register-address",
+               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+               &ab8500_address_fops);
+       if (!ab8500_address_file)
+               goto exit_destroy_bank;
+
+       ab8500_val_file = debugfs_create_file("register-value",
+               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
+       if (!ab8500_val_file)
+               goto exit_destroy_address;
+
+       return 0;
+
+exit_destroy_address:
+       debugfs_remove(ab8500_address_file);
+exit_destroy_bank:
+       debugfs_remove(ab8500_bank_file);
+exit_destroy_reg:
+       debugfs_remove(ab8500_reg_file);
+exit_destroy_dir:
+       debugfs_remove(ab8500_dir);
+exit_no_debugfs:
+       dev_err(&plf->dev, "failed to create debugfs entries.\n");
+       return -ENOMEM;
+}
+
+static int __devexit ab8500_debug_remove(struct platform_device *plf)
+{
+       debugfs_remove(ab8500_val_file);
+       debugfs_remove(ab8500_address_file);
+       debugfs_remove(ab8500_bank_file);
+       debugfs_remove(ab8500_reg_file);
+       debugfs_remove(ab8500_dir);
+
+       return 0;
+}
+
+static struct platform_driver ab8500_debug_driver = {
+       .driver = {
+               .name = "ab8500-debug",
+               .owner = THIS_MODULE,
+       },
+       .probe  = ab8500_debug_probe,
+       .remove = __devexit_p(ab8500_debug_remove)
+};
+
+static int __init ab8500_debug_init(void)
+{
+       return platform_driver_register(&ab8500_debug_driver);
+}
+
+static void __exit ab8500_debug_exit(void)
+{
+       platform_driver_unregister(&ab8500_debug_driver);
+}
+subsys_initcall(ab8500_debug_init);
+module_exit(ab8500_debug_exit);
+
+MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
+MODULE_DESCRIPTION("AB8500 DEBUG");
+MODULE_LICENSE("GPL v2");

+ 105 - 0
drivers/mfd/ab8500-i2c.c

@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
+ * License Terms: GNU General Public License v2
+ * This file was based on drivers/mfd/ab8500-spi.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ab8500.h>
+
+#include <mach/prcmu.h>
+
+static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
+{
+	int ret;
+
+	ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 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)
+{
+	int ret;
+	u8 data;
+
+	ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
+	if (ret < 0) {
+		dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+		return ret;
+	}
+	return (int)data;
+}
+
+static int __devinit ab8500_i2c_probe(struct platform_device *plf)
+{
+	struct ab8500 *ab8500;
+	struct resource *resource;
+	int ret;
+
+	ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
+	if (!ab8500)
+		return -ENOMEM;
+
+	ab8500->dev = &plf->dev;
+
+	resource = platform_get_resource(plf, IORESOURCE_IRQ, 0);
+	if (!resource) {
+		kfree(ab8500);
+		return -ENODEV;
+	}
+
+	ab8500->irq = resource->start;
+
+	ab8500->read = ab8500_i2c_read;
+	ab8500->write = ab8500_i2c_write;
+
+	platform_set_drvdata(plf, ab8500);
+
+	ret = ab8500_init(ab8500);
+	if (ret)
+		kfree(ab8500);
+
+	return ret;
+}
+
+static int __devexit ab8500_i2c_remove(struct platform_device *plf)
+{
+	struct ab8500 *ab8500 = platform_get_drvdata(plf);
+
+	ab8500_exit(ab8500);
+	kfree(ab8500);
+
+	return 0;
+}
+
+static struct platform_driver ab8500_i2c_driver = {
+	.driver = {
+		.name = "ab8500-i2c",
+		.owner = THIS_MODULE,
+	},
+	.probe	= ab8500_i2c_probe,
+	.remove	= __devexit_p(ab8500_i2c_remove)
+};
+
+static int __init ab8500_i2c_init(void)
+{
+	return platform_driver_register(&ab8500_i2c_driver);
+}
+
+static void __exit ab8500_i2c_exit(void)
+{
+	platform_driver_unregister(&ab8500_i2c_driver);
+}
+subsys_initcall(ab8500_i2c_init);
+module_exit(ab8500_i2c_exit);
+
+MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
+MODULE_DESCRIPTION("AB8500 Core access via PRCMU I2C");
+MODULE_LICENSE("GPL v2");

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

@@ -119,7 +119,7 @@ static int __devexit ab8500_spi_remove(struct spi_device *spi)
 
 
 static struct spi_driver ab8500_spi_driver = {
 static struct spi_driver ab8500_spi_driver = {
 	.driver = {
 	.driver = {
-		.name = "ab8500",
+		.name = "ab8500-spi",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe	= ab8500_spi_probe,
 	.probe	= ab8500_spi_probe,

+ 7 - 1
drivers/mfd/da903x.c

@@ -470,13 +470,19 @@ static int __devinit da903x_add_subdevs(struct da903x_chip *chip,
 		subdev = &pdata->subdevs[i];
 		subdev = &pdata->subdevs[i];
 
 
 		pdev = platform_device_alloc(subdev->name, subdev->id);
 		pdev = platform_device_alloc(subdev->name, subdev->id);
+		if (!pdev) {
+			ret = -ENOMEM;
+			goto failed;
+		}
 
 
 		pdev->dev.parent = chip->dev;
 		pdev->dev.parent = chip->dev;
 		pdev->dev.platform_data = subdev->platform_data;
 		pdev->dev.platform_data = subdev->platform_data;
 
 
 		ret = platform_device_add(pdev);
 		ret = platform_device_add(pdev);
-		if (ret)
+		if (ret) {
+			platform_device_put(pdev);
 			goto failed;
 			goto failed;
+		}
 	}
 	}
 	return 0;
 	return 0;
 
 

+ 10 - 1
drivers/mfd/ezx-pcap.c

@@ -384,12 +384,20 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap,
 						struct pcap_subdev *subdev)
 						struct pcap_subdev *subdev)
 {
 {
 	struct platform_device *pdev;
 	struct platform_device *pdev;
+	int ret;
 
 
 	pdev = platform_device_alloc(subdev->name, subdev->id);
 	pdev = platform_device_alloc(subdev->name, subdev->id);
+	if (!pdev)
+		return -ENOMEM;
+
 	pdev->dev.parent = &pcap->spi->dev;
 	pdev->dev.parent = &pcap->spi->dev;
 	pdev->dev.platform_data = subdev->platform_data;
 	pdev->dev.platform_data = subdev->platform_data;
 
 
-	return platform_device_add(pdev);
+	ret = platform_device_add(pdev);
+	if (ret)
+		platform_device_put(pdev);
+
+	return ret;
 }
 }
 
 
 static int __devexit ezx_pcap_remove(struct spi_device *spi)
 static int __devexit ezx_pcap_remove(struct spi_device *spi)
@@ -457,6 +465,7 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi)
 	pcap->irq_base = pdata->irq_base;
 	pcap->irq_base = pdata->irq_base;
 	pcap->workqueue = create_singlethread_workqueue("pcapd");
 	pcap->workqueue = create_singlethread_workqueue("pcapd");
 	if (!pcap->workqueue) {
 	if (!pcap->workqueue) {
+		ret = -ENOMEM;
 		dev_err(&spi->dev, "cant create pcap thread\n");
 		dev_err(&spi->dev, "cant create pcap thread\n");
 		goto free_pcap;
 		goto free_pcap;
 	}
 	}

+ 0 - 7
drivers/mfd/htc-pasic3.c

@@ -138,13 +138,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
 		irq = r->start;
 		irq = r->start;
 	}
 	}
 
 
-	r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (r) {
-		ds1wm_resources[1].flags = IORESOURCE_IRQ | (r->flags &
-			(IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE));
-		irq = r->start;
-	}
-
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!r)
 	if (!r)
 		return -ENXIO;
 		return -ENXIO;

+ 1 - 1
drivers/mfd/jz4740-adc.c

@@ -153,7 +153,7 @@ static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine,
 	if (enabled)
 	if (enabled)
 		val |= BIT(engine);
 		val |= BIT(engine);
 	else
 	else
-		val &= BIT(engine);
+		val &= ~BIT(engine);
 	writeb(val, adc->base + JZ_REG_ADC_ENABLE);
 	writeb(val, adc->base + JZ_REG_ADC_ENABLE);
 
 
 	spin_unlock_irqrestore(&adc->lock, flags);
 	spin_unlock_irqrestore(&adc->lock, flags);

+ 8 - 3
drivers/mfd/max8925-core.c

@@ -93,8 +93,13 @@ static struct mfd_cell rtc_devs[] = {
 static struct resource onkey_resources[] = {
 static struct resource onkey_resources[] = {
 	{
 	{
 		.name	= "max8925-onkey",
 		.name	= "max8925-onkey",
-		.start	= MAX8925_IRQ_GPM_SW_3SEC,
-		.end	= MAX8925_IRQ_GPM_SW_3SEC,
+		.start	= MAX8925_IRQ_GPM_SW_R,
+		.end	= MAX8925_IRQ_GPM_SW_R,
+		.flags	= IORESOURCE_IRQ,
+	}, {
+		.name	= "max8925-onkey",
+		.start	= MAX8925_IRQ_GPM_SW_F,
+		.end	= MAX8925_IRQ_GPM_SW_F,
 		.flags	= IORESOURCE_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 	},
 };
 };
@@ -102,7 +107,7 @@ static struct resource onkey_resources[] = {
 static struct mfd_cell onkey_devs[] = {
 static struct mfd_cell onkey_devs[] = {
 	{
 	{
 		.name		= "max8925-onkey",
 		.name		= "max8925-onkey",
-		.num_resources	= 1,
+		.num_resources	= 2,
 		.resources	= &onkey_resources[0],
 		.resources	= &onkey_resources[0],
 		.id		= -1,
 		.id		= -1,
 	},
 	},

+ 258 - 0
drivers/mfd/max8998-irq.c

@@ -0,0 +1,258 @@
+/*
+ * Interrupt controller support for MAX8998
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/max8998-private.h>
+
+struct max8998_irq_data {
+	int reg;
+	int mask;
+};
+
+static struct max8998_irq_data max8998_irqs[] = {
+	[MAX8998_IRQ_DCINF] = {
+		.reg = 1,
+		.mask = MAX8998_IRQ_DCINF_MASK,
+	},
+	[MAX8998_IRQ_DCINR] = {
+		.reg = 1,
+		.mask = MAX8998_IRQ_DCINR_MASK,
+	},
+	[MAX8998_IRQ_JIGF] = {
+		.reg = 1,
+		.mask = MAX8998_IRQ_JIGF_MASK,
+	},
+	[MAX8998_IRQ_JIGR] = {
+		.reg = 1,
+		.mask = MAX8998_IRQ_JIGR_MASK,
+	},
+	[MAX8998_IRQ_PWRONF] = {
+		.reg = 1,
+		.mask = MAX8998_IRQ_PWRONF_MASK,
+	},
+	[MAX8998_IRQ_PWRONR] = {
+		.reg = 1,
+		.mask = MAX8998_IRQ_PWRONR_MASK,
+	},
+	[MAX8998_IRQ_WTSREVNT] = {
+		.reg = 2,
+		.mask = MAX8998_IRQ_WTSREVNT_MASK,
+	},
+	[MAX8998_IRQ_SMPLEVNT] = {
+		.reg = 2,
+		.mask = MAX8998_IRQ_SMPLEVNT_MASK,
+	},
+	[MAX8998_IRQ_ALARM1] = {
+		.reg = 2,
+		.mask = MAX8998_IRQ_ALARM1_MASK,
+	},
+	[MAX8998_IRQ_ALARM0] = {
+		.reg = 2,
+		.mask = MAX8998_IRQ_ALARM0_MASK,
+	},
+	[MAX8998_IRQ_ONKEY1S] = {
+		.reg = 3,
+		.mask = MAX8998_IRQ_ONKEY1S_MASK,
+	},
+	[MAX8998_IRQ_TOPOFFR] = {
+		.reg = 3,
+		.mask = MAX8998_IRQ_TOPOFFR_MASK,
+	},
+	[MAX8998_IRQ_DCINOVPR] = {
+		.reg = 3,
+		.mask = MAX8998_IRQ_DCINOVPR_MASK,
+	},
+	[MAX8998_IRQ_CHGRSTF] = {
+		.reg = 3,
+		.mask = MAX8998_IRQ_CHGRSTF_MASK,
+	},
+	[MAX8998_IRQ_DONER] = {
+		.reg = 3,
+		.mask = MAX8998_IRQ_DONER_MASK,
+	},
+	[MAX8998_IRQ_CHGFAULT] = {
+		.reg = 3,
+		.mask = MAX8998_IRQ_CHGFAULT_MASK,
+	},
+	[MAX8998_IRQ_LOBAT1] = {
+		.reg = 4,
+		.mask = MAX8998_IRQ_LOBAT1_MASK,
+	},
+	[MAX8998_IRQ_LOBAT2] = {
+		.reg = 4,
+		.mask = MAX8998_IRQ_LOBAT2_MASK,
+	},
+};
+
+static inline struct max8998_irq_data *
+irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
+{
+	return &max8998_irqs[irq - max8998->irq_base];
+}
+
+static void max8998_irq_lock(unsigned int irq)
+{
+	struct max8998_dev *max8998 = get_irq_chip_data(irq);
+
+	mutex_lock(&max8998->irqlock);
+}
+
+static void max8998_irq_sync_unlock(unsigned int irq)
+{
+	struct max8998_dev *max8998 = get_irq_chip_data(irq);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
+		/*
+		 * If there's been a change in the mask write it back
+		 * to the hardware.
+		 */
+		if (max8998->irq_masks_cur[i] != max8998->irq_masks_cache[i]) {
+			max8998->irq_masks_cache[i] = max8998->irq_masks_cur[i];
+			max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i,
+					max8998->irq_masks_cur[i]);
+		}
+	}
+
+	mutex_unlock(&max8998->irqlock);
+}
+
+static void max8998_irq_unmask(unsigned int irq)
+{
+	struct max8998_dev *max8998 = get_irq_chip_data(irq);
+	struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+
+	max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void max8998_irq_mask(unsigned int irq)
+{
+	struct max8998_dev *max8998 = get_irq_chip_data(irq);
+	struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+
+	max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip max8998_irq_chip = {
+	.name = "max8998",
+	.bus_lock = max8998_irq_lock,
+	.bus_sync_unlock = max8998_irq_sync_unlock,
+	.mask = max8998_irq_mask,
+	.unmask = max8998_irq_unmask,
+};
+
+static irqreturn_t max8998_irq_thread(int irq, void *data)
+{
+	struct max8998_dev *max8998 = data;
+	u8 irq_reg[MAX8998_NUM_IRQ_REGS];
+	int ret;
+	int i;
+
+	ret = max8998_bulk_read(max8998->i2c, MAX8998_REG_IRQ1,
+			MAX8998_NUM_IRQ_REGS, irq_reg);
+	if (ret < 0) {
+		dev_err(max8998->dev, "Failed to read interrupt register: %d\n",
+				ret);
+		return IRQ_NONE;
+	}
+
+	/* Apply masking */
+	for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++)
+		irq_reg[i] &= ~max8998->irq_masks_cur[i];
+
+	/* Report */
+	for (i = 0; i < MAX8998_IRQ_NR; i++) {
+		if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask)
+			handle_nested_irq(max8998->irq_base + i);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int max8998_irq_init(struct max8998_dev *max8998)
+{
+	int i;
+	int cur_irq;
+	int ret;
+
+	if (!max8998->irq) {
+		dev_warn(max8998->dev,
+			 "No interrupt specified, no interrupts\n");
+		max8998->irq_base = 0;
+		return 0;
+	}
+
+	if (!max8998->irq_base) {
+		dev_err(max8998->dev,
+			"No interrupt base specified, no interrupts\n");
+		return 0;
+	}
+
+	mutex_init(&max8998->irqlock);
+
+	/* Mask the individual interrupt sources */
+	for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) {
+		max8998->irq_masks_cur[i] = 0xff;
+		max8998->irq_masks_cache[i] = 0xff;
+		max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, 0xff);
+	}
+
+	max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff);
+	max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff);
+
+	/* register with genirq */
+	for (i = 0; i < MAX8998_IRQ_NR; i++) {
+		cur_irq = i + max8998->irq_base;
+		set_irq_chip_data(cur_irq, max8998);
+		set_irq_chip_and_handler(cur_irq, &max8998_irq_chip,
+					 handle_edge_irq);
+		set_irq_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(cur_irq, IRQF_VALID);
+#else
+		set_irq_noprobe(cur_irq);
+#endif
+	}
+
+	ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   "max8998-irq", max8998);
+	if (ret) {
+		dev_err(max8998->dev, "Failed to request IRQ %d: %d\n",
+			max8998->irq, ret);
+		return ret;
+	}
+
+	if (!max8998->ono)
+		return 0;
+
+	ret = request_threaded_irq(max8998->ono, NULL, max8998_irq_thread,
+				   IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+				   IRQF_ONESHOT, "max8998-ono", max8998);
+	if (ret)
+		dev_err(max8998->dev, "Failed to request IRQ %d: %d\n",
+			max8998->ono, ret);
+
+	return 0;
+}
+
+void max8998_irq_exit(struct max8998_dev *max8998)
+{
+	if (max8998->ono)
+		free_irq(max8998->ono, max8998);
+
+	if (max8998->irq)
+		free_irq(max8998->irq, max8998);
+}

+ 69 - 21
drivers/mfd/max8998.c

@@ -1,5 +1,5 @@
 /*
 /*
- * max8698.c - mfd core driver for the Maxim 8998
+ * max8998.c - mfd core driver for the Maxim 8998
  *
  *
  *  Copyright (C) 2009-2010 Samsung Electronics
  *  Copyright (C) 2009-2010 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
  *  Kyungmin Park <kyungmin.park@samsung.com>
@@ -30,19 +30,23 @@
 #include <linux/mfd/max8998.h>
 #include <linux/mfd/max8998.h>
 #include <linux/mfd/max8998-private.h>
 #include <linux/mfd/max8998-private.h>
 
 
+#define RTC_I2C_ADDR		(0x0c >> 1)
+
 static struct mfd_cell max8998_devs[] = {
 static struct mfd_cell max8998_devs[] = {
 	{
 	{
 		.name = "max8998-pmic",
 		.name = "max8998-pmic",
-	}
+	}, {
+		.name = "max8998-rtc",
+	},
 };
 };
 
 
-static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest)
+int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
 {
 {
-	struct i2c_client *client = max8998->i2c_client;
+	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 	int ret;
 	int ret;
 
 
 	mutex_lock(&max8998->iolock);
 	mutex_lock(&max8998->iolock);
-	ret = i2c_smbus_read_byte_data(client, reg);
+	ret = i2c_smbus_read_byte_data(i2c, reg);
 	mutex_unlock(&max8998->iolock);
 	mutex_unlock(&max8998->iolock);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
@@ -51,40 +55,71 @@ static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest
 	*dest = ret;
 	*dest = ret;
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL(max8998_read_reg);
 
 
-static int max8998_i2c_device_write(struct max8998_dev *max8998, u8 reg, u8 value)
+int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
 {
 {
-	struct i2c_client *client = max8998->i2c_client;
+	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+	int ret;
+
+	mutex_lock(&max8998->iolock);
+	ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
+	mutex_unlock(&max8998->iolock);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(max8998_bulk_read);
+
+int max8998_write_reg(struct i2c_client *i2c, u8 reg, u8 value)
+{
+	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 	int ret;
 	int ret;
 
 
 	mutex_lock(&max8998->iolock);
 	mutex_lock(&max8998->iolock);
-	ret = i2c_smbus_write_byte_data(client, reg, value);
+	ret = i2c_smbus_write_byte_data(i2c, reg, value);
 	mutex_unlock(&max8998->iolock);
 	mutex_unlock(&max8998->iolock);
 	return ret;
 	return ret;
 }
 }
+EXPORT_SYMBOL(max8998_write_reg);
 
 
-static int max8998_i2c_device_update(struct max8998_dev *max8998, u8 reg,
-				     u8 val, u8 mask)
+int max8998_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
 {
 {
-	struct i2c_client *client = max8998->i2c_client;
+	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+	int ret;
+
+	mutex_lock(&max8998->iolock);
+	ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
+	mutex_unlock(&max8998->iolock);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(max8998_bulk_write);
+
+int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
+{
+	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 	int ret;
 	int ret;
 
 
 	mutex_lock(&max8998->iolock);
 	mutex_lock(&max8998->iolock);
-	ret = i2c_smbus_read_byte_data(client, reg);
+	ret = i2c_smbus_read_byte_data(i2c, reg);
 	if (ret >= 0) {
 	if (ret >= 0) {
 		u8 old_val = ret & 0xff;
 		u8 old_val = ret & 0xff;
 		u8 new_val = (val & mask) | (old_val & (~mask));
 		u8 new_val = (val & mask) | (old_val & (~mask));
-		ret = i2c_smbus_write_byte_data(client, reg, new_val);
-		if (ret >= 0)
-			ret = 0;
+		ret = i2c_smbus_write_byte_data(i2c, reg, new_val);
 	}
 	}
 	mutex_unlock(&max8998->iolock);
 	mutex_unlock(&max8998->iolock);
 	return ret;
 	return ret;
 }
 }
+EXPORT_SYMBOL(max8998_update_reg);
 
 
 static int max8998_i2c_probe(struct i2c_client *i2c,
 static int max8998_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 			    const struct i2c_device_id *id)
 {
 {
+	struct max8998_platform_data *pdata = i2c->dev.platform_data;
 	struct max8998_dev *max8998;
 	struct max8998_dev *max8998;
 	int ret = 0;
 	int ret = 0;
 
 
@@ -94,12 +129,20 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
 
 
 	i2c_set_clientdata(i2c, max8998);
 	i2c_set_clientdata(i2c, max8998);
 	max8998->dev = &i2c->dev;
 	max8998->dev = &i2c->dev;
-	max8998->i2c_client = i2c;
-	max8998->dev_read = max8998_i2c_device_read;
-	max8998->dev_write = max8998_i2c_device_write;
-	max8998->dev_update = max8998_i2c_device_update;
+	max8998->i2c = i2c;
+	max8998->irq = i2c->irq;
+	max8998->type = id->driver_data;
+	if (pdata) {
+		max8998->ono = pdata->ono;
+		max8998->irq_base = pdata->irq_base;
+	}
 	mutex_init(&max8998->iolock);
 	mutex_init(&max8998->iolock);
 
 
+	max8998->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+	i2c_set_clientdata(max8998->rtc, max8998);
+
+	max8998_irq_init(max8998);
+
 	ret = mfd_add_devices(max8998->dev, -1,
 	ret = mfd_add_devices(max8998->dev, -1,
 			      max8998_devs, ARRAY_SIZE(max8998_devs),
 			      max8998_devs, ARRAY_SIZE(max8998_devs),
 			      NULL, 0);
 			      NULL, 0);
@@ -110,6 +153,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
 
 
 err:
 err:
 	mfd_remove_devices(max8998->dev);
 	mfd_remove_devices(max8998->dev);
+	max8998_irq_exit(max8998);
+	i2c_unregister_device(max8998->rtc);
 	kfree(max8998);
 	kfree(max8998);
 	return ret;
 	return ret;
 }
 }
@@ -119,14 +164,17 @@ static int max8998_i2c_remove(struct i2c_client *i2c)
 	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 
 
 	mfd_remove_devices(max8998->dev);
 	mfd_remove_devices(max8998->dev);
+	max8998_irq_exit(max8998);
+	i2c_unregister_device(max8998->rtc);
 	kfree(max8998);
 	kfree(max8998);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static const struct i2c_device_id max8998_i2c_id[] = {
 static const struct i2c_device_id max8998_i2c_id[] = {
-       { "max8998", 0 },
-       { }
+	{ "max8998", TYPE_MAX8998 },
+	{ "lp3974", TYPE_LP3974},
+	{ }
 };
 };
 MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
 MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
 
 

+ 0 - 752
drivers/mfd/mc13783-core.c

@@ -1,752 +0,0 @@
-/*
- * Copyright 2009 Pengutronix
- * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
- *
- * loosely based on an earlier driver that has
- * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License version 2 as published by the
- * Free Software Foundation.
- */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/mc13783.h>
-
-struct mc13783 {
-	struct spi_device *spidev;
-	struct mutex lock;
-	int irq;
-	int flags;
-
-	irq_handler_t irqhandler[MC13783_NUM_IRQ];
-	void *irqdata[MC13783_NUM_IRQ];
-
-	/* XXX these should go as platformdata to the regulator subdevice */
-	struct mc13783_regulator_init_data *regulators;
-	int num_regulators;
-};
-
-#define MC13783_REG_REVISION			 7
-#define MC13783_REG_ADC_0			43
-#define MC13783_REG_ADC_1			44
-#define MC13783_REG_ADC_2			45
-
-#define MC13783_IRQSTAT0	0
-#define MC13783_IRQSTAT0_ADCDONEI	(1 << 0)
-#define MC13783_IRQSTAT0_ADCBISDONEI	(1 << 1)
-#define MC13783_IRQSTAT0_TSI		(1 << 2)
-#define MC13783_IRQSTAT0_WHIGHI		(1 << 3)
-#define MC13783_IRQSTAT0_WLOWI		(1 << 4)
-#define MC13783_IRQSTAT0_CHGDETI	(1 << 6)
-#define MC13783_IRQSTAT0_CHGOVI		(1 << 7)
-#define MC13783_IRQSTAT0_CHGREVI	(1 << 8)
-#define MC13783_IRQSTAT0_CHGSHORTI	(1 << 9)
-#define MC13783_IRQSTAT0_CCCVI		(1 << 10)
-#define MC13783_IRQSTAT0_CHGCURRI	(1 << 11)
-#define MC13783_IRQSTAT0_BPONI		(1 << 12)
-#define MC13783_IRQSTAT0_LOBATLI	(1 << 13)
-#define MC13783_IRQSTAT0_LOBATHI	(1 << 14)
-#define MC13783_IRQSTAT0_UDPI		(1 << 15)
-#define MC13783_IRQSTAT0_USBI		(1 << 16)
-#define MC13783_IRQSTAT0_IDI		(1 << 19)
-#define MC13783_IRQSTAT0_SE1I		(1 << 21)
-#define MC13783_IRQSTAT0_CKDETI		(1 << 22)
-#define MC13783_IRQSTAT0_UDMI		(1 << 23)
-
-#define MC13783_IRQMASK0	1
-#define MC13783_IRQMASK0_ADCDONEM	MC13783_IRQSTAT0_ADCDONEI
-#define MC13783_IRQMASK0_ADCBISDONEM	MC13783_IRQSTAT0_ADCBISDONEI
-#define MC13783_IRQMASK0_TSM		MC13783_IRQSTAT0_TSI
-#define MC13783_IRQMASK0_WHIGHM		MC13783_IRQSTAT0_WHIGHI
-#define MC13783_IRQMASK0_WLOWM		MC13783_IRQSTAT0_WLOWI
-#define MC13783_IRQMASK0_CHGDETM	MC13783_IRQSTAT0_CHGDETI
-#define MC13783_IRQMASK0_CHGOVM		MC13783_IRQSTAT0_CHGOVI
-#define MC13783_IRQMASK0_CHGREVM	MC13783_IRQSTAT0_CHGREVI
-#define MC13783_IRQMASK0_CHGSHORTM	MC13783_IRQSTAT0_CHGSHORTI
-#define MC13783_IRQMASK0_CCCVM		MC13783_IRQSTAT0_CCCVI
-#define MC13783_IRQMASK0_CHGCURRM	MC13783_IRQSTAT0_CHGCURRI
-#define MC13783_IRQMASK0_BPONM		MC13783_IRQSTAT0_BPONI
-#define MC13783_IRQMASK0_LOBATLM	MC13783_IRQSTAT0_LOBATLI
-#define MC13783_IRQMASK0_LOBATHM	MC13783_IRQSTAT0_LOBATHI
-#define MC13783_IRQMASK0_UDPM		MC13783_IRQSTAT0_UDPI
-#define MC13783_IRQMASK0_USBM		MC13783_IRQSTAT0_USBI
-#define MC13783_IRQMASK0_IDM		MC13783_IRQSTAT0_IDI
-#define MC13783_IRQMASK0_SE1M		MC13783_IRQSTAT0_SE1I
-#define MC13783_IRQMASK0_CKDETM		MC13783_IRQSTAT0_CKDETI
-#define MC13783_IRQMASK0_UDMM		MC13783_IRQSTAT0_UDMI
-
-#define MC13783_IRQSTAT1	3
-#define MC13783_IRQSTAT1_1HZI		(1 << 0)
-#define MC13783_IRQSTAT1_TODAI		(1 << 1)
-#define MC13783_IRQSTAT1_ONOFD1I	(1 << 3)
-#define MC13783_IRQSTAT1_ONOFD2I	(1 << 4)
-#define MC13783_IRQSTAT1_ONOFD3I	(1 << 5)
-#define MC13783_IRQSTAT1_SYSRSTI	(1 << 6)
-#define MC13783_IRQSTAT1_RTCRSTI	(1 << 7)
-#define MC13783_IRQSTAT1_PCI		(1 << 8)
-#define MC13783_IRQSTAT1_WARMI		(1 << 9)
-#define MC13783_IRQSTAT1_MEMHLDI	(1 << 10)
-#define MC13783_IRQSTAT1_PWRRDYI	(1 << 11)
-#define MC13783_IRQSTAT1_THWARNLI	(1 << 12)
-#define MC13783_IRQSTAT1_THWARNHI	(1 << 13)
-#define MC13783_IRQSTAT1_CLKI		(1 << 14)
-#define MC13783_IRQSTAT1_SEMAFI		(1 << 15)
-#define MC13783_IRQSTAT1_MC2BI		(1 << 17)
-#define MC13783_IRQSTAT1_HSDETI		(1 << 18)
-#define MC13783_IRQSTAT1_HSLI		(1 << 19)
-#define MC13783_IRQSTAT1_ALSPTHI	(1 << 20)
-#define MC13783_IRQSTAT1_AHSSHORTI	(1 << 21)
-
-#define MC13783_IRQMASK1	4
-#define MC13783_IRQMASK1_1HZM		MC13783_IRQSTAT1_1HZI
-#define MC13783_IRQMASK1_TODAM		MC13783_IRQSTAT1_TODAI
-#define MC13783_IRQMASK1_ONOFD1M	MC13783_IRQSTAT1_ONOFD1I
-#define MC13783_IRQMASK1_ONOFD2M	MC13783_IRQSTAT1_ONOFD2I
-#define MC13783_IRQMASK1_ONOFD3M	MC13783_IRQSTAT1_ONOFD3I
-#define MC13783_IRQMASK1_SYSRSTM	MC13783_IRQSTAT1_SYSRSTI
-#define MC13783_IRQMASK1_RTCRSTM	MC13783_IRQSTAT1_RTCRSTI
-#define MC13783_IRQMASK1_PCM		MC13783_IRQSTAT1_PCI
-#define MC13783_IRQMASK1_WARMM		MC13783_IRQSTAT1_WARMI
-#define MC13783_IRQMASK1_MEMHLDM	MC13783_IRQSTAT1_MEMHLDI
-#define MC13783_IRQMASK1_PWRRDYM	MC13783_IRQSTAT1_PWRRDYI
-#define MC13783_IRQMASK1_THWARNLM	MC13783_IRQSTAT1_THWARNLI
-#define MC13783_IRQMASK1_THWARNHM	MC13783_IRQSTAT1_THWARNHI
-#define MC13783_IRQMASK1_CLKM		MC13783_IRQSTAT1_CLKI
-#define MC13783_IRQMASK1_SEMAFM		MC13783_IRQSTAT1_SEMAFI
-#define MC13783_IRQMASK1_MC2BM		MC13783_IRQSTAT1_MC2BI
-#define MC13783_IRQMASK1_HSDETM		MC13783_IRQSTAT1_HSDETI
-#define MC13783_IRQMASK1_HSLM		MC13783_IRQSTAT1_HSLI
-#define MC13783_IRQMASK1_ALSPTHM	MC13783_IRQSTAT1_ALSPTHI
-#define MC13783_IRQMASK1_AHSSHORTM	MC13783_IRQSTAT1_AHSSHORTI
-
-#define MC13783_ADC1		44
-#define MC13783_ADC1_ADEN		(1 << 0)
-#define MC13783_ADC1_RAND		(1 << 1)
-#define MC13783_ADC1_ADSEL		(1 << 3)
-#define MC13783_ADC1_ASC		(1 << 20)
-#define MC13783_ADC1_ADTRIGIGN		(1 << 21)
-
-#define MC13783_NUMREGS 0x3f
-
-void mc13783_lock(struct mc13783 *mc13783)
-{
-	if (!mutex_trylock(&mc13783->lock)) {
-		dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n",
-				__func__, __builtin_return_address(0));
-
-		mutex_lock(&mc13783->lock);
-	}
-	dev_dbg(&mc13783->spidev->dev, "%s from %pf\n",
-			__func__, __builtin_return_address(0));
-}
-EXPORT_SYMBOL(mc13783_lock);
-
-void mc13783_unlock(struct mc13783 *mc13783)
-{
-	dev_dbg(&mc13783->spidev->dev, "%s from %pf\n",
-			__func__, __builtin_return_address(0));
-	mutex_unlock(&mc13783->lock);
-}
-EXPORT_SYMBOL(mc13783_unlock);
-
-#define MC13783_REGOFFSET_SHIFT 25
-int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val)
-{
-	struct spi_transfer t;
-	struct spi_message m;
-	int ret;
-
-	BUG_ON(!mutex_is_locked(&mc13783->lock));
-
-	if (offset > MC13783_NUMREGS)
-		return -EINVAL;
-
-	*val = offset << MC13783_REGOFFSET_SHIFT;
-
-	memset(&t, 0, sizeof(t));
-
-	t.tx_buf = val;
-	t.rx_buf = val;
-	t.len = sizeof(u32);
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t, &m);
-
-	ret = spi_sync(mc13783->spidev, &m);
-
-	/* error in message.status implies error return from spi_sync */
-	BUG_ON(!ret && m.status);
-
-	if (ret)
-		return ret;
-
-	*val &= 0xffffff;
-
-	dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
-
-	return 0;
-}
-EXPORT_SYMBOL(mc13783_reg_read);
-
-int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val)
-{
-	u32 buf;
-	struct spi_transfer t;
-	struct spi_message m;
-	int ret;
-
-	BUG_ON(!mutex_is_locked(&mc13783->lock));
-
-	dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val);
-
-	if (offset > MC13783_NUMREGS || val > 0xffffff)
-		return -EINVAL;
-
-	buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val;
-
-	memset(&t, 0, sizeof(t));
-
-	t.tx_buf = &buf;
-	t.rx_buf = &buf;
-	t.len = sizeof(u32);
-
-	spi_message_init(&m);
-	spi_message_add_tail(&t, &m);
-
-	ret = spi_sync(mc13783->spidev, &m);
-
-	BUG_ON(!ret && m.status);
-
-	if (ret)
-		return ret;
-
-	return 0;
-}
-EXPORT_SYMBOL(mc13783_reg_write);
-
-int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
-		u32 mask, u32 val)
-{
-	int ret;
-	u32 valread;
-
-	BUG_ON(val & ~mask);
-
-	ret = mc13783_reg_read(mc13783, offset, &valread);
-	if (ret)
-		return ret;
-
-	valread = (valread & ~mask) | val;
-
-	return mc13783_reg_write(mc13783, offset, valread);
-}
-EXPORT_SYMBOL(mc13783_reg_rmw);
-
-int mc13783_get_flags(struct mc13783 *mc13783)
-{
-	return mc13783->flags;
-}
-EXPORT_SYMBOL(mc13783_get_flags);
-
-int mc13783_irq_mask(struct mc13783 *mc13783, int irq)
-{
-	int ret;
-	unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
-	u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
-	u32 mask;
-
-	if (irq < 0 || irq >= MC13783_NUM_IRQ)
-		return -EINVAL;
-
-	ret = mc13783_reg_read(mc13783, offmask, &mask);
-	if (ret)
-		return ret;
-
-	if (mask & irqbit)
-		/* already masked */
-		return 0;
-
-	return mc13783_reg_write(mc13783, offmask, mask | irqbit);
-}
-EXPORT_SYMBOL(mc13783_irq_mask);
-
-int mc13783_irq_unmask(struct mc13783 *mc13783, int irq)
-{
-	int ret;
-	unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
-	u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
-	u32 mask;
-
-	if (irq < 0 || irq >= MC13783_NUM_IRQ)
-		return -EINVAL;
-
-	ret = mc13783_reg_read(mc13783, offmask, &mask);
-	if (ret)
-		return ret;
-
-	if (!(mask & irqbit))
-		/* already unmasked */
-		return 0;
-
-	return mc13783_reg_write(mc13783, offmask, mask & ~irqbit);
-}
-EXPORT_SYMBOL(mc13783_irq_unmask);
-
-int mc13783_irq_status(struct mc13783 *mc13783, int irq,
-		int *enabled, int *pending)
-{
-	int ret;
-	unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1;
-	unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1;
-	u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
-
-	if (irq < 0 || irq >= MC13783_NUM_IRQ)
-		return -EINVAL;
-
-	if (enabled) {
-		u32 mask;
-
-		ret = mc13783_reg_read(mc13783, offmask, &mask);
-		if (ret)
-			return ret;
-
-		*enabled = mask & irqbit;
-	}
-
-	if (pending) {
-		u32 stat;
-
-		ret = mc13783_reg_read(mc13783, offstat, &stat);
-		if (ret)
-			return ret;
-
-		*pending = stat & irqbit;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(mc13783_irq_status);
-
-int mc13783_irq_ack(struct mc13783 *mc13783, int irq)
-{
-	unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1;
-	unsigned int val = 1 << (irq < 24 ? irq : irq - 24);
-
-	BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ);
-
-	return mc13783_reg_write(mc13783, offstat, val);
-}
-EXPORT_SYMBOL(mc13783_irq_ack);
-
-int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,
-		irq_handler_t handler, const char *name, void *dev)
-{
-	BUG_ON(!mutex_is_locked(&mc13783->lock));
-	BUG_ON(!handler);
-
-	if (irq < 0 || irq >= MC13783_NUM_IRQ)
-		return -EINVAL;
-
-	if (mc13783->irqhandler[irq])
-		return -EBUSY;
-
-	mc13783->irqhandler[irq] = handler;
-	mc13783->irqdata[irq] = dev;
-
-	return 0;
-}
-EXPORT_SYMBOL(mc13783_irq_request_nounmask);
-
-int mc13783_irq_request(struct mc13783 *mc13783, int irq,
-		irq_handler_t handler, const char *name, void *dev)
-{
-	int ret;
-
-	ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev);
-	if (ret)
-		return ret;
-
-	ret = mc13783_irq_unmask(mc13783, irq);
-	if (ret) {
-		mc13783->irqhandler[irq] = NULL;
-		mc13783->irqdata[irq] = NULL;
-		return ret;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(mc13783_irq_request);
-
-int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev)
-{
-	int ret;
-	BUG_ON(!mutex_is_locked(&mc13783->lock));
-
-	if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] ||
-			mc13783->irqdata[irq] != dev)
-		return -EINVAL;
-
-	ret = mc13783_irq_mask(mc13783, irq);
-	if (ret)
-		return ret;
-
-	mc13783->irqhandler[irq] = NULL;
-	mc13783->irqdata[irq] = NULL;
-
-	return 0;
-}
-EXPORT_SYMBOL(mc13783_irq_free);
-
-static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq)
-{
-	return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]);
-}
-
-/*
- * returns: number of handled irqs or negative error
- * locking: holds mc13783->lock
- */
-static int mc13783_irq_handle(struct mc13783 *mc13783,
-		unsigned int offstat, unsigned int offmask, int baseirq)
-{
-	u32 stat, mask;
-	int ret = mc13783_reg_read(mc13783, offstat, &stat);
-	int num_handled = 0;
-
-	if (ret)
-		return ret;
-
-	ret = mc13783_reg_read(mc13783, offmask, &mask);
-	if (ret)
-		return ret;
-
-	while (stat & ~mask) {
-		int irq = __ffs(stat & ~mask);
-
-		stat &= ~(1 << irq);
-
-		if (likely(mc13783->irqhandler[baseirq + irq])) {
-			irqreturn_t handled;
-
-			handled = mc13783_irqhandler(mc13783, baseirq + irq);
-			if (handled == IRQ_HANDLED)
-				num_handled++;
-		} else {
-			dev_err(&mc13783->spidev->dev,
-					"BUG: irq %u but no handler\n",
-					baseirq + irq);
-
-			mask |= 1 << irq;
-
-			ret = mc13783_reg_write(mc13783, offmask, mask);
-		}
-	}
-
-	return num_handled;
-}
-
-static irqreturn_t mc13783_irq_thread(int irq, void *data)
-{
-	struct mc13783 *mc13783 = data;
-	irqreturn_t ret;
-	int handled = 0;
-
-	mc13783_lock(mc13783);
-
-	ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0,
-			MC13783_IRQMASK0, MC13783_IRQ_ADCDONE);
-	if (ret > 0)
-		handled = 1;
-
-	ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1,
-			MC13783_IRQMASK1, MC13783_IRQ_1HZ);
-	if (ret > 0)
-		handled = 1;
-
-	mc13783_unlock(mc13783);
-
-	return IRQ_RETVAL(handled);
-}
-
-#define MC13783_ADC1_CHAN0_SHIFT	5
-#define MC13783_ADC1_CHAN1_SHIFT	8
-
-struct mc13783_adcdone_data {
-	struct mc13783 *mc13783;
-	struct completion done;
-};
-
-static irqreturn_t mc13783_handler_adcdone(int irq, void *data)
-{
-	struct mc13783_adcdone_data *adcdone_data = data;
-
-	mc13783_irq_ack(adcdone_data->mc13783, irq);
-
-	complete_all(&adcdone_data->done);
-
-	return IRQ_HANDLED;
-}
-
-#define MC13783_ADC_WORKING (1 << 16)
-
-int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
-		unsigned int channel, unsigned int *sample)
-{
-	u32 adc0, adc1, old_adc0;
-	int i, ret;
-	struct mc13783_adcdone_data adcdone_data = {
-		.mc13783 = mc13783,
-	};
-	init_completion(&adcdone_data.done);
-
-	dev_dbg(&mc13783->spidev->dev, "%s\n", __func__);
-
-	mc13783_lock(mc13783);
-
-	if (mc13783->flags & MC13783_ADC_WORKING) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	mc13783->flags |= MC13783_ADC_WORKING;
-
-	mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0);
-
-	adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2;
-	adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC;
-
-	if (channel > 7)
-		adc1 |= MC13783_ADC1_ADSEL;
-
-	switch (mode) {
-	case MC13783_ADC_MODE_TS:
-		adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 |
-			MC13783_ADC0_TSMOD1;
-		adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
-		break;
-
-	case MC13783_ADC_MODE_SINGLE_CHAN:
-		adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK;
-		adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT;
-		adc1 |= MC13783_ADC1_RAND;
-		break;
-
-	case MC13783_ADC_MODE_MULT_CHAN:
-		adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK;
-		adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
-		break;
-
-	default:
-		mc13783_unlock(mc13783);
-		return -EINVAL;
-	}
-
-	dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__);
-	mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE,
-			mc13783_handler_adcdone, __func__, &adcdone_data);
-	mc13783_irq_ack(mc13783, MC13783_IRQ_ADCDONE);
-
-	mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0);
-	mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1);
-
-	mc13783_unlock(mc13783);
-
-	ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ);
-
-	if (!ret)
-		ret = -ETIMEDOUT;
-
-	mc13783_lock(mc13783);
-
-	mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data);
-
-	if (ret > 0)
-		for (i = 0; i < 4; ++i) {
-			ret = mc13783_reg_read(mc13783,
-					MC13783_REG_ADC_2, &sample[i]);
-			if (ret)
-				break;
-		}
-
-	if (mode == MC13783_ADC_MODE_TS)
-		/* restore TSMOD */
-		mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0);
-
-	mc13783->flags &= ~MC13783_ADC_WORKING;
-out:
-	mc13783_unlock(mc13783);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
-
-static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783,
-		const char *name, void *pdata, size_t pdata_size)
-{
-	struct mfd_cell cell = {
-		.name = name,
-		.platform_data = pdata,
-		.data_size = pdata_size,
-	};
-
-	return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0);
-}
-
-static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name)
-{
-	return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0);
-}
-
-static int mc13783_check_revision(struct mc13783 *mc13783)
-{
-	u32 rev_id, rev1, rev2, finid, icid;
-
-	mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id);
-
-	rev1 = (rev_id & 0x018) >> 3;
-	rev2 = (rev_id & 0x007);
-	icid = (rev_id & 0x01C0) >> 6;
-	finid = (rev_id & 0x01E00) >> 9;
-
-	/* Ver 0.2 is actually 3.2a.  Report as 3.2 */
-	if ((rev1 == 0) && (rev2 == 2))
-		rev1 = 3;
-
-	if (rev1 == 0 || icid != 2) {
-		dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n");
-		return -ENODEV;
-	}
-
-	dev_info(&mc13783->spidev->dev,
-			"MC13783 Rev %d.%d FinVer %x detected\n",
-			rev1, rev2, finid);
-
-	return 0;
-}
-
-static int mc13783_probe(struct spi_device *spi)
-{
-	struct mc13783 *mc13783;
-	struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev);
-	int ret;
-
-	mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL);
-	if (!mc13783)
-		return -ENOMEM;
-
-	dev_set_drvdata(&spi->dev, mc13783);
-	spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
-	spi->bits_per_word = 32;
-	spi_setup(spi);
-
-	mc13783->spidev = spi;
-
-	mutex_init(&mc13783->lock);
-	mc13783_lock(mc13783);
-
-	ret = mc13783_check_revision(mc13783);
-	if (ret)
-		goto err_revision;
-
-	/* mask all irqs */
-	ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff);
-	if (ret)
-		goto err_mask;
-
-	ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff);
-	if (ret)
-		goto err_mask;
-
-	ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread,
-			IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783);
-
-	if (ret) {
-err_mask:
-err_revision:
-		mutex_unlock(&mc13783->lock);
-		dev_set_drvdata(&spi->dev, NULL);
-		kfree(mc13783);
-		return ret;
-	}
-
-	/* This should go away (BEGIN) */
-	if (pdata) {
-		mc13783->flags = pdata->flags;
-		mc13783->regulators = pdata->regulators;
-		mc13783->num_regulators = pdata->num_regulators;
-	}
-	/* This should go away (END) */
-
-	mc13783_unlock(mc13783);
-
-	if (pdata->flags & MC13783_USE_ADC)
-		mc13783_add_subdevice(mc13783, "mc13783-adc");
-
-	if (pdata->flags & MC13783_USE_CODEC)
-		mc13783_add_subdevice(mc13783, "mc13783-codec");
-
-	if (pdata->flags & MC13783_USE_REGULATOR) {
-		struct mc13783_regulator_platform_data regulator_pdata = {
-			.num_regulators = pdata->num_regulators,
-			.regulators = pdata->regulators,
-		};
-
-		mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator",
-				&regulator_pdata, sizeof(regulator_pdata));
-	}
-
-	if (pdata->flags & MC13783_USE_RTC)
-		mc13783_add_subdevice(mc13783, "mc13783-rtc");
-
-	if (pdata->flags & MC13783_USE_TOUCHSCREEN)
-		mc13783_add_subdevice(mc13783, "mc13783-ts");
-
-	if (pdata->flags & MC13783_USE_LED)
-		mc13783_add_subdevice_pdata(mc13783, "mc13783-led",
-					pdata->leds, sizeof(*pdata->leds));
-
-	return 0;
-}
-
-static int __devexit mc13783_remove(struct spi_device *spi)
-{
-	struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev);
-
-	free_irq(mc13783->spidev->irq, mc13783);
-
-	mfd_remove_devices(&spi->dev);
-
-	return 0;
-}
-
-static struct spi_driver mc13783_driver = {
-	.driver = {
-		.name = "mc13783",
-		.bus = &spi_bus_type,
-		.owner = THIS_MODULE,
-	},
-	.probe = mc13783_probe,
-	.remove = __devexit_p(mc13783_remove),
-};
-
-static int __init mc13783_init(void)
-{
-	return spi_register_driver(&mc13783_driver);
-}
-subsys_initcall(mc13783_init);
-
-static void __exit mc13783_exit(void)
-{
-	spi_unregister_driver(&mc13783_driver);
-}
-module_exit(mc13783_exit);
-
-MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC");
-MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
-MODULE_LICENSE("GPL v2");

+ 840 - 0
drivers/mfd/mc13xxx-core.c

@@ -0,0 +1,840 @@
+/*
+ * Copyright 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * loosely based on an earlier driver that has
+ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mc13xxx.h>
+
+struct mc13xxx {
+	struct spi_device *spidev;
+	struct mutex lock;
+	int irq;
+
+	irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
+	void *irqdata[MC13XXX_NUM_IRQ];
+};
+
+struct mc13783 {
+	struct mc13xxx mc13xxx;
+
+	int adcflags;
+};
+
+struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783)
+{
+	return &mc13783->mc13xxx;
+}
+EXPORT_SYMBOL(mc13783_to_mc13xxx);
+
+#define MC13XXX_IRQSTAT0	0
+#define MC13XXX_IRQSTAT0_ADCDONEI	(1 << 0)
+#define MC13XXX_IRQSTAT0_ADCBISDONEI	(1 << 1)
+#define MC13XXX_IRQSTAT0_TSI		(1 << 2)
+#define MC13783_IRQSTAT0_WHIGHI		(1 << 3)
+#define MC13783_IRQSTAT0_WLOWI		(1 << 4)
+#define MC13XXX_IRQSTAT0_CHGDETI	(1 << 6)
+#define MC13783_IRQSTAT0_CHGOVI		(1 << 7)
+#define MC13XXX_IRQSTAT0_CHGREVI	(1 << 8)
+#define MC13XXX_IRQSTAT0_CHGSHORTI	(1 << 9)
+#define MC13XXX_IRQSTAT0_CCCVI		(1 << 10)
+#define MC13XXX_IRQSTAT0_CHGCURRI	(1 << 11)
+#define MC13XXX_IRQSTAT0_BPONI		(1 << 12)
+#define MC13XXX_IRQSTAT0_LOBATLI	(1 << 13)
+#define MC13XXX_IRQSTAT0_LOBATHI	(1 << 14)
+#define MC13783_IRQSTAT0_UDPI		(1 << 15)
+#define MC13783_IRQSTAT0_USBI		(1 << 16)
+#define MC13783_IRQSTAT0_IDI		(1 << 19)
+#define MC13783_IRQSTAT0_SE1I		(1 << 21)
+#define MC13783_IRQSTAT0_CKDETI		(1 << 22)
+#define MC13783_IRQSTAT0_UDMI		(1 << 23)
+
+#define MC13XXX_IRQMASK0	1
+#define MC13XXX_IRQMASK0_ADCDONEM	MC13XXX_IRQSTAT0_ADCDONEI
+#define MC13XXX_IRQMASK0_ADCBISDONEM	MC13XXX_IRQSTAT0_ADCBISDONEI
+#define MC13XXX_IRQMASK0_TSM		MC13XXX_IRQSTAT0_TSI
+#define MC13783_IRQMASK0_WHIGHM		MC13783_IRQSTAT0_WHIGHI
+#define MC13783_IRQMASK0_WLOWM		MC13783_IRQSTAT0_WLOWI
+#define MC13XXX_IRQMASK0_CHGDETM	MC13XXX_IRQSTAT0_CHGDETI
+#define MC13783_IRQMASK0_CHGOVM		MC13783_IRQSTAT0_CHGOVI
+#define MC13XXX_IRQMASK0_CHGREVM	MC13XXX_IRQSTAT0_CHGREVI
+#define MC13XXX_IRQMASK0_CHGSHORTM	MC13XXX_IRQSTAT0_CHGSHORTI
+#define MC13XXX_IRQMASK0_CCCVM		MC13XXX_IRQSTAT0_CCCVI
+#define MC13XXX_IRQMASK0_CHGCURRM	MC13XXX_IRQSTAT0_CHGCURRI
+#define MC13XXX_IRQMASK0_BPONM		MC13XXX_IRQSTAT0_BPONI
+#define MC13XXX_IRQMASK0_LOBATLM	MC13XXX_IRQSTAT0_LOBATLI
+#define MC13XXX_IRQMASK0_LOBATHM	MC13XXX_IRQSTAT0_LOBATHI
+#define MC13783_IRQMASK0_UDPM		MC13783_IRQSTAT0_UDPI
+#define MC13783_IRQMASK0_USBM		MC13783_IRQSTAT0_USBI
+#define MC13783_IRQMASK0_IDM		MC13783_IRQSTAT0_IDI
+#define MC13783_IRQMASK0_SE1M		MC13783_IRQSTAT0_SE1I
+#define MC13783_IRQMASK0_CKDETM		MC13783_IRQSTAT0_CKDETI
+#define MC13783_IRQMASK0_UDMM		MC13783_IRQSTAT0_UDMI
+
+#define MC13XXX_IRQSTAT1	3
+#define MC13XXX_IRQSTAT1_1HZI		(1 << 0)
+#define MC13XXX_IRQSTAT1_TODAI		(1 << 1)
+#define MC13783_IRQSTAT1_ONOFD1I	(1 << 3)
+#define MC13783_IRQSTAT1_ONOFD2I	(1 << 4)
+#define MC13783_IRQSTAT1_ONOFD3I	(1 << 5)
+#define MC13XXX_IRQSTAT1_SYSRSTI	(1 << 6)
+#define MC13XXX_IRQSTAT1_RTCRSTI	(1 << 7)
+#define MC13XXX_IRQSTAT1_PCI		(1 << 8)
+#define MC13XXX_IRQSTAT1_WARMI		(1 << 9)
+#define MC13XXX_IRQSTAT1_MEMHLDI	(1 << 10)
+#define MC13783_IRQSTAT1_PWRRDYI	(1 << 11)
+#define MC13XXX_IRQSTAT1_THWARNLI	(1 << 12)
+#define MC13XXX_IRQSTAT1_THWARNHI	(1 << 13)
+#define MC13XXX_IRQSTAT1_CLKI		(1 << 14)
+#define MC13783_IRQSTAT1_SEMAFI		(1 << 15)
+#define MC13783_IRQSTAT1_MC2BI		(1 << 17)
+#define MC13783_IRQSTAT1_HSDETI		(1 << 18)
+#define MC13783_IRQSTAT1_HSLI		(1 << 19)
+#define MC13783_IRQSTAT1_ALSPTHI	(1 << 20)
+#define MC13783_IRQSTAT1_AHSSHORTI	(1 << 21)
+
+#define MC13XXX_IRQMASK1	4
+#define MC13XXX_IRQMASK1_1HZM		MC13XXX_IRQSTAT1_1HZI
+#define MC13XXX_IRQMASK1_TODAM		MC13XXX_IRQSTAT1_TODAI
+#define MC13783_IRQMASK1_ONOFD1M	MC13783_IRQSTAT1_ONOFD1I
+#define MC13783_IRQMASK1_ONOFD2M	MC13783_IRQSTAT1_ONOFD2I
+#define MC13783_IRQMASK1_ONOFD3M	MC13783_IRQSTAT1_ONOFD3I
+#define MC13XXX_IRQMASK1_SYSRSTM	MC13XXX_IRQSTAT1_SYSRSTI
+#define MC13XXX_IRQMASK1_RTCRSTM	MC13XXX_IRQSTAT1_RTCRSTI
+#define MC13XXX_IRQMASK1_PCM		MC13XXX_IRQSTAT1_PCI
+#define MC13XXX_IRQMASK1_WARMM		MC13XXX_IRQSTAT1_WARMI
+#define MC13XXX_IRQMASK1_MEMHLDM	MC13XXX_IRQSTAT1_MEMHLDI
+#define MC13783_IRQMASK1_PWRRDYM	MC13783_IRQSTAT1_PWRRDYI
+#define MC13XXX_IRQMASK1_THWARNLM	MC13XXX_IRQSTAT1_THWARNLI
+#define MC13XXX_IRQMASK1_THWARNHM	MC13XXX_IRQSTAT1_THWARNHI
+#define MC13XXX_IRQMASK1_CLKM		MC13XXX_IRQSTAT1_CLKI
+#define MC13783_IRQMASK1_SEMAFM		MC13783_IRQSTAT1_SEMAFI
+#define MC13783_IRQMASK1_MC2BM		MC13783_IRQSTAT1_MC2BI
+#define MC13783_IRQMASK1_HSDETM		MC13783_IRQSTAT1_HSDETI
+#define MC13783_IRQMASK1_HSLM		MC13783_IRQSTAT1_HSLI
+#define MC13783_IRQMASK1_ALSPTHM	MC13783_IRQSTAT1_ALSPTHI
+#define MC13783_IRQMASK1_AHSSHORTM	MC13783_IRQSTAT1_AHSSHORTI
+
+#define MC13XXX_REVISION	7
+#define MC13XXX_REVISION_REVMETAL	(0x07 <<  0)
+#define MC13XXX_REVISION_REVFULL	(0x03 <<  3)
+#define MC13XXX_REVISION_ICID		(0x07 <<  6)
+#define MC13XXX_REVISION_FIN		(0x03 <<  9)
+#define MC13XXX_REVISION_FAB		(0x03 << 11)
+#define MC13XXX_REVISION_ICIDCODE	(0x3f << 13)
+
+#define MC13783_ADC1		44
+#define MC13783_ADC1_ADEN		(1 << 0)
+#define MC13783_ADC1_RAND		(1 << 1)
+#define MC13783_ADC1_ADSEL		(1 << 3)
+#define MC13783_ADC1_ASC		(1 << 20)
+#define MC13783_ADC1_ADTRIGIGN		(1 << 21)
+
+#define MC13783_ADC2		45
+
+#define MC13XXX_NUMREGS 0x3f
+
+void mc13xxx_lock(struct mc13xxx *mc13xxx)
+{
+	if (!mutex_trylock(&mc13xxx->lock)) {
+		dev_dbg(&mc13xxx->spidev->dev, "wait for %s from %pf\n",
+				__func__, __builtin_return_address(0));
+
+		mutex_lock(&mc13xxx->lock);
+	}
+	dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n",
+			__func__, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(mc13xxx_lock);
+
+void mc13xxx_unlock(struct mc13xxx *mc13xxx)
+{
+	dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n",
+			__func__, __builtin_return_address(0));
+	mutex_unlock(&mc13xxx->lock);
+}
+EXPORT_SYMBOL(mc13xxx_unlock);
+
+#define MC13XXX_REGOFFSET_SHIFT 25
+int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
+{
+	struct spi_transfer t;
+	struct spi_message m;
+	int ret;
+
+	BUG_ON(!mutex_is_locked(&mc13xxx->lock));
+
+	if (offset > MC13XXX_NUMREGS)
+		return -EINVAL;
+
+	*val = offset << MC13XXX_REGOFFSET_SHIFT;
+
+	memset(&t, 0, sizeof(t));
+
+	t.tx_buf = val;
+	t.rx_buf = val;
+	t.len = sizeof(u32);
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	ret = spi_sync(mc13xxx->spidev, &m);
+
+	/* error in message.status implies error return from spi_sync */
+	BUG_ON(!ret && m.status);
+
+	if (ret)
+		return ret;
+
+	*val &= 0xffffff;
+
+	dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
+
+	return 0;
+}
+EXPORT_SYMBOL(mc13xxx_reg_read);
+
+int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
+{
+	u32 buf;
+	struct spi_transfer t;
+	struct spi_message m;
+	int ret;
+
+	BUG_ON(!mutex_is_locked(&mc13xxx->lock));
+
+	dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val);
+
+	if (offset > MC13XXX_NUMREGS || val > 0xffffff)
+		return -EINVAL;
+
+	buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val;
+
+	memset(&t, 0, sizeof(t));
+
+	t.tx_buf = &buf;
+	t.rx_buf = &buf;
+	t.len = sizeof(u32);
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	ret = spi_sync(mc13xxx->spidev, &m);
+
+	BUG_ON(!ret && m.status);
+
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(mc13xxx_reg_write);
+
+int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
+		u32 mask, u32 val)
+{
+	int ret;
+	u32 valread;
+
+	BUG_ON(val & ~mask);
+
+	ret = mc13xxx_reg_read(mc13xxx, offset, &valread);
+	if (ret)
+		return ret;
+
+	valread = (valread & ~mask) | val;
+
+	return mc13xxx_reg_write(mc13xxx, offset, valread);
+}
+EXPORT_SYMBOL(mc13xxx_reg_rmw);
+
+int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq)
+{
+	int ret;
+	unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
+	u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+	u32 mask;
+
+	if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
+		return -EINVAL;
+
+	ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
+	if (ret)
+		return ret;
+
+	if (mask & irqbit)
+		/* already masked */
+		return 0;
+
+	return mc13xxx_reg_write(mc13xxx, offmask, mask | irqbit);
+}
+EXPORT_SYMBOL(mc13xxx_irq_mask);
+
+int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq)
+{
+	int ret;
+	unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
+	u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+	u32 mask;
+
+	if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
+		return -EINVAL;
+
+	ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
+	if (ret)
+		return ret;
+
+	if (!(mask & irqbit))
+		/* already unmasked */
+		return 0;
+
+	return mc13xxx_reg_write(mc13xxx, offmask, mask & ~irqbit);
+}
+EXPORT_SYMBOL(mc13xxx_irq_unmask);
+
+int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq,
+		int *enabled, int *pending)
+{
+	int ret;
+	unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
+	unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1;
+	u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+
+	if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
+		return -EINVAL;
+
+	if (enabled) {
+		u32 mask;
+
+		ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
+		if (ret)
+			return ret;
+
+		*enabled = mask & irqbit;
+	}
+
+	if (pending) {
+		u32 stat;
+
+		ret = mc13xxx_reg_read(mc13xxx, offstat, &stat);
+		if (ret)
+			return ret;
+
+		*pending = stat & irqbit;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(mc13xxx_irq_status);
+
+int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq)
+{
+	unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1;
+	unsigned int val = 1 << (irq < 24 ? irq : irq - 24);
+
+	BUG_ON(irq < 0 || irq >= MC13XXX_NUM_IRQ);
+
+	return mc13xxx_reg_write(mc13xxx, offstat, val);
+}
+EXPORT_SYMBOL(mc13xxx_irq_ack);
+
+int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq,
+		irq_handler_t handler, const char *name, void *dev)
+{
+	BUG_ON(!mutex_is_locked(&mc13xxx->lock));
+	BUG_ON(!handler);
+
+	if (irq < 0 || irq >= MC13XXX_NUM_IRQ)
+		return -EINVAL;
+
+	if (mc13xxx->irqhandler[irq])
+		return -EBUSY;
+
+	mc13xxx->irqhandler[irq] = handler;
+	mc13xxx->irqdata[irq] = dev;
+
+	return 0;
+}
+EXPORT_SYMBOL(mc13xxx_irq_request_nounmask);
+
+int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq,
+		irq_handler_t handler, const char *name, void *dev)
+{
+	int ret;
+
+	ret = mc13xxx_irq_request_nounmask(mc13xxx, irq, handler, name, dev);
+	if (ret)
+		return ret;
+
+	ret = mc13xxx_irq_unmask(mc13xxx, irq);
+	if (ret) {
+		mc13xxx->irqhandler[irq] = NULL;
+		mc13xxx->irqdata[irq] = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(mc13xxx_irq_request);
+
+int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev)
+{
+	int ret;
+	BUG_ON(!mutex_is_locked(&mc13xxx->lock));
+
+	if (irq < 0 || irq >= MC13XXX_NUM_IRQ || !mc13xxx->irqhandler[irq] ||
+			mc13xxx->irqdata[irq] != dev)
+		return -EINVAL;
+
+	ret = mc13xxx_irq_mask(mc13xxx, irq);
+	if (ret)
+		return ret;
+
+	mc13xxx->irqhandler[irq] = NULL;
+	mc13xxx->irqdata[irq] = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(mc13xxx_irq_free);
+
+static inline irqreturn_t mc13xxx_irqhandler(struct mc13xxx *mc13xxx, int irq)
+{
+	return mc13xxx->irqhandler[irq](irq, mc13xxx->irqdata[irq]);
+}
+
+/*
+ * returns: number of handled irqs or negative error
+ * locking: holds mc13xxx->lock
+ */
+static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx,
+		unsigned int offstat, unsigned int offmask, int baseirq)
+{
+	u32 stat, mask;
+	int ret = mc13xxx_reg_read(mc13xxx, offstat, &stat);
+	int num_handled = 0;
+
+	if (ret)
+		return ret;
+
+	ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
+	if (ret)
+		return ret;
+
+	while (stat & ~mask) {
+		int irq = __ffs(stat & ~mask);
+
+		stat &= ~(1 << irq);
+
+		if (likely(mc13xxx->irqhandler[baseirq + irq])) {
+			irqreturn_t handled;
+
+			handled = mc13xxx_irqhandler(mc13xxx, baseirq + irq);
+			if (handled == IRQ_HANDLED)
+				num_handled++;
+		} else {
+			dev_err(&mc13xxx->spidev->dev,
+					"BUG: irq %u but no handler\n",
+					baseirq + irq);
+
+			mask |= 1 << irq;
+
+			ret = mc13xxx_reg_write(mc13xxx, offmask, mask);
+		}
+	}
+
+	return num_handled;
+}
+
+static irqreturn_t mc13xxx_irq_thread(int irq, void *data)
+{
+	struct mc13xxx *mc13xxx = data;
+	irqreturn_t ret;
+	int handled = 0;
+
+	mc13xxx_lock(mc13xxx);
+
+	ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT0,
+			MC13XXX_IRQMASK0, 0);
+	if (ret > 0)
+		handled = 1;
+
+	ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT1,
+			MC13XXX_IRQMASK1, 24);
+	if (ret > 0)
+		handled = 1;
+
+	mc13xxx_unlock(mc13xxx);
+
+	return IRQ_RETVAL(handled);
+}
+
+enum mc13xxx_id {
+	MC13XXX_ID_MC13783,
+	MC13XXX_ID_MC13892,
+	MC13XXX_ID_INVALID,
+};
+
+const char *mc13xxx_chipname[] = {
+	[MC13XXX_ID_MC13783] = "mc13783",
+	[MC13XXX_ID_MC13892] = "mc13892",
+};
+
+#define maskval(reg, mask)	(((reg) & (mask)) >> __ffs(mask))
+static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id)
+{
+	u32 icid;
+	u32 revision;
+	const char *name;
+	int ret;
+
+	ret = mc13xxx_reg_read(mc13xxx, 46, &icid);
+	if (ret)
+		return ret;
+
+	icid = (icid >> 6) & 0x7;
+
+	switch (icid) {
+	case 2:
+		*id = MC13XXX_ID_MC13783;
+		name = "mc13783";
+		break;
+	case 7:
+		*id = MC13XXX_ID_MC13892;
+		name = "mc13892";
+		break;
+	default:
+		*id = MC13XXX_ID_INVALID;
+		break;
+	}
+
+	if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) {
+		ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
+		if (ret)
+			return ret;
+
+		dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, "
+				"fin: %d, fab: %d, icid: %d/%d\n",
+				mc13xxx_chipname[*id],
+				maskval(revision, MC13XXX_REVISION_REVFULL),
+				maskval(revision, MC13XXX_REVISION_REVMETAL),
+				maskval(revision, MC13XXX_REVISION_FIN),
+				maskval(revision, MC13XXX_REVISION_FAB),
+				maskval(revision, MC13XXX_REVISION_ICID),
+				maskval(revision, MC13XXX_REVISION_ICIDCODE));
+	}
+
+	if (*id != MC13XXX_ID_INVALID) {
+		const struct spi_device_id *devid =
+			spi_get_device_id(mc13xxx->spidev);
+		if (!devid || devid->driver_data != *id)
+			dev_warn(&mc13xxx->spidev->dev, "device id doesn't "
+					"match auto detection!\n");
+	}
+
+	return 0;
+}
+
+static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
+{
+	const struct spi_device_id *devid =
+		spi_get_device_id(mc13xxx->spidev);
+
+	if (!devid)
+		return NULL;
+
+	return mc13xxx_chipname[devid->driver_data];
+}
+
+#include <linux/mfd/mc13783.h>
+
+int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
+{
+	struct mc13xxx_platform_data *pdata =
+		dev_get_platdata(&mc13xxx->spidev->dev);
+
+	return pdata->flags;
+}
+EXPORT_SYMBOL(mc13xxx_get_flags);
+
+#define MC13783_ADC1_CHAN0_SHIFT	5
+#define MC13783_ADC1_CHAN1_SHIFT	8
+
+struct mc13xxx_adcdone_data {
+	struct mc13xxx *mc13xxx;
+	struct completion done;
+};
+
+static irqreturn_t mc13783_handler_adcdone(int irq, void *data)
+{
+	struct mc13xxx_adcdone_data *adcdone_data = data;
+
+	mc13xxx_irq_ack(adcdone_data->mc13xxx, irq);
+
+	complete_all(&adcdone_data->done);
+
+	return IRQ_HANDLED;
+}
+
+#define MC13783_ADC_WORKING (1 << 0)
+
+int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
+		unsigned int channel, unsigned int *sample)
+{
+	struct mc13xxx *mc13xxx = &mc13783->mc13xxx;
+	u32 adc0, adc1, old_adc0;
+	int i, ret;
+	struct mc13xxx_adcdone_data adcdone_data = {
+		.mc13xxx = mc13xxx,
+	};
+	init_completion(&adcdone_data.done);
+
+	dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__);
+
+	mc13xxx_lock(mc13xxx);
+
+	if (mc13783->adcflags & MC13783_ADC_WORKING) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	mc13783->adcflags |= MC13783_ADC_WORKING;
+
+	mc13xxx_reg_read(mc13xxx, MC13783_ADC0, &old_adc0);
+
+	adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2;
+	adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC;
+
+	if (channel > 7)
+		adc1 |= MC13783_ADC1_ADSEL;
+
+	switch (mode) {
+	case MC13783_ADC_MODE_TS:
+		adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 |
+			MC13783_ADC0_TSMOD1;
+		adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
+		break;
+
+	case MC13783_ADC_MODE_SINGLE_CHAN:
+		adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK;
+		adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT;
+		adc1 |= MC13783_ADC1_RAND;
+		break;
+
+	case MC13783_ADC_MODE_MULT_CHAN:
+		adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK;
+		adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
+		break;
+
+	default:
+		mc13783_unlock(mc13783);
+		return -EINVAL;
+	}
+
+	dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__);
+	mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE,
+			mc13783_handler_adcdone, __func__, &adcdone_data);
+	mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE);
+
+	mc13xxx_reg_write(mc13xxx, MC13783_ADC0, adc0);
+	mc13xxx_reg_write(mc13xxx, MC13783_ADC1, adc1);
+
+	mc13xxx_unlock(mc13xxx);
+
+	ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ);
+
+	if (!ret)
+		ret = -ETIMEDOUT;
+
+	mc13xxx_lock(mc13xxx);
+
+	mc13xxx_irq_free(mc13xxx, MC13783_IRQ_ADCDONE, &adcdone_data);
+
+	if (ret > 0)
+		for (i = 0; i < 4; ++i) {
+			ret = mc13xxx_reg_read(mc13xxx,
+					MC13783_ADC2, &sample[i]);
+			if (ret)
+				break;
+		}
+
+	if (mode == MC13783_ADC_MODE_TS)
+		/* restore TSMOD */
+		mc13xxx_reg_write(mc13xxx, MC13783_ADC0, old_adc0);
+
+	mc13783->adcflags &= ~MC13783_ADC_WORKING;
+out:
+	mc13xxx_unlock(mc13xxx);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
+
+static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
+		const char *format, void *pdata, size_t pdata_size)
+{
+	char buf[30];
+	const char *name = mc13xxx_get_chipname(mc13xxx);
+
+	struct mfd_cell cell = {
+		.platform_data = pdata,
+		.data_size = pdata_size,
+	};
+
+	/* there is no asnprintf in the kernel :-( */
+	if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf))
+		return -E2BIG;
+
+	cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL);
+	if (!cell.name)
+		return -ENOMEM;
+
+	return mfd_add_devices(&mc13xxx->spidev->dev, -1, &cell, 1, NULL, 0);
+}
+
+static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
+{
+	return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
+}
+
+static int mc13xxx_probe(struct spi_device *spi)
+{
+	struct mc13xxx *mc13xxx;
+	struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
+	enum mc13xxx_id id;
+	int ret;
+
+	mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
+	if (!mc13xxx)
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi->dev, mc13xxx);
+	spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
+	spi->bits_per_word = 32;
+	spi_setup(spi);
+
+	mc13xxx->spidev = spi;
+
+	mutex_init(&mc13xxx->lock);
+	mc13xxx_lock(mc13xxx);
+
+	ret = mc13xxx_identify(mc13xxx, &id);
+	if (ret || id == MC13XXX_ID_INVALID)
+		goto err_revision;
+
+	/* mask all irqs */
+	ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff);
+	if (ret)
+		goto err_mask;
+
+	ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff);
+	if (ret)
+		goto err_mask;
+
+	ret = request_threaded_irq(spi->irq, NULL, mc13xxx_irq_thread,
+			IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx);
+
+	if (ret) {
+err_mask:
+err_revision:
+		mutex_unlock(&mc13xxx->lock);
+		dev_set_drvdata(&spi->dev, NULL);
+		kfree(mc13xxx);
+		return ret;
+	}
+
+	mc13xxx_unlock(mc13xxx);
+
+	if (pdata->flags & MC13XXX_USE_ADC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-adc");
+
+	if (pdata->flags & MC13XXX_USE_CODEC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+
+	if (pdata->flags & MC13XXX_USE_REGULATOR) {
+		struct mc13xxx_regulator_platform_data regulator_pdata = {
+			.num_regulators = pdata->num_regulators,
+			.regulators = pdata->regulators,
+		};
+
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
+				&regulator_pdata, sizeof(regulator_pdata));
+	}
+
+	if (pdata->flags & MC13XXX_USE_RTC)
+		mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
+
+	if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
+		mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+
+	if (pdata->flags & MC13XXX_USE_LED) {
+		mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
+					pdata->leds, sizeof(*pdata->leds));
+	}
+
+	return 0;
+}
+
+static int __devexit mc13xxx_remove(struct spi_device *spi)
+{
+	struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev);
+
+	free_irq(mc13xxx->spidev->irq, mc13xxx);
+
+	mfd_remove_devices(&spi->dev);
+
+	kfree(mc13xxx);
+
+	return 0;
+}
+
+static const struct spi_device_id mc13xxx_device_id[] = {
+	{
+		.name = "mc13783",
+		.driver_data = MC13XXX_ID_MC13783,
+	}, {
+		.name = "mc13892",
+		.driver_data = MC13XXX_ID_MC13892,
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct spi_driver mc13xxx_driver = {
+	.id_table = mc13xxx_device_id,
+	.driver = {
+		.name = "mc13xxx",
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe = mc13xxx_probe,
+	.remove = __devexit_p(mc13xxx_remove),
+};
+
+static int __init mc13xxx_init(void)
+{
+	return spi_register_driver(&mc13xxx_driver);
+}
+subsys_initcall(mc13xxx_init);
+
+static void __exit mc13xxx_exit(void)
+{
+	spi_unregister_driver(&mc13xxx_driver);
+}
+module_exit(mc13xxx_exit);
+
+MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC");
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_LICENSE("GPL v2");

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

@@ -38,10 +38,12 @@ static int mfd_add_device(struct device *parent, int id,
 	pdev->dev.parent = parent;
 	pdev->dev.parent = parent;
 	platform_set_drvdata(pdev, cell->driver_data);
 	platform_set_drvdata(pdev, cell->driver_data);
 
 
-	ret = platform_device_add_data(pdev,
-			cell->platform_data, cell->data_size);
-	if (ret)
-		goto fail_res;
+	if (cell->data_size) {
+		ret = platform_device_add_data(pdev,
+					cell->platform_data, cell->data_size);
+		if (ret)
+			goto fail_res;
+	}
 
 
 	for (r = 0; r < cell->num_resources; r++) {
 	for (r = 0; r < cell->num_resources; r++) {
 		res[r].name = cell->resources[r].name;
 		res[r].name = cell->resources[r].name;
@@ -65,9 +67,11 @@ static int mfd_add_device(struct device *parent, int id,
 			res[r].end   = cell->resources[r].end;
 			res[r].end   = cell->resources[r].end;
 		}
 		}
 
 
-		ret = acpi_check_resource_conflict(res);
-		if (ret)
-			goto fail_res;
+		if (!cell->ignore_resource_conflicts) {
+			ret = acpi_check_resource_conflict(res);
+			if (ret)
+				goto fail_res;
+		}
 	}
 	}
 
 
 	ret = platform_device_add_resources(pdev, res, cell->num_resources);
 	ret = platform_device_add_resources(pdev, res, cell->num_resources);

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

@@ -25,13 +25,6 @@
 
 
 #include <linux/mfd/pcf50633/core.h>
 #include <linux/mfd/pcf50633/core.h>
 
 
-int pcf50633_irq_init(struct pcf50633 *pcf, int irq);
-void pcf50633_irq_free(struct pcf50633 *pcf);
-#ifdef CONFIG_PM
-int pcf50633_irq_suspend(struct pcf50633 *pcf);
-int pcf50633_irq_resume(struct pcf50633 *pcf);
-#endif
-
 static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
 static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
 {
 {
 	int ret;
 	int ret;
@@ -346,12 +339,14 @@ static int __devexit pcf50633_remove(struct i2c_client *client)
 	struct pcf50633 *pcf = i2c_get_clientdata(client);
 	struct pcf50633 *pcf = i2c_get_clientdata(client);
 	int i;
 	int i;
 
 
+	sysfs_remove_group(&client->dev.kobj, &pcf_attr_group);
 	pcf50633_irq_free(pcf);
 	pcf50633_irq_free(pcf);
 
 
 	platform_device_unregister(pcf->input_pdev);
 	platform_device_unregister(pcf->input_pdev);
 	platform_device_unregister(pcf->rtc_pdev);
 	platform_device_unregister(pcf->rtc_pdev);
 	platform_device_unregister(pcf->mbc_pdev);
 	platform_device_unregister(pcf->mbc_pdev);
 	platform_device_unregister(pcf->adc_pdev);
 	platform_device_unregister(pcf->adc_pdev);
+	platform_device_unregister(pcf->bl_pdev);
 
 
 	for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
 	for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
 		platform_device_unregister(pcf->regulator_pdev[i]);
 		platform_device_unregister(pcf->regulator_pdev[i]);

+ 19 - 0
drivers/mfd/sh_mobile_sdhi.c

@@ -65,6 +65,17 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
 		p->set_pwr(pdev, state);
 		p->set_pwr(pdev, state);
 }
 }
 
 
+static int sh_mobile_sdhi_get_cd(struct platform_device *tmio)
+{
+	struct platform_device *pdev = to_platform_device(tmio->dev.parent);
+	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+
+	if (p && p->get_cd)
+		return p->get_cd(pdev);
+	else
+		return -ENOSYS;
+}
+
 static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
 {
 	struct sh_mobile_sdhi *priv;
 	struct sh_mobile_sdhi *priv;
@@ -106,12 +117,20 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 
 
 	mmc_data->hclk = clk_get_rate(priv->clk);
 	mmc_data->hclk = clk_get_rate(priv->clk);
 	mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
 	mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
+	mmc_data->get_cd = sh_mobile_sdhi_get_cd;
 	mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
 	mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
 	if (p) {
 	if (p) {
 		mmc_data->flags = p->tmio_flags;
 		mmc_data->flags = p->tmio_flags;
 		mmc_data->ocr_mask = p->tmio_ocr_mask;
 		mmc_data->ocr_mask = p->tmio_ocr_mask;
+		mmc_data->capabilities |= p->tmio_caps;
 	}
 	}
 
 
+	/*
+	 * All SDHI blocks support 2-byte and larger block sizes in 4-bit
+	 * bus width mode.
+	 */
+	mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
+
 	if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
 	if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
 		priv->param_tx.slave_id = p->dma_slave_tx;
 		priv->param_tx.slave_id = p->dma_slave_tx;
 		priv->param_rx.slave_id = p->dma_slave_rx;
 		priv->param_rx.slave_id = p->dma_slave_rx;

+ 32 - 0
drivers/mfd/stmpe.c

@@ -873,6 +873,28 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe)
 	return ret;
 	return ret;
 }
 }
 
 
+#ifdef CONFIG_PM
+static int stmpe_suspend(struct device *dev)
+{
+	struct i2c_client *i2c = to_i2c_client(dev);
+
+	if (device_may_wakeup(&i2c->dev))
+		enable_irq_wake(i2c->irq);
+
+	return 0;
+}
+
+static int stmpe_resume(struct device *dev)
+{
+	struct i2c_client *i2c = to_i2c_client(dev);
+
+	if (device_may_wakeup(&i2c->dev))
+		disable_irq_wake(i2c->irq);
+
+	return 0;
+}
+#endif
+
 static int __devinit stmpe_probe(struct i2c_client *i2c,
 static int __devinit stmpe_probe(struct i2c_client *i2c,
 				 const struct i2c_device_id *id)
 				 const struct i2c_device_id *id)
 {
 {
@@ -960,9 +982,19 @@ static const struct i2c_device_id stmpe_id[] = {
 };
 };
 MODULE_DEVICE_TABLE(i2c, stmpe_id);
 MODULE_DEVICE_TABLE(i2c, stmpe_id);
 
 
+#ifdef CONFIG_PM
+static const struct dev_pm_ops stmpe_dev_pm_ops = {
+	.suspend	= stmpe_suspend,
+	.resume		= stmpe_resume,
+};
+#endif
+
 static struct i2c_driver stmpe_driver = {
 static struct i2c_driver stmpe_driver = {
 	.driver.name	= "stmpe",
 	.driver.name	= "stmpe",
 	.driver.owner	= THIS_MODULE,
 	.driver.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+	.driver.pm	= &stmpe_dev_pm_ops,
+#endif
 	.probe		= stmpe_probe,
 	.probe		= stmpe_probe,
 	.remove		= __devexit_p(stmpe_remove),
 	.remove		= __devexit_p(stmpe_remove),
 	.id_table	= stmpe_id,
 	.id_table	= stmpe_id,

+ 1 - 1
drivers/mfd/tc6393xb.c

@@ -155,7 +155,7 @@ static struct resource __devinitdata tc6393xb_nand_resources[] = {
 	},
 	},
 };
 };
 
 
-static struct resource __devinitdata tc6393xb_mmc_resources[] = {
+static struct resource tc6393xb_mmc_resources[] = {
 	{
 	{
 		.start	= 0x800,
 		.start	= 0x800,
 		.end	= 0x9ff,
 		.end	= 0x9ff,

+ 14 - 0
drivers/mfd/timberdale.c

@@ -43,6 +43,8 @@
 
 
 #include <linux/timb_dma.h>
 #include <linux/timb_dma.h>
 
 
+#include <linux/ks8842.h>
+
 #include "timberdale.h"
 #include "timberdale.h"
 
 
 #define DRIVER_NAME "timberdale"
 #define DRIVER_NAME "timberdale"
@@ -161,6 +163,12 @@ static const __devinitconst struct resource timberdale_spi_resources[] = {
 	},
 	},
 };
 };
 
 
+static __devinitdata struct ks8842_platform_data
+	timberdale_ks8842_platform_data = {
+	.rx_dma_channel = DMA_ETH_RX,
+	.tx_dma_channel = DMA_ETH_TX
+};
+
 static const __devinitconst struct resource timberdale_eth_resources[] = {
 static const __devinitconst struct resource timberdale_eth_resources[] = {
 	{
 	{
 		.start	= ETHOFFSET,
 		.start	= ETHOFFSET,
@@ -389,6 +397,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
 		.name = "ks8842",
 		.name = "ks8842",
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.resources = timberdale_eth_resources,
 		.resources = timberdale_eth_resources,
+		.platform_data = &timberdale_ks8842_platform_data,
+		.data_size = sizeof(timberdale_ks8842_platform_data)
 	},
 	},
 };
 };
 
 
@@ -447,6 +457,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
 		.name = "ks8842",
 		.name = "ks8842",
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.resources = timberdale_eth_resources,
 		.resources = timberdale_eth_resources,
+		.platform_data = &timberdale_ks8842_platform_data,
+		.data_size = sizeof(timberdale_ks8842_platform_data)
 	},
 	},
 };
 };
 
 
@@ -538,6 +550,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
 		.name = "ks8842",
 		.name = "ks8842",
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.num_resources = ARRAY_SIZE(timberdale_eth_resources),
 		.resources = timberdale_eth_resources,
 		.resources = timberdale_eth_resources,
+		.platform_data = &timberdale_ks8842_platform_data,
+		.data_size = sizeof(timberdale_ks8842_platform_data)
 	},
 	},
 };
 };
 
 

+ 1 - 1
drivers/mfd/tps6507x.c

@@ -68,7 +68,7 @@ static int tps6507x_i2c_write_device(struct tps6507x_dev *tps6507x, char reg,
 	u8 msg[TPS6507X_MAX_REGISTER + 1];
 	u8 msg[TPS6507X_MAX_REGISTER + 1];
 	int ret;
 	int ret;
 
 
-	if (bytes > (TPS6507X_MAX_REGISTER + 1))
+	if (bytes > TPS6507X_MAX_REGISTER)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	msg[0] = reg;
 	msg[0] = reg;

+ 223 - 2
drivers/mfd/tps6586x.c

@@ -15,6 +15,8 @@
  * published by the Free Software Foundation.
  * published by the Free Software Foundation.
  */
  */
 
 
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
@@ -29,9 +31,64 @@
 #define TPS6586X_GPIOSET1	0x5d
 #define TPS6586X_GPIOSET1	0x5d
 #define TPS6586X_GPIOSET2	0x5e
 #define TPS6586X_GPIOSET2	0x5e
 
 
+/* interrupt control registers */
+#define TPS6586X_INT_ACK1	0xb5
+#define TPS6586X_INT_ACK2	0xb6
+#define TPS6586X_INT_ACK3	0xb7
+#define TPS6586X_INT_ACK4	0xb8
+
+/* interrupt mask registers */
+#define TPS6586X_INT_MASK1	0xb0
+#define TPS6586X_INT_MASK2	0xb1
+#define TPS6586X_INT_MASK3	0xb2
+#define TPS6586X_INT_MASK4	0xb3
+#define TPS6586X_INT_MASK5	0xb4
+
 /* device id */
 /* device id */
 #define TPS6586X_VERSIONCRC	0xcd
 #define TPS6586X_VERSIONCRC	0xcd
 #define TPS658621A_VERSIONCRC	0x15
 #define TPS658621A_VERSIONCRC	0x15
+#define TPS658621C_VERSIONCRC	0x2c
+
+struct tps6586x_irq_data {
+	u8	mask_reg;
+	u8	mask_mask;
+};
+
+#define TPS6586X_IRQ(_reg, _mask)				\
+	{							\
+		.mask_reg = (_reg) - TPS6586X_INT_MASK1,	\
+		.mask_mask = (_mask),				\
+	}
+
+static const struct tps6586x_irq_data tps6586x_irqs[] = {
+	[TPS6586X_INT_PLDO_0]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 0),
+	[TPS6586X_INT_PLDO_1]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 1),
+	[TPS6586X_INT_PLDO_2]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 2),
+	[TPS6586X_INT_PLDO_3]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 3),
+	[TPS6586X_INT_PLDO_4]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 4),
+	[TPS6586X_INT_PLDO_5]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 5),
+	[TPS6586X_INT_PLDO_6]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 6),
+	[TPS6586X_INT_PLDO_7]	= TPS6586X_IRQ(TPS6586X_INT_MASK1, 1 << 7),
+	[TPS6586X_INT_COMP_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 0),
+	[TPS6586X_INT_ADC]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 1),
+	[TPS6586X_INT_PLDO_8]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 2),
+	[TPS6586X_INT_PLDO_9]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 3),
+	[TPS6586X_INT_PSM_0]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 4),
+	[TPS6586X_INT_PSM_1]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 5),
+	[TPS6586X_INT_PSM_2]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 6),
+	[TPS6586X_INT_PSM_3]	= TPS6586X_IRQ(TPS6586X_INT_MASK2, 1 << 7),
+	[TPS6586X_INT_RTC_ALM1]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 4),
+	[TPS6586X_INT_ACUSB_OVP] = TPS6586X_IRQ(TPS6586X_INT_MASK5, 0x03),
+	[TPS6586X_INT_USB_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 2),
+	[TPS6586X_INT_AC_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 3),
+	[TPS6586X_INT_BAT_DET]	= TPS6586X_IRQ(TPS6586X_INT_MASK3, 1 << 0),
+	[TPS6586X_INT_CHG_STAT]	= TPS6586X_IRQ(TPS6586X_INT_MASK4, 0xfc),
+	[TPS6586X_INT_CHG_TEMP]	= TPS6586X_IRQ(TPS6586X_INT_MASK3, 0x06),
+	[TPS6586X_INT_PP]	= TPS6586X_IRQ(TPS6586X_INT_MASK3, 0xf0),
+	[TPS6586X_INT_RESUME]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 5),
+	[TPS6586X_INT_LOW_SYS]	= TPS6586X_IRQ(TPS6586X_INT_MASK5, 1 << 6),
+	[TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1),
+};
 
 
 struct tps6586x {
 struct tps6586x {
 	struct mutex		lock;
 	struct mutex		lock;
@@ -39,6 +96,12 @@ struct tps6586x {
 	struct i2c_client	*client;
 	struct i2c_client	*client;
 
 
 	struct gpio_chip	gpio;
 	struct gpio_chip	gpio;
+	struct irq_chip		irq_chip;
+	struct mutex		irq_lock;
+	int			irq_base;
+	u32			irq_en;
+	u8			mask_cache[5];
+	u8			mask_reg[5];
 };
 };
 
 
 static inline int __tps6586x_read(struct i2c_client *client,
 static inline int __tps6586x_read(struct i2c_client *client,
@@ -262,6 +325,129 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
 	return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
 	return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
 }
 }
 
 
+static void tps6586x_irq_lock(unsigned int irq)
+{
+	struct tps6586x *tps6586x = get_irq_chip_data(irq);
+
+	mutex_lock(&tps6586x->irq_lock);
+}
+
+static void tps6586x_irq_enable(unsigned int irq)
+{
+	struct tps6586x *tps6586x = get_irq_chip_data(irq);
+	unsigned int __irq = irq - tps6586x->irq_base;
+	const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
+
+	tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
+	tps6586x->irq_en |= (1 << __irq);
+}
+
+static void tps6586x_irq_disable(unsigned int irq)
+{
+	struct tps6586x *tps6586x = get_irq_chip_data(irq);
+
+	unsigned int __irq = irq - tps6586x->irq_base;
+	const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
+
+	tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
+	tps6586x->irq_en &= ~(1 << __irq);
+}
+
+static void tps6586x_irq_sync_unlock(unsigned int irq)
+{
+	struct tps6586x *tps6586x = get_irq_chip_data(irq);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
+		if (tps6586x->mask_reg[i] != tps6586x->mask_cache[i]) {
+			if (!WARN_ON(tps6586x_write(tps6586x->dev,
+						    TPS6586X_INT_MASK1 + i,
+						    tps6586x->mask_reg[i])))
+				tps6586x->mask_cache[i] = tps6586x->mask_reg[i];
+		}
+	}
+
+	mutex_unlock(&tps6586x->irq_lock);
+}
+
+static irqreturn_t tps6586x_irq(int irq, void *data)
+{
+	struct tps6586x *tps6586x = data;
+	u32 acks;
+	int ret = 0;
+
+	ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1,
+			     sizeof(acks), (uint8_t *)&acks);
+
+	if (ret < 0) {
+		dev_err(tps6586x->dev, "failed to read interrupt status\n");
+		return IRQ_NONE;
+	}
+
+	acks = le32_to_cpu(acks);
+
+	while (acks) {
+		int i = __ffs(acks);
+
+		if (tps6586x->irq_en & (1 << i))
+			handle_nested_irq(tps6586x->irq_base + i);
+
+		acks &= ~(1 << i);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
+				       int irq_base)
+{
+	int i, ret;
+	u8 tmp[4];
+
+	if (!irq_base) {
+		dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&tps6586x->irq_lock);
+	for (i = 0; i < 5; i++) {
+		tps6586x->mask_cache[i] = 0xff;
+		tps6586x->mask_reg[i] = 0xff;
+		tps6586x_write(tps6586x->dev, TPS6586X_INT_MASK1 + i, 0xff);
+	}
+
+	tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp);
+
+	tps6586x->irq_base = irq_base;
+
+	tps6586x->irq_chip.name = "tps6586x";
+	tps6586x->irq_chip.enable = tps6586x_irq_enable;
+	tps6586x->irq_chip.disable = tps6586x_irq_disable;
+	tps6586x->irq_chip.bus_lock = tps6586x_irq_lock;
+	tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock;
+
+	for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
+		int __irq = i + tps6586x->irq_base;
+		set_irq_chip_data(__irq, tps6586x);
+		set_irq_chip_and_handler(__irq, &tps6586x->irq_chip,
+					 handle_simple_irq);
+		set_irq_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(__irq, IRQF_VALID);
+#endif
+	}
+
+	ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT,
+				   "tps6586x", tps6586x);
+
+	if (!ret) {
+		device_init_wakeup(tps6586x->dev, 1);
+		enable_irq_wake(irq);
+	}
+
+	return ret;
+}
+
 static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
 static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
 					  struct tps6586x_platform_data *pdata)
 					  struct tps6586x_platform_data *pdata)
 {
 {
@@ -273,13 +459,19 @@ static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
 		subdev = &pdata->subdevs[i];
 		subdev = &pdata->subdevs[i];
 
 
 		pdev = platform_device_alloc(subdev->name, subdev->id);
 		pdev = platform_device_alloc(subdev->name, subdev->id);
+		if (!pdev) {
+			ret = -ENOMEM;
+			goto failed;
+		}
 
 
 		pdev->dev.parent = tps6586x->dev;
 		pdev->dev.parent = tps6586x->dev;
 		pdev->dev.platform_data = subdev->platform_data;
 		pdev->dev.platform_data = subdev->platform_data;
 
 
 		ret = platform_device_add(pdev);
 		ret = platform_device_add(pdev);
-		if (ret)
+		if (ret) {
+			platform_device_put(pdev);
 			goto failed;
 			goto failed;
+		}
 	}
 	}
 	return 0;
 	return 0;
 
 
@@ -306,7 +498,8 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
-	if (ret != TPS658621A_VERSIONCRC) {
+	if ((ret != TPS658621A_VERSIONCRC) &&
+	    (ret != TPS658621C_VERSIONCRC)) {
 		dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
 		dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -321,6 +514,15 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
 
 
 	mutex_init(&tps6586x->lock);
 	mutex_init(&tps6586x->lock);
 
 
+	if (client->irq) {
+		ret = tps6586x_irq_init(tps6586x, client->irq,
+					pdata->irq_base);
+		if (ret) {
+			dev_err(&client->dev, "IRQ init failed: %d\n", ret);
+			goto err_irq_init;
+		}
+	}
+
 	ret = tps6586x_add_subdevs(tps6586x, pdata);
 	ret = tps6586x_add_subdevs(tps6586x, pdata);
 	if (ret) {
 	if (ret) {
 		dev_err(&client->dev, "add devices failed: %d\n", ret);
 		dev_err(&client->dev, "add devices failed: %d\n", ret);
@@ -332,12 +534,31 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
 	return 0;
 	return 0;
 
 
 err_add_devs:
 err_add_devs:
+	if (client->irq)
+		free_irq(client->irq, tps6586x);
+err_irq_init:
 	kfree(tps6586x);
 	kfree(tps6586x);
 	return ret;
 	return ret;
 }
 }
 
 
 static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
 static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
 {
 {
+	struct tps6586x *tps6586x = i2c_get_clientdata(client);
+	struct tps6586x_platform_data *pdata = client->dev.platform_data;
+	int ret;
+
+	if (client->irq)
+		free_irq(client->irq, tps6586x);
+
+	if (pdata->gpio_base) {
+		ret = gpiochip_remove(&tps6586x->gpio);
+		if (ret)
+			dev_err(&client->dev, "Can't remove gpio chip: %d\n",
+				ret);
+	}
+
+	tps6586x_remove_subdevs(tps6586x);
+	kfree(tps6586x);
 	return 0;
 	return 0;
 }
 }
 
 

+ 27 - 13
drivers/mfd/twl-core.c

@@ -115,6 +115,12 @@
 #define twl_has_codec()	false
 #define twl_has_codec()	false
 #endif
 #endif
 
 
+#if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE)
+#define twl_has_bci()	true
+#else
+#define twl_has_bci()	false
+#endif
+
 /* Triton Core internal information (BEGIN) */
 /* Triton Core internal information (BEGIN) */
 
 
 /* Last - for index max*/
 /* Last - for index max*/
@@ -202,12 +208,6 @@
 
 
 /* Few power values */
 /* Few power values */
 #define R_CFG_BOOT			0x05
 #define R_CFG_BOOT			0x05
-#define R_PROTECT_KEY			0x0E
-
-/* access control values for R_PROTECT_KEY */
-#define KEY_UNLOCK1			0xce
-#define KEY_UNLOCK2			0xec
-#define KEY_LOCK			0x00
 
 
 /* some fields in R_CFG_BOOT */
 /* some fields in R_CFG_BOOT */
 #define HFCLK_FREQ_19p2_MHZ		(1 << 0)
 #define HFCLK_FREQ_19p2_MHZ		(1 << 0)
@@ -255,7 +255,7 @@ struct twl_mapping {
 	unsigned char sid;	/* Slave ID */
 	unsigned char sid;	/* Slave ID */
 	unsigned char base;	/* base address */
 	unsigned char base;	/* base address */
 };
 };
-struct twl_mapping *twl_map;
+static struct twl_mapping *twl_map;
 
 
 static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
 static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
 	/*
 	/*
@@ -832,6 +832,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 			return PTR_ERR(child);
 			return PTR_ERR(child);
 	}
 	}
 
 
+	if (twl_has_bci() && pdata->bci &&
+			!(features & (TPS_SUBSET | TWL5031))) {
+		child = add_child(3, "twl4030_bci",
+				pdata->bci, sizeof(*pdata->bci), false,
+				/* irq0 = CHG_PRES, irq1 = BCI */
+				pdata->irq_base + BCI_PRES_INTR_OFFSET,
+				pdata->irq_base + BCI_INTR_OFFSET);
+		if (IS_ERR(child))
+			return PTR_ERR(child);
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -846,8 +857,8 @@ static inline int __init protect_pm_master(void)
 {
 {
 	int e = 0;
 	int e = 0;
 
 
-	e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK,
-			R_PROTECT_KEY);
+	e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 	return e;
 	return e;
 }
 }
 
 
@@ -855,10 +866,13 @@ static inline int __init unprotect_pm_master(void)
 {
 {
 	int e = 0;
 	int e = 0;
 
 
-	e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1,
-			R_PROTECT_KEY);
-	e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2,
-			R_PROTECT_KEY);
+	e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG1,
+			TWL4030_PM_MASTER_PROTECT_KEY);
+	e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG2,
+			TWL4030_PM_MASTER_PROTECT_KEY);
+
 	return e;
 	return e;
 }
 }
 
 

+ 10 - 0
drivers/mfd/twl-core.h

@@ -0,0 +1,10 @@
+#ifndef __TWL_CORE_H__
+#define __TWL_CORE_H__
+
+extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl6030_exit_irq(void);
+extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl4030_exit_irq(void);
+extern int twl4030_init_chip_irq(const char *chip);
+
+#endif /*  __TWL_CORE_H__ */

+ 3 - 1
drivers/mfd/twl4030-irq.c

@@ -35,6 +35,7 @@
 
 
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 
 
+#include "twl-core.h"
 
 
 /*
 /*
  * TWL4030 IRQ handling has two stages in hardware, and thus in software.
  * TWL4030 IRQ handling has two stages in hardware, and thus in software.
@@ -144,6 +145,7 @@ static const struct sih sih_modules_twl4030[6] = {
 		.name		= "bci",
 		.name		= "bci",
 		.module		= TWL4030_MODULE_INTERRUPTS,
 		.module		= TWL4030_MODULE_INTERRUPTS,
 		.control_offset	= TWL4030_INTERRUPTS_BCISIHCTRL,
 		.control_offset	= TWL4030_INTERRUPTS_BCISIHCTRL,
+		.set_cor	= true,
 		.bits		= 12,
 		.bits		= 12,
 		.bytes_ixr	= 2,
 		.bytes_ixr	= 2,
 		.edr_offset	= TWL4030_INTERRUPTS_BCIEDR1,
 		.edr_offset	= TWL4030_INTERRUPTS_BCIEDR1,
@@ -408,7 +410,7 @@ static int twl4030_init_sih_modules(unsigned line)
 		 * 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
-		 * inverted:  for MADC and BCI, COR=1 means "clear on write".
+		 * inverted:  for MADC, COR=1 means "clear on write".
 		 * And for PWR_INT it's not documented...
 		 * And for PWR_INT it's not documented...
 		 */
 		 */
 		if (sih->set_cor) {
 		if (sih->set_cor) {

+ 16 - 14
drivers/mfd/twl4030-power.c

@@ -63,10 +63,6 @@ static u8 twl4030_start_script_address = 0x2b;
 #define R_MEMORY_ADDRESS	PHY_TO_OFF_PM_MASTER(0x59)
 #define R_MEMORY_ADDRESS	PHY_TO_OFF_PM_MASTER(0x59)
 #define R_MEMORY_DATA		PHY_TO_OFF_PM_MASTER(0x5a)
 #define R_MEMORY_DATA		PHY_TO_OFF_PM_MASTER(0x5a)
 
 
-#define R_PROTECT_KEY		0x0E
-#define R_KEY_1			0xC0
-#define R_KEY_2			0x0C
-
 /* resource configuration registers
 /* resource configuration registers
    <RESOURCE>_DEV_GRP   at address 'n+0'
    <RESOURCE>_DEV_GRP   at address 'n+0'
    <RESOURCE>_TYPE      at address 'n+1'
    <RESOURCE>_TYPE      at address 'n+1'
@@ -465,15 +461,17 @@ int twl4030_remove_script(u8 flags)
 {
 {
 	int err = 0;
 	int err = 0;
 
 
-	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
-			R_PROTECT_KEY);
+	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG1,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 	if (err) {
 	if (err) {
 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
 		return err;
 		return err;
 	}
 	}
 
 
-	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
-			R_PROTECT_KEY);
+	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG2,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 	if (err) {
 	if (err) {
 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
 		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
 		return err;
 		return err;
@@ -504,7 +502,8 @@ int twl4030_remove_script(u8 flags)
 			return err;
 			return err;
 	}
 	}
 
 
-	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
+	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 	if (err)
 	if (err)
 		pr_err("TWL4030 Unable to relock registers\n");
 		pr_err("TWL4030 Unable to relock registers\n");
 
 
@@ -518,13 +517,15 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
 	struct twl4030_resconfig *resconfig;
 	struct twl4030_resconfig *resconfig;
 	u8 address = twl4030_start_script_address;
 	u8 address = twl4030_start_script_address;
 
 
-	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
-				R_PROTECT_KEY);
+	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG1,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 	if (err)
 	if (err)
 		goto unlock;
 		goto unlock;
 
 
-	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
-				R_PROTECT_KEY);
+	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG2,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 	if (err)
 	if (err)
 		goto unlock;
 		goto unlock;
 
 
@@ -546,7 +547,8 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
 		}
 		}
 	}
 	}
 
 
-	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
+	err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 	if (err)
 	if (err)
 		pr_err("TWL4030 Unable to relock registers\n");
 		pr_err("TWL4030 Unable to relock registers\n");
 	return;
 	return;

+ 75 - 0
drivers/mfd/twl6030-irq.c

@@ -36,6 +36,9 @@
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/kthread.h>
 #include <linux/kthread.h>
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
+#include <linux/platform_device.h>
+
+#include "twl-core.h"
 
 
 /*
 /*
  * TWL6030 (unlike its predecessors, which had two level interrupt handling)
  * TWL6030 (unlike its predecessors, which had two level interrupt handling)
@@ -223,6 +226,78 @@ int twl6030_interrupt_mask(u8 bit_mask, u8 offset)
 }
 }
 EXPORT_SYMBOL(twl6030_interrupt_mask);
 EXPORT_SYMBOL(twl6030_interrupt_mask);
 
 
+int twl6030_mmc_card_detect_config(void)
+{
+	int ret;
+	u8 reg_val = 0;
+
+	/* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */
+	twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK,
+						REG_INT_MSK_LINE_B);
+	twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK,
+						REG_INT_MSK_STS_B);
+	/*
+	 * Intially Configuring MMC_CTRL for receving interrupts &
+	 * Card status on TWL6030 for MMC1
+	 */
+	ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &reg_val, TWL6030_MMCCTRL);
+	if (ret < 0) {
+		pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret);
+		return ret;
+	}
+	reg_val &= ~VMMC_AUTO_OFF;
+	reg_val |= SW_FC;
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL);
+	if (ret < 0) {
+		pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret);
+		return ret;
+	}
+
+	/* Configuring PullUp-PullDown register */
+	ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &reg_val,
+						TWL6030_CFG_INPUT_PUPD3);
+	if (ret < 0) {
+		pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n",
+									ret);
+		return ret;
+	}
+	reg_val &= ~(MMC_PU | MMC_PD);
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val,
+						TWL6030_CFG_INPUT_PUPD3);
+	if (ret < 0) {
+		pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n",
+									ret);
+		return ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
+
+int twl6030_mmc_card_detect(struct device *dev, int slot)
+{
+	int ret = -EIO;
+	u8 read_reg = 0;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	if (pdev->id) {
+		/* TWL6030 provide's Card detect support for
+		 * only MMC1 controller.
+		 */
+		pr_err("Unkown MMC controller %d in %s\n", pdev->id, __func__);
+		return ret;
+	}
+	/*
+	 * BIT0 of MMC_CTRL on TWL6030 provides card status for MMC1
+	 * 0 - Card not present ,1 - Card present
+	 */
+	ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg,
+						TWL6030_MMCCTRL);
+	if (ret >= 0)
+		ret = read_reg & STS_MMC;
+	return ret;
+}
+EXPORT_SYMBOL(twl6030_mmc_card_detect);
+
 int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 {
 {
 
 

+ 147 - 0
drivers/mfd/vx855.c

@@ -0,0 +1,147 @@
+/*
+ * Linux multi-function-device driver (MFD) for the integrated peripherals
+ * of the VIA VX855 chipset
+ *
+ * Copyright (C) 2009 VIA Technologies, Inc.
+ * Copyright (C) 2010 One Laptop per Child
+ * Author: Harald Welte <HaraldWelte@viatech.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/mfd/core.h>
+
+/* offset into pci config space indicating the 16bit register containing
+ * the power management IO space base */
+#define VX855_CFG_PMIO_OFFSET	0x88
+
+/* ACPI I/O Space registers */
+#define VX855_PMIO_ACPI		0x00
+#define VX855_PMIO_ACPI_LEN	0x0b
+
+/* Processor Power Management */
+#define VX855_PMIO_PPM		0x10
+#define VX855_PMIO_PPM_LEN	0x08
+
+/* General Purpose Power Management */
+#define VX855_PMIO_GPPM		0x20
+#define VX855_PMIO_R_GPI	0x48
+#define VX855_PMIO_R_GPO	0x4c
+#define VX855_PMIO_GPPM_LEN	0x33
+
+#define VSPIC_MMIO_SIZE	0x1000
+
+static struct resource vx855_gpio_resources[] = {
+	{
+		.flags = IORESOURCE_IO,
+	},
+	{
+		.flags = IORESOURCE_IO,
+	},
+};
+
+static struct mfd_cell vx855_cells[] = {
+	{
+		.name = "vx855_gpio",
+		.num_resources = ARRAY_SIZE(vx855_gpio_resources),
+		.resources = vx855_gpio_resources,
+
+		/* we must ignore resource conflicts, for reasons outlined in
+		 * the vx855_gpio driver */
+		.ignore_resource_conflicts = true,
+	},
+};
+
+static __devinit int vx855_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *id)
+{
+	int ret;
+	u16 gpio_io_offset;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return -ENODEV;
+
+	pci_read_config_word(pdev, VX855_CFG_PMIO_OFFSET, &gpio_io_offset);
+	if (!gpio_io_offset) {
+		dev_warn(&pdev->dev,
+			"BIOS did not assign PMIO base offset?!?\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* mask out the lowest seven bits, as they are always zero, but
+	 * hardware returns them as 0x01 */
+	gpio_io_offset &= 0xff80;
+
+	/* As the region identified here includes many non-GPIO things, we
+	 * only work with the specific registers that concern us. */
+	vx855_gpio_resources[0].start = gpio_io_offset + VX855_PMIO_R_GPI;
+	vx855_gpio_resources[0].end = vx855_gpio_resources[0].start + 3;
+	vx855_gpio_resources[1].start = gpio_io_offset + VX855_PMIO_R_GPO;
+	vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3;
+
+	ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells),
+			NULL, 0);
+
+	/* we always return -ENODEV here in order to enable other
+	 * drivers like old, not-yet-platform_device ported i2c-viapro */
+	return -ENODEV;
+out:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void vx855_remove(struct pci_dev *pdev)
+{
+	mfd_remove_devices(&pdev->dev);
+	pci_disable_device(pdev);
+}
+
+static struct pci_device_id vx855_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
+	{ 0, }
+};
+
+static struct pci_driver vx855_pci_driver = {
+	.name		= "vx855",
+	.id_table	= vx855_pci_tbl,
+	.probe		= vx855_probe,
+	.remove		= __devexit_p(vx855_remove),
+};
+
+static int vx855_init(void)
+{
+	return pci_register_driver(&vx855_pci_driver);
+}
+module_init(vx855_init);
+
+static void vx855_exit(void)
+{
+	pci_unregister_driver(&vx855_pci_driver);
+}
+module_exit(vx855_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
+MODULE_DESCRIPTION("Driver for the VIA VX855 chipset");

+ 16 - 132
drivers/mfd/wm831x-core.c

@@ -14,7 +14,6 @@
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/i2c.h>
 #include <linux/bcd.h>
 #include <linux/bcd.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/core.h>
@@ -90,14 +89,6 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
 };
 };
 EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
 EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
 
 
-enum wm831x_parent {
-	WM8310 = 0x8310,
-	WM8311 = 0x8311,
-	WM8312 = 0x8312,
-	WM8320 = 0x8320,
-	WM8321 = 0x8321,
-};
-
 static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
 static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
 {
 {
 	if (!wm831x->locked)
 	if (!wm831x->locked)
@@ -1446,7 +1437,7 @@ static struct mfd_cell backlight_devs[] = {
 /*
 /*
  * Instantiate the generic non-control parts of the device.
  * Instantiate the generic non-control parts of the device.
  */
  */
-static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
+int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 {
 {
 	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
 	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
 	int rev;
 	int rev;
@@ -1540,6 +1531,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 		dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev);
 		dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev);
 		break;
 		break;
 
 
+	case WM8325:
+		parent = WM8325;
+		wm831x->num_gpio = 12;
+		dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
+		break;
+
 	default:
 	default:
 		dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
 		dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
 		ret = -EINVAL;
 		ret = -EINVAL;
@@ -1620,6 +1617,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 				      NULL, 0);
 				      NULL, 0);
 		break;
 		break;
 
 
+	case WM8325:
+		ret = mfd_add_devices(wm831x->dev, -1,
+				      wm8320_devs, ARRAY_SIZE(wm8320_devs),
+				      NULL, 0);
+		break;
+
 	default:
 	default:
 		/* If this happens the bus probe function is buggy */
 		/* If this happens the bus probe function is buggy */
 		BUG();
 		BUG();
@@ -1660,7 +1663,7 @@ err:
 	return ret;
 	return ret;
 }
 }
 
 
-static void wm831x_device_exit(struct wm831x *wm831x)
+void wm831x_device_exit(struct wm831x *wm831x)
 {
 {
 	wm831x_otp_exit(wm831x);
 	wm831x_otp_exit(wm831x);
 	mfd_remove_devices(wm831x->dev);
 	mfd_remove_devices(wm831x->dev);
@@ -1670,7 +1673,7 @@ static void wm831x_device_exit(struct wm831x *wm831x)
 	kfree(wm831x);
 	kfree(wm831x);
 }
 }
 
 
-static int wm831x_device_suspend(struct wm831x *wm831x)
+int wm831x_device_suspend(struct wm831x *wm831x)
 {
 {
 	int reg, mask;
 	int reg, mask;
 
 
@@ -1706,125 +1709,6 @@ static int wm831x_device_suspend(struct wm831x *wm831x)
 	return 0;
 	return 0;
 }
 }
 
 
-static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
-				  int bytes, void *dest)
-{
-	struct i2c_client *i2c = wm831x->control_data;
-	int ret;
-	u16 r = cpu_to_be16(reg);
-
-	ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
-	if (ret < 0)
-		return ret;
-	if (ret != 2)
-		return -EIO;
-
-	ret = i2c_master_recv(i2c, dest, bytes);
-	if (ret < 0)
-		return ret;
-	if (ret != bytes)
-		return -EIO;
-	return 0;
-}
-
-/* Currently we allocate the write buffer on the stack; this is OK for
- * small writes - if we need to do large writes this will need to be
- * revised.
- */
-static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
-				   int bytes, void *src)
-{
-	struct i2c_client *i2c = wm831x->control_data;
-	unsigned char msg[bytes + 2];
-	int ret;
-
-	reg = cpu_to_be16(reg);
-	memcpy(&msg[0], &reg, 2);
-	memcpy(&msg[2], src, bytes);
-
-	ret = i2c_master_send(i2c, msg, bytes + 2);
-	if (ret < 0)
-		return ret;
-	if (ret < bytes + 2)
-		return -EIO;
-
-	return 0;
-}
-
-static int wm831x_i2c_probe(struct i2c_client *i2c,
-			    const struct i2c_device_id *id)
-{
-	struct wm831x *wm831x;
-
-	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
-	if (wm831x == NULL)
-		return -ENOMEM;
-
-	i2c_set_clientdata(i2c, wm831x);
-	wm831x->dev = &i2c->dev;
-	wm831x->control_data = i2c;
-	wm831x->read_dev = wm831x_i2c_read_device;
-	wm831x->write_dev = wm831x_i2c_write_device;
-
-	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
-}
-
-static int wm831x_i2c_remove(struct i2c_client *i2c)
-{
-	struct wm831x *wm831x = i2c_get_clientdata(i2c);
-
-	wm831x_device_exit(wm831x);
-
-	return 0;
-}
-
-static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
-{
-	struct wm831x *wm831x = i2c_get_clientdata(i2c);
-
-	return wm831x_device_suspend(wm831x);
-}
-
-static const struct i2c_device_id wm831x_i2c_id[] = {
-	{ "wm8310", WM8310 },
-	{ "wm8311", WM8311 },
-	{ "wm8312", WM8312 },
-	{ "wm8320", WM8320 },
-	{ "wm8321", WM8321 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
-
-
-static struct i2c_driver wm831x_i2c_driver = {
-	.driver = {
-		   .name = "wm831x",
-		   .owner = THIS_MODULE,
-	},
-	.probe = wm831x_i2c_probe,
-	.remove = wm831x_i2c_remove,
-	.suspend = wm831x_i2c_suspend,
-	.id_table = wm831x_i2c_id,
-};
-
-static int __init wm831x_i2c_init(void)
-{
-	int ret;
-
-	ret = i2c_add_driver(&wm831x_i2c_driver);
-	if (ret != 0)
-		pr_err("Failed to register wm831x I2C driver: %d\n", ret);
-
-	return ret;
-}
-subsys_initcall(wm831x_i2c_init);
-
-static void __exit wm831x_i2c_exit(void)
-{
-	i2c_del_driver(&wm831x_i2c_driver);
-}
-module_exit(wm831x_i2c_exit);
-
-MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
+MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mark Brown");
 MODULE_AUTHOR("Mark Brown");

+ 143 - 0
drivers/mfd/wm831x-i2c.c

@@ -0,0 +1,143 @@
+/*
+ * wm831x-i2c.c  --  I2C access for Wolfson WM831x PMICs
+ *
+ * Copyright 2009,2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/pdata.h>
+
+static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
+				  int bytes, void *dest)
+{
+	struct i2c_client *i2c = wm831x->control_data;
+	int ret;
+	u16 r = cpu_to_be16(reg);
+
+	ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
+	if (ret < 0)
+		return ret;
+	if (ret != 2)
+		return -EIO;
+
+	ret = i2c_master_recv(i2c, dest, bytes);
+	if (ret < 0)
+		return ret;
+	if (ret != bytes)
+		return -EIO;
+	return 0;
+}
+
+/* Currently we allocate the write buffer on the stack; this is OK for
+ * small writes - if we need to do large writes this will need to be
+ * revised.
+ */
+static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
+				   int bytes, void *src)
+{
+	struct i2c_client *i2c = wm831x->control_data;
+	unsigned char msg[bytes + 2];
+	int ret;
+
+	reg = cpu_to_be16(reg);
+	memcpy(&msg[0], &reg, 2);
+	memcpy(&msg[2], src, bytes);
+
+	ret = i2c_master_send(i2c, msg, bytes + 2);
+	if (ret < 0)
+		return ret;
+	if (ret < bytes + 2)
+		return -EIO;
+
+	return 0;
+}
+
+static int wm831x_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct wm831x *wm831x;
+
+	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+	if (wm831x == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm831x);
+	wm831x->dev = &i2c->dev;
+	wm831x->control_data = i2c;
+	wm831x->read_dev = wm831x_i2c_read_device;
+	wm831x->write_dev = wm831x_i2c_write_device;
+
+	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
+}
+
+static int wm831x_i2c_remove(struct i2c_client *i2c)
+{
+	struct wm831x *wm831x = i2c_get_clientdata(i2c);
+
+	wm831x_device_exit(wm831x);
+
+	return 0;
+}
+
+static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+{
+	struct wm831x *wm831x = i2c_get_clientdata(i2c);
+
+	return wm831x_device_suspend(wm831x);
+}
+
+static const struct i2c_device_id wm831x_i2c_id[] = {
+	{ "wm8310", WM8310 },
+	{ "wm8311", WM8311 },
+	{ "wm8312", WM8312 },
+	{ "wm8320", WM8320 },
+	{ "wm8321", WM8321 },
+	{ "wm8325", WM8325 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
+
+
+static struct i2c_driver wm831x_i2c_driver = {
+	.driver = {
+		   .name = "wm831x",
+		   .owner = THIS_MODULE,
+	},
+	.probe = wm831x_i2c_probe,
+	.remove = wm831x_i2c_remove,
+	.suspend = wm831x_i2c_suspend,
+	.id_table = wm831x_i2c_id,
+};
+
+static int __init wm831x_i2c_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&wm831x_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register wm831x I2C driver: %d\n", ret);
+
+	return ret;
+}
+subsys_initcall(wm831x_i2c_init);
+
+static void __exit wm831x_i2c_exit(void)
+{
+	i2c_del_driver(&wm831x_i2c_driver);
+}
+module_exit(wm831x_i2c_exit);

+ 232 - 0
drivers/mfd/wm831x-spi.c

@@ -0,0 +1,232 @@
+/*
+ * wm831x-spi.c  --  SPI access for Wolfson WM831x PMICs
+ *
+ * Copyright 2009,2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <linux/mfd/wm831x/core.h>
+
+static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg,
+				  int bytes, void *dest)
+{
+	u16 tx_val;
+	u16 *d = dest;
+	int r, ret;
+
+	/* Go register at a time */
+	for (r = reg; r < reg + (bytes / 2); r++) {
+		tx_val = r | 0x8000;
+
+		ret = spi_write_then_read(wm831x->control_data,
+					  (u8 *)&tx_val, 2, (u8 *)d, 2);
+		if (ret != 0)
+			return ret;
+
+		*d = be16_to_cpu(*d);
+
+		d++;
+	}
+
+	return 0;
+}
+
+static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg,
+				   int bytes, void *src)
+{
+	struct spi_device *spi = wm831x->control_data;
+	u16 *s = src;
+	u16 data[2];
+	int ret, r;
+
+	/* Go register at a time */
+	for (r = reg; r < reg + (bytes / 2); r++) {
+		data[0] = r;
+		data[1] = *s++;
+
+		ret = spi_write(spi, (char *)&data, sizeof(data));
+		if (ret != 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit wm831x_spi_probe(struct spi_device *spi)
+{
+	struct wm831x *wm831x;
+	enum wm831x_parent type;
+
+	/* Currently SPI support for ID tables is unmerged, we're faking it */
+	if (strcmp(spi->modalias, "wm8310") == 0)
+		type = WM8310;
+	else if (strcmp(spi->modalias, "wm8311") == 0)
+		type = WM8311;
+	else if (strcmp(spi->modalias, "wm8312") == 0)
+		type = WM8312;
+	else if (strcmp(spi->modalias, "wm8320") == 0)
+		type = WM8320;
+	else if (strcmp(spi->modalias, "wm8321") == 0)
+		type = WM8321;
+	else if (strcmp(spi->modalias, "wm8325") == 0)
+		type = WM8325;
+	else {
+		dev_err(&spi->dev, "Unknown device type\n");
+		return -EINVAL;
+	}
+
+	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+	if (wm831x == NULL)
+		return -ENOMEM;
+
+	spi->bits_per_word = 16;
+	spi->mode = SPI_MODE_0;
+
+	dev_set_drvdata(&spi->dev, wm831x);
+	wm831x->dev = &spi->dev;
+	wm831x->control_data = spi;
+	wm831x->read_dev = wm831x_spi_read_device;
+	wm831x->write_dev = wm831x_spi_write_device;
+
+	return wm831x_device_init(wm831x, type, spi->irq);
+}
+
+static int __devexit wm831x_spi_remove(struct spi_device *spi)
+{
+	struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
+
+	wm831x_device_exit(wm831x);
+
+	return 0;
+}
+
+static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m)
+{
+	struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
+
+	return wm831x_device_suspend(wm831x);
+}
+
+static struct spi_driver wm8310_spi_driver = {
+	.driver = {
+		.name	= "wm8310",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm831x_spi_probe,
+	.remove		= __devexit_p(wm831x_spi_remove),
+	.suspend	= wm831x_spi_suspend,
+};
+
+static struct spi_driver wm8311_spi_driver = {
+	.driver = {
+		.name	= "wm8311",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm831x_spi_probe,
+	.remove		= __devexit_p(wm831x_spi_remove),
+	.suspend	= wm831x_spi_suspend,
+};
+
+static struct spi_driver wm8312_spi_driver = {
+	.driver = {
+		.name	= "wm8312",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm831x_spi_probe,
+	.remove		= __devexit_p(wm831x_spi_remove),
+	.suspend	= wm831x_spi_suspend,
+};
+
+static struct spi_driver wm8320_spi_driver = {
+	.driver = {
+		.name	= "wm8320",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm831x_spi_probe,
+	.remove		= __devexit_p(wm831x_spi_remove),
+	.suspend	= wm831x_spi_suspend,
+};
+
+static struct spi_driver wm8321_spi_driver = {
+	.driver = {
+		.name	= "wm8321",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm831x_spi_probe,
+	.remove		= __devexit_p(wm831x_spi_remove),
+	.suspend	= wm831x_spi_suspend,
+};
+
+static struct spi_driver wm8325_spi_driver = {
+	.driver = {
+		.name	= "wm8325",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= wm831x_spi_probe,
+	.remove		= __devexit_p(wm831x_spi_remove),
+	.suspend	= wm831x_spi_suspend,
+};
+
+static int __init wm831x_spi_init(void)
+{
+	int ret;
+
+	ret = spi_register_driver(&wm8310_spi_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM8310 SPI driver: %d\n", ret);
+
+	ret = spi_register_driver(&wm8311_spi_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM8311 SPI driver: %d\n", ret);
+
+	ret = spi_register_driver(&wm8312_spi_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM8312 SPI driver: %d\n", ret);
+
+	ret = spi_register_driver(&wm8320_spi_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM8320 SPI driver: %d\n", ret);
+
+	ret = spi_register_driver(&wm8321_spi_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM8321 SPI driver: %d\n", ret);
+
+	ret = spi_register_driver(&wm8325_spi_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
+
+	return 0;
+}
+subsys_initcall(wm831x_spi_init);
+
+static void __exit wm831x_spi_exit(void)
+{
+	spi_unregister_driver(&wm8325_spi_driver);
+	spi_unregister_driver(&wm8321_spi_driver);
+	spi_unregister_driver(&wm8320_spi_driver);
+	spi_unregister_driver(&wm8312_spi_driver);
+	spi_unregister_driver(&wm8311_spi_driver);
+	spi_unregister_driver(&wm8310_spi_driver);
+}
+module_exit(wm831x_spi_exit);
+
+MODULE_DESCRIPTION("SPI support for WM831x/2x AudioPlus PMICs");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown");

+ 9 - 0
drivers/misc/Kconfig

@@ -62,6 +62,15 @@ config ATMEL_PWM
 	  purposes including software controlled power-efficient backlights
 	  purposes including software controlled power-efficient backlights
 	  on LCD displays, motor control, and waveform generation.
 	  on LCD displays, motor control, and waveform generation.
 
 
+config AB8500_PWM
+	bool "AB8500 PWM support"
+	depends on AB8500_CORE
+	select HAVE_PWM
+	help
+	  This driver exports functions to enable/disble/config/free Pulse
+	  Width Modulation in the Analog Baseband Chip AB8500.
+	  It is used by led and backlight driver to control the intensity.
+
 config ATMEL_TCLIB
 config ATMEL_TCLIB
 	bool "Atmel AT32/AT91 Timer/Counter Library"
 	bool "Atmel AT32/AT91 Timer/Counter Library"
 	depends on (AVR32 || ARCH_AT91)
 	depends on (AVR32 || ARCH_AT91)

+ 1 - 0
drivers/misc/Makefile

@@ -41,3 +41,4 @@ obj-$(CONFIG_VMWARE_BALLOON)	+= vmw_balloon.o
 obj-$(CONFIG_ARM_CHARLCD)	+= arm-charlcd.o
 obj-$(CONFIG_ARM_CHARLCD)	+= arm-charlcd.o
 obj-$(CONFIG_PCH_PHUB)		+= pch_phub.o
 obj-$(CONFIG_PCH_PHUB)		+= pch_phub.o
 obj-y				+= ti-st/
 obj-y				+= ti-st/
+obj-$(CONFIG_AB8500_PWM)	+= ab8500-pwm.o

+ 168 - 0
drivers/misc/ab8500-pwm.c

@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pwm.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+
+/*
+ * PWM Out generators
+ * Bank: 0x10
+ */
+#define AB8500_PWM_OUT_CTRL1_REG	0x60
+#define AB8500_PWM_OUT_CTRL2_REG	0x61
+#define AB8500_PWM_OUT_CTRL7_REG	0x66
+
+/* backlight driver constants */
+#define ENABLE_PWM			1
+#define DISABLE_PWM			0
+
+struct pwm_device {
+	struct device *dev;
+	struct list_head node;
+	const char *label;
+	unsigned int pwm_id;
+};
+
+static LIST_HEAD(pwm_list);
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	int ret = 0;
+	unsigned int higher_val, lower_val;
+	u8 reg;
+
+	/*
+	 * get the first 8 bits that are be written to
+	 * AB8500_PWM_OUT_CTRL1_REG[0:7]
+	 */
+	lower_val = duty_ns & 0x00FF;
+	/*
+	 * get bits [9:10] that are to be written to
+	 * AB8500_PWM_OUT_CTRL2_REG[0:1]
+	 */
+	higher_val = ((duty_ns & 0x0300) >> 8);
+
+	reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2);
+
+	ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+			reg, (u8)lower_val);
+	if (ret < 0)
+		return ret;
+	ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC,
+			(reg + 1), (u8)higher_val);
+
+	return ret;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+	int ret;
+
+	ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+				AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
+				1 << (pwm->pwm_id-1), ENABLE_PWM);
+	if (ret < 0)
+		dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+							pwm->label, ret);
+	return ret;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+	int ret;
+
+	ret = abx500_mask_and_set_register_interruptible(pwm->dev,
+				AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
+				1 << (pwm->pwm_id-1), DISABLE_PWM);
+	if (ret < 0)
+		dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n",
+							pwm->label, ret);
+	return;
+}
+EXPORT_SYMBOL(pwm_disable);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+	struct pwm_device *pwm;
+
+	list_for_each_entry(pwm, &pwm_list, node) {
+		if (pwm->pwm_id == pwm_id) {
+			pwm->label = label;
+			pwm->pwm_id = pwm_id;
+			return pwm;
+		}
+	}
+
+	return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+	pwm_disable(pwm);
+}
+EXPORT_SYMBOL(pwm_free);
+
+static int __devinit ab8500_pwm_probe(struct platform_device *pdev)
+{
+	struct pwm_device *pwm;
+	/*
+	 * Nothing to be done in probe, this is required to get the
+	 * device which is required for ab8500 read and write
+	 */
+	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+	if (pwm == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+	pwm->dev = &pdev->dev;
+	pwm->pwm_id = pdev->id;
+	list_add_tail(&pwm->node, &pwm_list);
+	platform_set_drvdata(pdev, pwm);
+	dev_dbg(pwm->dev, "pwm probe successful\n");
+	return 0;
+}
+
+static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
+{
+	struct pwm_device *pwm = platform_get_drvdata(pdev);
+	list_del(&pwm->node);
+	dev_dbg(&pdev->dev, "pwm driver removed\n");
+	kfree(pwm);
+	return 0;
+}
+
+static struct platform_driver ab8500_pwm_driver = {
+	.driver = {
+		.name = "ab8500-pwm",
+		.owner = THIS_MODULE,
+	},
+	.probe = ab8500_pwm_probe,
+	.remove = __devexit_p(ab8500_pwm_remove),
+};
+
+static int __init ab8500_pwm_init(void)
+{
+	return platform_driver_register(&ab8500_pwm_driver);
+}
+
+static void __exit ab8500_pwm_exit(void)
+{
+	platform_driver_unregister(&ab8500_pwm_driver);
+}
+
+subsys_initcall(ab8500_pwm_init);
+module_exit(ab8500_pwm_exit);
+MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>");
+MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
+MODULE_ALIAS("AB8500 PWM driver");
+MODULE_LICENSE("GPL v2");

+ 2 - 2
drivers/mmc/host/omap_hsmmc.c

@@ -483,8 +483,6 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
 	int ret;
 	int ret;
 
 
 	if (gpio_is_valid(pdata->slots[0].switch_pin)) {
 	if (gpio_is_valid(pdata->slots[0].switch_pin)) {
-		pdata->suspend = omap_hsmmc_suspend_cdirq;
-		pdata->resume = omap_hsmmc_resume_cdirq;
 		if (pdata->slots[0].cover)
 		if (pdata->slots[0].cover)
 			pdata->slots[0].get_cover_state =
 			pdata->slots[0].get_cover_state =
 					omap_hsmmc_get_cover_state;
 					omap_hsmmc_get_cover_state;
@@ -2218,6 +2216,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 				"Unable to grab MMC CD IRQ\n");
 				"Unable to grab MMC CD IRQ\n");
 			goto err_irq_cd;
 			goto err_irq_cd;
 		}
 		}
+		pdata->suspend = omap_hsmmc_suspend_cdirq;
+		pdata->resume = omap_hsmmc_resume_cdirq;
 	}
 	}
 
 
 	omap_hsmmc_disable_irq(host);
 	omap_hsmmc_disable_irq(host);

+ 12 - 0
drivers/mmc/host/sh_mmcif.c

@@ -710,9 +710,21 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	host->bus_width = ios->bus_width;
 	host->bus_width = ios->bus_width;
 }
 }
 
 
+static int sh_mmcif_get_cd(struct mmc_host *mmc)
+{
+	struct sh_mmcif_host *host = mmc_priv(mmc);
+	struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+
+	if (!p->get_cd)
+		return -ENOSYS;
+	else
+		return p->get_cd(host->pd);
+}
+
 static struct mmc_host_ops sh_mmcif_ops = {
 static struct mmc_host_ops sh_mmcif_ops = {
 	.request	= sh_mmcif_request,
 	.request	= sh_mmcif_request,
 	.set_ios	= sh_mmcif_set_ios,
 	.set_ios	= sh_mmcif_set_ios,
+	.get_cd		= sh_mmcif_get_cd,
 };
 };
 
 
 static void sh_mmcif_detect(struct mmc_host *mmc)
 static void sh_mmcif_detect(struct mmc_host *mmc)

+ 25 - 5
drivers/mmc/host/tmio_mmc.c

@@ -658,14 +658,21 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
 static int tmio_mmc_start_data(struct tmio_mmc_host *host,
 static int tmio_mmc_start_data(struct tmio_mmc_host *host,
 	struct mmc_data *data)
 	struct mmc_data *data)
 {
 {
+	struct mfd_cell *cell = host->pdev->dev.platform_data;
+	struct tmio_mmc_data *pdata = cell->driver_data;
+
 	pr_debug("setup data transfer: blocksize %08x  nr_blocks %d\n",
 	pr_debug("setup data transfer: blocksize %08x  nr_blocks %d\n",
 		 data->blksz, data->blocks);
 		 data->blksz, data->blocks);
 
 
-	/* Hardware cannot perform 1 and 2 byte requests in 4 bit mode */
-	if (data->blksz < 4 && host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
-		pr_err("%s: %d byte block unsupported in 4 bit mode\n",
-		       mmc_hostname(host->mmc), data->blksz);
-		return -EINVAL;
+	/* Some hardware cannot perform 2 byte requests in 4 bit mode */
+	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
+		int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES;
+
+		if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) {
+			pr_err("%s: %d byte block unsupported in 4 bit mode\n",
+			       mmc_hostname(host->mmc), data->blksz);
+			return -EINVAL;
+		}
 	}
 	}
 
 
 	tmio_mmc_init_sg(host, data);
 	tmio_mmc_init_sg(host, data);
@@ -756,10 +763,23 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
 		(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1;
 		(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1;
 }
 }
 
 
+static int tmio_mmc_get_cd(struct mmc_host *mmc)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	struct mfd_cell	*cell = host->pdev->dev.platform_data;
+	struct tmio_mmc_data *pdata = cell->driver_data;
+
+	if (!pdata->get_cd)
+		return -ENOSYS;
+	else
+		return pdata->get_cd(host->pdev);
+}
+
 static const struct mmc_host_ops tmio_mmc_ops = {
 static const struct mmc_host_ops tmio_mmc_ops = {
 	.request	= tmio_mmc_request,
 	.request	= tmio_mmc_request,
 	.set_ios	= tmio_mmc_set_ios,
 	.set_ios	= tmio_mmc_set_ios,
 	.get_ro         = tmio_mmc_get_ro,
 	.get_ro         = tmio_mmc_get_ro,
+	.get_cd		= tmio_mmc_get_cd,
 };
 };
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM

+ 0 - 1
drivers/power/Kconfig

@@ -182,7 +182,6 @@ config CHARGER_ISP1704
 config CHARGER_TWL4030
 config CHARGER_TWL4030
 	tristate "OMAP TWL4030 BCI charger driver"
 	tristate "OMAP TWL4030 BCI charger driver"
 	depends on TWL4030_CORE
 	depends on TWL4030_CORE
-	depends on BROKEN
 	help
 	help
 	  Say Y here to enable support for TWL4030 Battery Charge Interface.
 	  Say Y here to enable support for TWL4030 Battery Charge Interface.
 
 

+ 50 - 36
drivers/regulator/ab8500.c

@@ -21,6 +21,7 @@
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/ab8500.h>
 #include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/ab8500.h>
 #include <linux/regulator/ab8500.h>
@@ -33,9 +34,11 @@
  * @max_uV: maximum voltage (for variable voltage supplies)
  * @max_uV: maximum voltage (for variable voltage supplies)
  * @min_uV: minimum voltage (for variable voltage supplies)
  * @min_uV: minimum voltage (for variable voltage supplies)
  * @fixed_uV: typical voltage (for fixed voltage supplies)
  * @fixed_uV: typical voltage (for fixed voltage supplies)
+ * @update_bank: bank to control on/off
  * @update_reg: register to control on/off
  * @update_reg: register to control on/off
  * @mask: mask to enable/disable regulator
  * @mask: mask to enable/disable regulator
  * @enable: bits to enable the regulator in normal(high power) mode
  * @enable: bits to enable the regulator in normal(high power) mode
+ * @voltage_bank: bank to control regulator voltage
  * @voltage_reg: register to control regulator voltage
  * @voltage_reg: register to control regulator voltage
  * @voltage_mask: mask to control regulator voltage
  * @voltage_mask: mask to control regulator voltage
  * @supported_voltages: supported voltage table
  * @supported_voltages: supported voltage table
@@ -49,11 +52,13 @@ struct ab8500_regulator_info {
 	int max_uV;
 	int max_uV;
 	int min_uV;
 	int min_uV;
 	int fixed_uV;
 	int fixed_uV;
-	int update_reg;
-	int mask;
-	int enable;
-	int voltage_reg;
-	int voltage_mask;
+	u8 update_bank;
+	u8 update_reg;
+	u8 mask;
+	u8 enable;
+	u8 voltage_bank;
+	u8 voltage_reg;
+	u8 voltage_mask;
 	int const *supported_voltages;
 	int const *supported_voltages;
 	int voltages_len;
 	int voltages_len;
 };
 };
@@ -97,8 +102,8 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev)
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	ret = ab8500_set_bits(info->ab8500, info->update_reg,
-			info->mask, info->enable);
+	ret = abx500_mask_and_set_register_interruptible(info->dev,
+		info->update_bank, info->update_reg, info->mask, info->enable);
 	if (ret < 0)
 	if (ret < 0)
 		dev_err(rdev_get_dev(rdev),
 		dev_err(rdev_get_dev(rdev),
 			"couldn't set enable bits for regulator\n");
 			"couldn't set enable bits for regulator\n");
@@ -114,8 +119,8 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev)
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	ret = ab8500_set_bits(info->ab8500, info->update_reg,
-			info->mask, 0x0);
+	ret = abx500_mask_and_set_register_interruptible(info->dev,
+		info->update_bank, info->update_reg, info->mask, 0x0);
 	if (ret < 0)
 	if (ret < 0)
 		dev_err(rdev_get_dev(rdev),
 		dev_err(rdev_get_dev(rdev),
 			"couldn't set disable bits for regulator\n");
 			"couldn't set disable bits for regulator\n");
@@ -126,19 +131,21 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
 {
 {
 	int regulator_id, ret;
 	int regulator_id, ret;
 	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
 	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	u8 value;
 
 
 	regulator_id = rdev_get_id(rdev);
 	regulator_id = rdev_get_id(rdev);
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	ret = ab8500_read(info->ab8500, info->update_reg);
+	ret = abx500_get_register_interruptible(info->dev,
+		info->update_bank, info->update_reg, &value);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(rdev_get_dev(rdev),
 		dev_err(rdev_get_dev(rdev),
 			"couldn't read 0x%x register\n", info->update_reg);
 			"couldn't read 0x%x register\n", info->update_reg);
 		return ret;
 		return ret;
 	}
 	}
 
 
-	if (ret & info->mask)
+	if (value & info->mask)
 		return true;
 		return true;
 	else
 	else
 		return false;
 		return false;
@@ -165,14 +172,16 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
 
 
 static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
 static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
 {
 {
-	int regulator_id, ret, val;
+	int regulator_id, ret;
 	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
 	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	u8 value;
 
 
 	regulator_id = rdev_get_id(rdev);
 	regulator_id = rdev_get_id(rdev);
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 	if (regulator_id >= AB8500_NUM_REGULATORS)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	ret = ab8500_read(info->ab8500, info->voltage_reg);
+	ret = abx500_get_register_interruptible(info->dev, info->voltage_bank,
+		info->voltage_reg, &value);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(rdev_get_dev(rdev),
 		dev_err(rdev_get_dev(rdev),
 			"couldn't read voltage reg for regulator\n");
 			"couldn't read voltage reg for regulator\n");
@@ -180,11 +189,11 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
 	}
 	}
 
 
 	/* vintcore has a different layout */
 	/* vintcore has a different layout */
-	val = ret & info->voltage_mask;
+	value &= info->voltage_mask;
 	if (regulator_id == AB8500_LDO_INTCORE)
 	if (regulator_id == AB8500_LDO_INTCORE)
-		ret = info->supported_voltages[val >> 0x3];
+		ret = info->supported_voltages[value >> 0x3];
 	else
 	else
-		ret = info->supported_voltages[val];
+		ret = info->supported_voltages[value];
 
 
 	return ret;
 	return ret;
 }
 }
@@ -224,8 +233,9 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
 	}
 	}
 
 
 	/* set the registers for the request */
 	/* set the registers for the request */
-	ret = ab8500_set_bits(info->ab8500, info->voltage_reg,
-				info->voltage_mask, ret);
+	ret = abx500_mask_and_set_register_interruptible(info->dev,
+		info->voltage_bank, info->voltage_reg,
+		info->voltage_mask, (u8)ret);
 	if (ret < 0)
 	if (ret < 0)
 		dev_err(rdev_get_dev(rdev),
 		dev_err(rdev_get_dev(rdev),
 		"couldn't set voltage reg for regulator\n");
 		"couldn't set voltage reg for regulator\n");
@@ -262,9 +272,9 @@ static struct regulator_ops ab8500_ldo_fixed_ops = {
 	.list_voltage	= ab8500_list_voltage,
 	.list_voltage	= ab8500_list_voltage,
 };
 };
 
 
-#define AB8500_LDO(_id, min, max, reg, reg_mask, reg_enable,	\
-		volt_reg, volt_mask, voltages,			\
-			len_volts)				\
+#define AB8500_LDO(_id, min, max, bank, reg, reg_mask,		\
+		reg_enable, volt_bank, volt_reg, volt_mask,	\
+		voltages, len_volts)				\
 {								\
 {								\
 	.desc	= {						\
 	.desc	= {						\
 		.name	= "LDO-" #_id,				\
 		.name	= "LDO-" #_id,				\
@@ -275,9 +285,11 @@ static struct regulator_ops ab8500_ldo_fixed_ops = {
 	},							\
 	},							\
 	.min_uV		= (min) * 1000,				\
 	.min_uV		= (min) * 1000,				\
 	.max_uV		= (max) * 1000,				\
 	.max_uV		= (max) * 1000,				\
+	.update_bank	= bank,					\
 	.update_reg	= reg,					\
 	.update_reg	= reg,					\
 	.mask		= reg_mask,				\
 	.mask		= reg_mask,				\
 	.enable		= reg_enable,				\
 	.enable		= reg_enable,				\
+	.voltage_bank	= volt_bank,				\
 	.voltage_reg	= volt_reg,				\
 	.voltage_reg	= volt_reg,				\
 	.voltage_mask	= volt_mask,				\
 	.voltage_mask	= volt_mask,				\
 	.supported_voltages = voltages,				\
 	.supported_voltages = voltages,				\
@@ -285,8 +297,8 @@ static struct regulator_ops ab8500_ldo_fixed_ops = {
 	.fixed_uV	= 0,					\
 	.fixed_uV	= 0,					\
 }
 }
 
 
-#define AB8500_FIXED_LDO(_id, fixed, reg, reg_mask,	\
-				reg_enable)		\
+#define AB8500_FIXED_LDO(_id, fixed, bank, reg,		\
+			reg_mask, reg_enable)		\
 {							\
 {							\
 	.desc	= {					\
 	.desc	= {					\
 		.name	= "LDO-" #_id,			\
 		.name	= "LDO-" #_id,			\
@@ -296,6 +308,7 @@ static struct regulator_ops ab8500_ldo_fixed_ops = {
 		.owner	= THIS_MODULE,			\
 		.owner	= THIS_MODULE,			\
 	},						\
 	},						\
 	.fixed_uV	= fixed * 1000,			\
 	.fixed_uV	= fixed * 1000,			\
+	.update_bank	= bank,				\
 	.update_reg	= reg,				\
 	.update_reg	= reg,				\
 	.mask		= reg_mask,			\
 	.mask		= reg_mask,			\
 	.enable		= reg_enable,			\
 	.enable		= reg_enable,			\
@@ -304,28 +317,29 @@ static struct regulator_ops ab8500_ldo_fixed_ops = {
 static struct ab8500_regulator_info ab8500_regulator_info[] = {
 static struct ab8500_regulator_info ab8500_regulator_info[] = {
 	/*
 	/*
 	 * Variable Voltage LDOs
 	 * Variable Voltage LDOs
-	 * name, min uV, max uV, ctrl reg, reg mask, enable mask,
-	 *	volt ctrl reg, volt ctrl mask, volt table, num supported volts
+	 * name, min uV, max uV, ctrl bank, ctrl reg, reg mask, enable mask,
+	 *      volt ctrl bank, volt ctrl reg, volt ctrl mask, volt table,
+	 *      num supported volts
 	 */
 	 */
-	AB8500_LDO(AUX1, 1100, 3300, 0x0409, 0x3, 0x1, 0x041f, 0xf,
+	AB8500_LDO(AUX1, 1100, 3300, 0x04, 0x09, 0x3, 0x1, 0x04, 0x1f, 0xf,
 			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
 			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
-	AB8500_LDO(AUX2, 1100, 3300, 0x0409, 0xc, 0x4, 0x0420, 0xf,
+	AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf,
 			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
 			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
-	AB8500_LDO(AUX3, 1100, 3300, 0x040a, 0x3, 0x1, 0x0421, 0xf,
+	AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf,
 			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
 			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
-	AB8500_LDO(INTCORE, 1100, 3300, 0x0380, 0x4, 0x4, 0x0380, 0x38,
+	AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x4, 0x4, 0x03, 0x80, 0x38,
 		ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)),
 		ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)),
 
 
 	/*
 	/*
 	 * Fixed Voltage LDOs
 	 * Fixed Voltage LDOs
-	 *		 name,	o/p uV, ctrl reg, enable, disable
+	 *		 name,	o/p uV, ctrl bank, ctrl reg, enable, disable
 	 */
 	 */
-	AB8500_FIXED_LDO(TVOUT,	  2000,   0x0380,   0x2,    0x2),
-	AB8500_FIXED_LDO(AUDIO,   2000,   0x0383,   0x2,    0x2),
-	AB8500_FIXED_LDO(ANAMIC1, 2050,   0x0383,   0x4,    0x4),
-	AB8500_FIXED_LDO(ANAMIC2, 2050,   0x0383,   0x8,    0x8),
-	AB8500_FIXED_LDO(DMIC,    1800,   0x0383,   0x10,   0x10),
-	AB8500_FIXED_LDO(ANA,     1200,   0x0383,   0xc,    0x4),
+	AB8500_FIXED_LDO(TVOUT,	  2000, 0x03,      0x80,     0x2,    0x2),
+	AB8500_FIXED_LDO(AUDIO,   2000, 0x03,      0x83,     0x2,    0x2),
+	AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03,      0x83,     0x4,    0x4),
+	AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03,      0x83,     0x8,    0x8),
+	AB8500_FIXED_LDO(DMIC,    1800, 0x03,      0x83,     0x10,   0x10),
+	AB8500_FIXED_LDO(ANA,     1200, 0x03,      0x83,     0xc,    0x4),
 };
 };
 
 
 static inline struct ab8500_regulator_info *find_regulator_info(int id)
 static inline struct ab8500_regulator_info *find_regulator_info(int id)

+ 245 - 25
drivers/regulator/max8998.c

@@ -39,6 +39,11 @@ struct max8998_data {
 	struct max8998_dev	*iodev;
 	struct max8998_dev	*iodev;
 	int			num_regulators;
 	int			num_regulators;
 	struct regulator_dev	**rdev;
 	struct regulator_dev	**rdev;
+	u8                      buck1_vol[4]; /* voltages for selection */
+	u8                      buck2_vol[2];
+	unsigned int		buck1_idx; /* index to last changed voltage */
+					   /* value in a set */
+	unsigned int		buck2_idx;
 };
 };
 
 
 struct voltage_map_desc {
 struct voltage_map_desc {
@@ -173,6 +178,7 @@ static int max8998_get_enable_register(struct regulator_dev *rdev,
 static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
 static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
 {
 {
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
 	int ret, reg, shift = 8;
 	int ret, reg, shift = 8;
 	u8 val;
 	u8 val;
 
 
@@ -180,7 +186,7 @@ static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	ret = max8998_read_reg(max8998->iodev, reg, &val);
+	ret = max8998_read_reg(i2c, reg, &val);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
@@ -190,31 +196,34 @@ static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
 static int max8998_ldo_enable(struct regulator_dev *rdev)
 static int max8998_ldo_enable(struct regulator_dev *rdev)
 {
 {
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
 	int reg, shift = 8, ret;
 	int reg, shift = 8, ret;
 
 
 	ret = max8998_get_enable_register(rdev, &reg, &shift);
 	ret = max8998_get_enable_register(rdev, &reg, &shift);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	return max8998_update_reg(max8998->iodev, reg, 1<<shift, 1<<shift);
+	return max8998_update_reg(i2c, reg, 1<<shift, 1<<shift);
 }
 }
 
 
 static int max8998_ldo_disable(struct regulator_dev *rdev)
 static int max8998_ldo_disable(struct regulator_dev *rdev)
 {
 {
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
 	int reg, shift = 8, ret;
 	int reg, shift = 8, ret;
 
 
 	ret = max8998_get_enable_register(rdev, &reg, &shift);
 	ret = max8998_get_enable_register(rdev, &reg, &shift);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	return max8998_update_reg(max8998->iodev, reg, 0, 1<<shift);
+	return max8998_update_reg(i2c, reg, 0, 1<<shift);
 }
 }
 
 
 static int max8998_get_voltage_register(struct regulator_dev *rdev,
 static int max8998_get_voltage_register(struct regulator_dev *rdev,
 				int *_reg, int *_shift, int *_mask)
 				int *_reg, int *_shift, int *_mask)
 {
 {
 	int ldo = max8998_get_ldo(rdev);
 	int ldo = max8998_get_ldo(rdev);
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	int reg, shift = 0, mask = 0xff;
 	int reg, shift = 0, mask = 0xff;
 
 
 	switch (ldo) {
 	switch (ldo) {
@@ -251,10 +260,10 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev,
 		reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12);
 		reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12);
 		break;
 		break;
 	case MAX8998_BUCK1:
 	case MAX8998_BUCK1:
-		reg = MAX8998_REG_BUCK1_DVSARM1;
+		reg = MAX8998_REG_BUCK1_VOLTAGE1 + max8998->buck1_idx;
 		break;
 		break;
 	case MAX8998_BUCK2:
 	case MAX8998_BUCK2:
-		reg = MAX8998_REG_BUCK2_DVSINT1;
+		reg = MAX8998_REG_BUCK2_VOLTAGE1 + max8998->buck2_idx;
 		break;
 		break;
 	case MAX8998_BUCK3:
 	case MAX8998_BUCK3:
 		reg = MAX8998_REG_BUCK3;
 		reg = MAX8998_REG_BUCK3;
@@ -276,6 +285,7 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev,
 static int max8998_get_voltage(struct regulator_dev *rdev)
 static int max8998_get_voltage(struct regulator_dev *rdev)
 {
 {
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
 	int reg, shift = 0, mask, ret;
 	int reg, shift = 0, mask, ret;
 	u8 val;
 	u8 val;
 
 
@@ -283,7 +293,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	ret = max8998_read_reg(max8998->iodev, reg, &val);
+	ret = max8998_read_reg(i2c, reg, &val);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
@@ -293,18 +303,16 @@ static int max8998_get_voltage(struct regulator_dev *rdev)
 	return max8998_list_voltage(rdev, val);
 	return max8998_list_voltage(rdev, val);
 }
 }
 
 
-static int max8998_set_voltage(struct regulator_dev *rdev,
+static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
 				int min_uV, int max_uV)
 				int min_uV, int max_uV)
 {
 {
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
 	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
 	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
 	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
-	int previous_vol = 0;
 	const struct voltage_map_desc *desc;
 	const struct voltage_map_desc *desc;
 	int ldo = max8998_get_ldo(rdev);
 	int ldo = max8998_get_ldo(rdev);
 	int reg, shift = 0, mask, ret;
 	int reg, shift = 0, mask, ret;
 	int i = 0;
 	int i = 0;
-	u8 val;
-	bool en_ramp = false;
 
 
 	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
 	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
 		return -EINVAL;
 		return -EINVAL;
@@ -327,24 +335,155 @@ static int max8998_set_voltage(struct regulator_dev *rdev,
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	/* wait for RAMP_UP_DELAY if rdev is BUCK1/2 and
-	 * ENRAMP is ON */
-	if (ldo == MAX8998_BUCK1 || ldo == MAX8998_BUCK2) {
-		max8998_read_reg(max8998->iodev, MAX8998_REG_ONOFF4, &val);
-		if (val & (1 << 4)) {
-			en_ramp = true;
-			previous_vol = max8998_get_voltage(rdev);
-		}
+	ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+
+	return ret;
+}
+
+static inline void buck1_gpio_set(int gpio1, int gpio2, int v)
+{
+	gpio_set_value(gpio1, v & 0x1);
+	gpio_set_value(gpio2, (v >> 1) & 0x1);
+}
+
+static inline void buck2_gpio_set(int gpio, int v)
+{
+	gpio_set_value(gpio, v & 0x1);
+}
+
+static int max8998_set_voltage_buck(struct regulator_dev *rdev,
+				    int min_uV, int max_uV)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct max8998_platform_data *pdata =
+		dev_get_platdata(max8998->iodev->dev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	const struct voltage_map_desc *desc;
+	int buck = max8998_get_ldo(rdev);
+	int reg, shift = 0, mask, ret;
+	int difference = 0, i = 0, j = 0, previous_vol = 0;
+	u8 val = 0;
+	static u8 buck1_last_val;
+
+	if (buck >= ARRAY_SIZE(ldo_voltage_map))
+		return -EINVAL;
+
+	desc = ldo_voltage_map[buck];
+
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (max_vol < desc->min || min_vol > desc->max)
+		return -EINVAL;
+
+	while (desc->min + desc->step*i < min_vol &&
+	       desc->min + desc->step*i < desc->max)
+		i++;
+
+	if (desc->min + desc->step*i > max_vol)
+		return -EINVAL;
+
+	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	previous_vol = max8998_get_voltage(rdev);
+
+	/* Check if voltage needs to be changed */
+	/* if previous_voltage equal new voltage, return */
+	if (previous_vol == max8998_list_voltage(rdev, i)) {
+		dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
+			previous_vol, max8998_list_voltage(rdev, i));
+		return ret;
 	}
 	}
 
 
-	ret = max8998_update_reg(max8998->iodev, reg, i<<shift, mask<<shift);
+	switch (buck) {
+	case MAX8998_BUCK1:
+		dev_dbg(max8998->dev,
+			"BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n\
+			 buck1_vol3:%d, buck1_vol4:%d\n",
+			i, max8998->buck1_vol[0], max8998->buck1_vol[1],
+			max8998->buck1_vol[2], max8998->buck1_vol[3]);
+
+		if (gpio_is_valid(pdata->buck1_set1) &&
+		    gpio_is_valid(pdata->buck1_set2)) {
+
+			/* check if requested voltage */
+			/* value is already defined */
+			for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) {
+				if (max8998->buck1_vol[j] == i) {
+					max8998->buck1_idx = j;
+					buck1_gpio_set(pdata->buck1_set1,
+						       pdata->buck1_set2, j);
+					goto buck1_exit;
+				}
+			}
+
+			/* no predefine regulator found */
+			max8998->buck1_idx = (buck1_last_val % 2) + 2;
+			dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
+				max8998->buck1_idx);
+			max8998->buck1_vol[max8998->buck1_idx] = i;
+			ret = max8998_get_voltage_register(rdev, &reg,
+							   &shift,
+							   &mask);
+			ret = max8998_write_reg(i2c, reg, i);
+			buck1_gpio_set(pdata->buck1_set1,
+				       pdata->buck1_set2, max8998->buck1_idx);
+			buck1_last_val++;
+buck1_exit:
+			dev_dbg(max8998->dev, "%s: SET1:%d, SET2:%d\n",
+				i2c->name, gpio_get_value(pdata->buck1_set1),
+				gpio_get_value(pdata->buck1_set2));
+			break;
+		} else {
+			ret = max8998_write_reg(i2c, reg, i);
+		}
+		break;
+
+	case MAX8998_BUCK2:
+		dev_dbg(max8998->dev,
+			"BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
+			, i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
+		if (gpio_is_valid(pdata->buck2_set3)) {
+			if (max8998->buck2_vol[0] == i) {
+				max8998->buck1_idx = 0;
+				buck2_gpio_set(pdata->buck2_set3, 0);
+			} else {
+				max8998->buck1_idx = 1;
+				ret = max8998_get_voltage_register(rdev, &reg,
+								   &shift,
+								   &mask);
+				ret = max8998_write_reg(i2c, reg, i);
+				max8998->buck2_vol[1] = i;
+				buck2_gpio_set(pdata->buck2_set3, 1);
+			}
+			dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
+				gpio_get_value(pdata->buck2_set3));
+		} else {
+			ret = max8998_write_reg(i2c, reg, i);
+		}
+		break;
 
 
-	if (en_ramp == true) {
-		int difference = desc->min + desc->step*i - previous_vol/1000;
-		if (difference > 0)
-			udelay(difference / ((val & 0x0f) + 1));
+	case MAX8998_BUCK3:
+	case MAX8998_BUCK4:
+		ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+		break;
 	}
 	}
 
 
+	/* Voltage stabilization */
+	max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val);
+
+	/* lp3974 hasn't got ENRAMP bit - ramp is assumed as true */
+	/* MAX8998 has ENRAMP bit implemented, so test it*/
+	if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP))
+		return ret;
+
+	difference = desc->min + desc->step*i - previous_vol/1000;
+	if (difference > 0)
+		udelay(difference / ((val & 0x0f) + 1));
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -354,7 +493,7 @@ static struct regulator_ops max8998_ldo_ops = {
 	.enable			= max8998_ldo_enable,
 	.enable			= max8998_ldo_enable,
 	.disable		= max8998_ldo_disable,
 	.disable		= max8998_ldo_disable,
 	.get_voltage		= max8998_get_voltage,
 	.get_voltage		= max8998_get_voltage,
-	.set_voltage		= max8998_set_voltage,
+	.set_voltage		= max8998_set_voltage_ldo,
 	.set_suspend_enable	= max8998_ldo_enable,
 	.set_suspend_enable	= max8998_ldo_enable,
 	.set_suspend_disable	= max8998_ldo_disable,
 	.set_suspend_disable	= max8998_ldo_disable,
 };
 };
@@ -365,7 +504,7 @@ static struct regulator_ops max8998_buck_ops = {
 	.enable			= max8998_ldo_enable,
 	.enable			= max8998_ldo_enable,
 	.disable		= max8998_ldo_disable,
 	.disable		= max8998_ldo_disable,
 	.get_voltage		= max8998_get_voltage,
 	.get_voltage		= max8998_get_voltage,
-	.set_voltage		= max8998_set_voltage,
+	.set_voltage		= max8998_set_voltage_buck,
 	.set_suspend_enable	= max8998_ldo_enable,
 	.set_suspend_enable	= max8998_ldo_enable,
 	.set_suspend_disable	= max8998_ldo_disable,
 	.set_suspend_disable	= max8998_ldo_disable,
 };
 };
@@ -538,6 +677,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
 	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
 	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
 	struct regulator_dev **rdev;
 	struct regulator_dev **rdev;
 	struct max8998_data *max8998;
 	struct max8998_data *max8998;
+	struct i2c_client *i2c;
 	int i, ret, size;
 	int i, ret, size;
 
 
 	if (!pdata) {
 	if (!pdata) {
@@ -561,6 +701,86 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
 	max8998->iodev = iodev;
 	max8998->iodev = iodev;
 	max8998->num_regulators = pdata->num_regulators;
 	max8998->num_regulators = pdata->num_regulators;
 	platform_set_drvdata(pdev, max8998);
 	platform_set_drvdata(pdev, max8998);
+	i2c = max8998->iodev->i2c;
+
+	/* NOTE: */
+	/* For unused GPIO NOT marked as -1 (thereof equal to 0)  WARN_ON */
+	/* will be displayed */
+
+	/* Check if MAX8998 voltage selection GPIOs are defined */
+	if (gpio_is_valid(pdata->buck1_set1) &&
+	    gpio_is_valid(pdata->buck1_set2)) {
+		/* Check if SET1 is not equal to 0 */
+		if (!pdata->buck1_set1) {
+			printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n");
+			WARN_ON(!pdata->buck1_set1);
+			return -EIO;
+		}
+		/* Check if SET2 is not equal to 0 */
+		if (!pdata->buck1_set2) {
+			printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n");
+			WARN_ON(!pdata->buck1_set2);
+			return -EIO;
+		}
+
+		gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1");
+		gpio_direction_output(pdata->buck1_set1,
+				      max8998->buck1_idx & 0x1);
+
+
+		gpio_request(pdata->buck1_set2, "MAX8998 BUCK1_SET2");
+		gpio_direction_output(pdata->buck1_set2,
+				      (max8998->buck1_idx >> 1) & 0x1);
+		/* Set predefined value for BUCK1 register 1 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       != (pdata->buck1_max_voltage1 / 1000))
+			i++;
+		printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
+		max8998->buck1_vol[0] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
+
+		/* Set predefined value for BUCK1 register 2 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       != (pdata->buck1_max_voltage2 / 1000))
+			i++;
+
+		max8998->buck1_vol[1] = i;
+		printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i)
+			+ ret;
+		if (ret)
+			return ret;
+
+	}
+
+	if (gpio_is_valid(pdata->buck2_set3)) {
+		/* Check if SET3 is not equal to 0 */
+		if (!pdata->buck2_set3) {
+			printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n");
+			WARN_ON(!pdata->buck2_set3);
+			return -EIO;
+		}
+		gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3");
+		gpio_direction_output(pdata->buck2_set3,
+				      max8998->buck2_idx & 0x1);
+
+		/* BUCK2 - set preset default voltage value to buck2_vol[0] */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       != (pdata->buck2_max_voltage / 1000))
+			i++;
+		printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
+		max8998->buck2_vol[0] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
+		if (ret)
+			return ret;
+
+	}
 
 
 	for (i = 0; i < pdata->num_regulators; i++) {
 	for (i = 0; i < pdata->num_regulators; i++) {
 		const struct voltage_map_desc *desc;
 		const struct voltage_map_desc *desc;

+ 15 - 4
drivers/rtc/Kconfig

@@ -196,6 +196,16 @@ config RTC_DRV_MAX8925
 	  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 rtc-max8925.
 	  will be called rtc-max8925.
 
 
+config RTC_DRV_MAX8998
+	tristate "Maxim MAX8998"
+	depends on MFD_MAX8998
+	help
+	  If you say yes here you will get support for the
+	  RTC of Maxim MAX8998 PMIC.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max8998.
+
 config RTC_DRV_RS5C372
 config RTC_DRV_RS5C372
 	tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
 	tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
 	help
 	help
@@ -926,11 +936,12 @@ config RTC_DRV_PCAP
 	  If you say Y here you will get support for the RTC found on
 	  If you say Y here you will get support for the RTC found on
 	  the PCAP2 ASIC used on some Motorola phones.
 	  the PCAP2 ASIC used on some Motorola phones.
 
 
-config RTC_DRV_MC13783
-	depends on MFD_MC13783
-	tristate "Freescale MC13783 RTC"
+config RTC_DRV_MC13XXX
+	depends on MFD_MC13XXX
+	tristate "Freescale MC13xxx RTC"
 	help
 	help
-	  This enables support for the Freescale MC13783 PMIC RTC
+	  This enables support for the RTCs found on Freescale's PMICs
+	  MC13783 and MC13892.
 
 
 config RTC_DRV_MPC5121
 config RTC_DRV_MPC5121
 	tristate "Freescale MPC5121 built-in RTC"
 	tristate "Freescale MPC5121 built-in RTC"

+ 2 - 1
drivers/rtc/Makefile

@@ -60,8 +60,9 @@ obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
 obj-$(CONFIG_RTC_MXC)		+= rtc-mxc.o
 obj-$(CONFIG_RTC_MXC)		+= rtc-mxc.o
 obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX8925)	+= rtc-max8925.o
 obj-$(CONFIG_RTC_DRV_MAX8925)	+= rtc-max8925.o
+obj-$(CONFIG_RTC_DRV_MAX8998)	+= rtc-max8998.o
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
-obj-$(CONFIG_RTC_DRV_MC13783)	+= rtc-mc13783.o
+obj-$(CONFIG_RTC_DRV_MC13XXX)	+= rtc-mc13xxx.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MPC5121)	+= rtc-mpc5121.o
 obj-$(CONFIG_RTC_DRV_MPC5121)	+= rtc-mpc5121.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o

+ 53 - 50
drivers/rtc/rtc-ab8500.c

@@ -14,26 +14,26 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
 #include <linux/rtc.h>
+#include <linux/mfd/abx500.h>
 #include <linux/mfd/ab8500.h>
 #include <linux/mfd/ab8500.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 
 
-#define AB8500_RTC_SOFF_STAT_REG	0x0F00
-#define AB8500_RTC_CC_CONF_REG		0x0F01
-#define AB8500_RTC_READ_REQ_REG		0x0F02
-#define AB8500_RTC_WATCH_TSECMID_REG	0x0F03
-#define AB8500_RTC_WATCH_TSECHI_REG	0x0F04
-#define AB8500_RTC_WATCH_TMIN_LOW_REG	0x0F05
-#define AB8500_RTC_WATCH_TMIN_MID_REG	0x0F06
-#define AB8500_RTC_WATCH_TMIN_HI_REG	0x0F07
-#define AB8500_RTC_ALRM_MIN_LOW_REG	0x0F08
-#define AB8500_RTC_ALRM_MIN_MID_REG	0x0F09
-#define AB8500_RTC_ALRM_MIN_HI_REG	0x0F0A
-#define AB8500_RTC_STAT_REG		0x0F0B
-#define AB8500_RTC_BKUP_CHG_REG		0x0F0C
-#define AB8500_RTC_FORCE_BKUP_REG	0x0F0D
-#define AB8500_RTC_CALIB_REG		0x0F0E
-#define AB8500_RTC_SWITCH_STAT_REG	0x0F0F
-#define AB8500_REV_REG			0x1080
+#define AB8500_RTC_SOFF_STAT_REG	0x00
+#define AB8500_RTC_CC_CONF_REG		0x01
+#define AB8500_RTC_READ_REQ_REG		0x02
+#define AB8500_RTC_WATCH_TSECMID_REG	0x03
+#define AB8500_RTC_WATCH_TSECHI_REG	0x04
+#define AB8500_RTC_WATCH_TMIN_LOW_REG	0x05
+#define AB8500_RTC_WATCH_TMIN_MID_REG	0x06
+#define AB8500_RTC_WATCH_TMIN_HI_REG	0x07
+#define AB8500_RTC_ALRM_MIN_LOW_REG	0x08
+#define AB8500_RTC_ALRM_MIN_MID_REG	0x09
+#define AB8500_RTC_ALRM_MIN_HI_REG	0x0A
+#define AB8500_RTC_STAT_REG		0x0B
+#define AB8500_RTC_BKUP_CHG_REG		0x0C
+#define AB8500_RTC_FORCE_BKUP_REG	0x0D
+#define AB8500_RTC_CALIB_REG		0x0E
+#define AB8500_RTC_SWITCH_STAT_REG	0x0F
 
 
 /* RtcReadRequest bits */
 /* RtcReadRequest bits */
 #define RTC_READ_REQUEST		0x01
 #define RTC_READ_REQUEST		0x01
@@ -46,13 +46,13 @@
 #define COUNTS_PER_SEC			(0xF000 / 60)
 #define COUNTS_PER_SEC			(0xF000 / 60)
 #define AB8500_RTC_EPOCH		2000
 #define AB8500_RTC_EPOCH		2000
 
 
-static const unsigned long ab8500_rtc_time_regs[] = {
+static const u8 ab8500_rtc_time_regs[] = {
 	AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
 	AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
 	AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG,
 	AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG,
 	AB8500_RTC_WATCH_TSECMID_REG
 	AB8500_RTC_WATCH_TSECMID_REG
 };
 };
 
 
-static const unsigned long ab8500_rtc_alarm_regs[] = {
+static const u8 ab8500_rtc_alarm_regs[] = {
 	AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG,
 	AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG,
 	AB8500_RTC_ALRM_MIN_LOW_REG
 	AB8500_RTC_ALRM_MIN_LOW_REG
 };
 };
@@ -76,29 +76,30 @@ static unsigned long get_elapsed_seconds(int year)
 
 
 static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
 {
-	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
 	unsigned long timeout = jiffies + HZ;
 	unsigned long timeout = jiffies + HZ;
 	int retval, i;
 	int retval, i;
 	unsigned long mins, secs;
 	unsigned long mins, secs;
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+	u8 value;
 
 
 	/* Request a data read */
 	/* Request a data read */
-	retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG,
-			      RTC_READ_REQUEST);
+	retval = abx500_set_register_interruptible(dev,
+		AB8500_RTC, AB8500_RTC_READ_REQ_REG, RTC_READ_REQUEST);
 	if (retval < 0)
 	if (retval < 0)
 		return retval;
 		return retval;
 
 
 	/* Early AB8500 chips will not clear the rtc read request bit */
 	/* Early AB8500 chips will not clear the rtc read request bit */
-	if (ab8500->revision == 0) {
+	if (abx500_get_chip_id(dev) == 0) {
 		msleep(1);
 		msleep(1);
 	} else {
 	} else {
 		/* Wait for some cycles after enabling the rtc read in ab8500 */
 		/* Wait for some cycles after enabling the rtc read in ab8500 */
 		while (time_before(jiffies, timeout)) {
 		while (time_before(jiffies, timeout)) {
-			retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG);
+			retval = abx500_get_register_interruptible(dev,
+				AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
 			if (retval < 0)
 			if (retval < 0)
 				return retval;
 				return retval;
 
 
-			if (!(retval & RTC_READ_REQUEST))
+			if (!(value & RTC_READ_REQUEST))
 				break;
 				break;
 
 
 			msleep(1);
 			msleep(1);
@@ -107,10 +108,11 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
 
 	/* Read the Watchtime registers */
 	/* Read the Watchtime registers */
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
-		retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]);
+		retval = abx500_get_register_interruptible(dev,
+			AB8500_RTC, ab8500_rtc_time_regs[i], &value);
 		if (retval < 0)
 		if (retval < 0)
 			return retval;
 			return retval;
-		buf[i] = retval;
+		buf[i] = value;
 	}
 	}
 
 
 	mins = (buf[0] << 16) | (buf[1] << 8) | buf[2];
 	mins = (buf[0] << 16) | (buf[1] << 8) | buf[2];
@@ -128,7 +130,6 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
 
 static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
 static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
 {
-	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
 	int retval, i;
 	int retval, i;
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
 	unsigned long no_secs, no_mins, secs = 0;
 	unsigned long no_secs, no_mins, secs = 0;
@@ -162,27 +163,29 @@ static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	buf[0] = (no_mins >> 16) & 0xFF;
 	buf[0] = (no_mins >> 16) & 0xFF;
 
 
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
-		retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]);
+		retval = abx500_set_register_interruptible(dev, AB8500_RTC,
+			ab8500_rtc_time_regs[i], buf[i]);
 		if (retval < 0)
 		if (retval < 0)
 			return retval;
 			return retval;
 	}
 	}
 
 
 	/* Request a data write */
 	/* Request a data write */
-	return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
+	return abx500_set_register_interruptible(dev, AB8500_RTC,
+		AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
 }
 }
 
 
 static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
 {
-	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
 	int retval, i;
 	int retval, i;
-	int rtc_ctrl;
+	u8 rtc_ctrl, value;
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
 	unsigned long secs, mins;
 	unsigned long secs, mins;
 
 
 	/* Check if the alarm is enabled or not */
 	/* Check if the alarm is enabled or not */
-	rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
-	if (rtc_ctrl < 0)
-		return rtc_ctrl;
+	retval = abx500_get_register_interruptible(dev, AB8500_RTC,
+		AB8500_RTC_STAT_REG, &rtc_ctrl);
+	if (retval < 0)
+		return retval;
 
 
 	if (rtc_ctrl & RTC_ALARM_ENA)
 	if (rtc_ctrl & RTC_ALARM_ENA)
 		alarm->enabled = 1;
 		alarm->enabled = 1;
@@ -192,10 +195,11 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 	alarm->pending = 0;
 	alarm->pending = 0;
 
 
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
-		retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]);
+		retval = abx500_get_register_interruptible(dev, AB8500_RTC,
+			ab8500_rtc_alarm_regs[i], &value);
 		if (retval < 0)
 		if (retval < 0)
 			return retval;
 			return retval;
-		buf[i] = retval;
+		buf[i] = value;
 	}
 	}
 
 
 	mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
 	mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
@@ -211,15 +215,13 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 
 
 static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
 static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
 {
 {
-	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
-
-	return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
-			       enabled ? RTC_ALARM_ENA : 0);
+	return abx500_mask_and_set_register_interruptible(dev, AB8500_RTC,
+		AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
+		enabled ? RTC_ALARM_ENA : 0);
 }
 }
 
 
 static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
 {
-	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
 	int retval, i;
 	int retval, i;
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
 	unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
 	unsigned long mins, secs = 0;
 	unsigned long mins, secs = 0;
@@ -247,7 +249,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 
 
 	/* Set the alarm time */
 	/* Set the alarm time */
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
 	for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
-		retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]);
+		retval = abx500_set_register_interruptible(dev, AB8500_RTC,
+			ab8500_rtc_alarm_regs[i], buf[i]);
 		if (retval < 0)
 		if (retval < 0)
 			return retval;
 			return retval;
 	}
 	}
@@ -276,10 +279,9 @@ static const struct rtc_class_ops ab8500_rtc_ops = {
 
 
 static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
 static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
 {
 {
-	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
 	int err;
 	int err;
 	struct rtc_device *rtc;
 	struct rtc_device *rtc;
-	int rtc_ctrl;
+	u8 rtc_ctrl;
 	int irq;
 	int irq;
 
 
 	irq = platform_get_irq_byname(pdev, "ALARM");
 	irq = platform_get_irq_byname(pdev, "ALARM");
@@ -287,17 +289,18 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
 		return irq;
 		return irq;
 
 
 	/* For RTC supply test */
 	/* For RTC supply test */
-	err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA,
-			RTC_STATUS_DATA);
+	err = abx500_mask_and_set_register_interruptible(&pdev->dev, AB8500_RTC,
+		AB8500_RTC_STAT_REG, RTC_STATUS_DATA, RTC_STATUS_DATA);
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
 
 
 	/* Wait for reset by the PorRtc */
 	/* Wait for reset by the PorRtc */
 	msleep(1);
 	msleep(1);
 
 
-	rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
-	if (rtc_ctrl < 0)
-		return rtc_ctrl;
+	err = abx500_get_register_interruptible(&pdev->dev, AB8500_RTC,
+		AB8500_RTC_STAT_REG, &rtc_ctrl);
+	if (err < 0)
+		return err;
 
 
 	/* Check if the RTC Supply fails */
 	/* Check if the RTC Supply fails */
 	if (!(rtc_ctrl & RTC_STATUS_DATA)) {
 	if (!(rtc_ctrl & RTC_STATUS_DATA)) {

+ 300 - 0
drivers/rtc/rtc-max8998.c

@@ -0,0 +1,300 @@
+/*
+ * RTC driver for Maxim MAX8998
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Minkyu Kang <mk7.kang@samsung.com>
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max8998.h>
+#include <linux/mfd/max8998-private.h>
+
+#define MAX8998_RTC_SEC			0x00
+#define MAX8998_RTC_MIN			0x01
+#define MAX8998_RTC_HOUR		0x02
+#define MAX8998_RTC_WEEKDAY		0x03
+#define MAX8998_RTC_DATE		0x04
+#define MAX8998_RTC_MONTH		0x05
+#define MAX8998_RTC_YEAR1		0x06
+#define MAX8998_RTC_YEAR2		0x07
+#define MAX8998_ALARM0_SEC		0x08
+#define MAX8998_ALARM0_MIN		0x09
+#define MAX8998_ALARM0_HOUR		0x0a
+#define MAX8998_ALARM0_WEEKDAY		0x0b
+#define MAX8998_ALARM0_DATE		0x0c
+#define MAX8998_ALARM0_MONTH		0x0d
+#define MAX8998_ALARM0_YEAR1		0x0e
+#define MAX8998_ALARM0_YEAR2		0x0f
+#define MAX8998_ALARM1_SEC		0x10
+#define MAX8998_ALARM1_MIN		0x11
+#define MAX8998_ALARM1_HOUR		0x12
+#define MAX8998_ALARM1_WEEKDAY		0x13
+#define MAX8998_ALARM1_DATE		0x14
+#define MAX8998_ALARM1_MONTH		0x15
+#define MAX8998_ALARM1_YEAR1		0x16
+#define MAX8998_ALARM1_YEAR2		0x17
+#define MAX8998_ALARM0_CONF		0x18
+#define MAX8998_ALARM1_CONF		0x19
+#define MAX8998_RTC_STATUS		0x1a
+#define MAX8998_WTSR_SMPL_CNTL		0x1b
+#define MAX8998_TEST			0x1f
+
+#define HOUR_12				(1 << 7)
+#define HOUR_PM				(1 << 5)
+#define ALARM0_STATUS			(1 << 1)
+#define ALARM1_STATUS			(1 << 2)
+
+enum {
+	RTC_SEC = 0,
+	RTC_MIN,
+	RTC_HOUR,
+	RTC_WEEKDAY,
+	RTC_DATE,
+	RTC_MONTH,
+	RTC_YEAR1,
+	RTC_YEAR2,
+};
+
+struct max8998_rtc_info {
+	struct device		*dev;
+	struct max8998_dev	*max8998;
+	struct i2c_client	*rtc;
+	struct rtc_device	*rtc_dev;
+	int irq;
+};
+
+static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
+{
+	tm->tm_sec = bcd2bin(data[RTC_SEC]);
+	tm->tm_min = bcd2bin(data[RTC_MIN]);
+	if (data[RTC_HOUR] & HOUR_12) {
+		tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f);
+		if (data[RTC_HOUR] & HOUR_PM)
+			tm->tm_hour += 12;
+	} else
+		tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f);
+
+	tm->tm_wday = data[RTC_WEEKDAY] & 0x07;
+	tm->tm_mday = bcd2bin(data[RTC_DATE]);
+	tm->tm_mon = bcd2bin(data[RTC_MONTH]);
+	tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100;
+	tm->tm_year -= 1900;
+}
+
+static void max8998_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+	data[RTC_SEC] = bin2bcd(tm->tm_sec);
+	data[RTC_MIN] = bin2bcd(tm->tm_min);
+	data[RTC_HOUR] = bin2bcd(tm->tm_hour);
+	data[RTC_WEEKDAY] = tm->tm_wday;
+	data[RTC_DATE] = bin2bcd(tm->tm_mday);
+	data[RTC_MONTH] = bin2bcd(tm->tm_mon);
+	data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100);
+	data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100);
+}
+
+static int max8998_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct max8998_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[8];
+	int ret;
+
+	ret = max8998_bulk_read(info->rtc, MAX8998_RTC_SEC, 8, data);
+	if (ret < 0)
+		return ret;
+
+	max8998_data_to_tm(data, tm);
+
+	return rtc_valid_tm(tm);
+}
+
+static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct max8998_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[8];
+
+	max8998_tm_to_data(tm, data);
+
+	return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+}
+
+static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct max8998_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[8];
+	u8 val;
+	int ret;
+
+	ret = max8998_bulk_read(info->rtc, MAX8998_ALARM0_SEC, 8, data);
+	if (ret < 0)
+		return ret;
+
+	max8998_data_to_tm(data, &alrm->time);
+
+	ret = max8998_read_reg(info->rtc, MAX8998_ALARM0_CONF, &val);
+	if (ret < 0)
+		return ret;
+
+	alrm->enabled = !!val;
+
+	ret = max8998_read_reg(info->rtc, MAX8998_RTC_STATUS, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val & ALARM0_STATUS)
+		alrm->pending = 1;
+	else
+		alrm->pending = 0;
+
+	return 0;
+}
+
+static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
+{
+	return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+}
+
+static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
+{
+	return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
+}
+
+static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct max8998_rtc_info *info = dev_get_drvdata(dev);
+	u8 data[8];
+	int ret;
+
+	max8998_tm_to_data(&alrm->time, data);
+
+	ret = max8998_rtc_stop_alarm(info);
+	if (ret < 0)
+		return ret;
+
+	ret = max8998_bulk_write(info->rtc, MAX8998_ALARM0_SEC, 8, data);
+	if (ret < 0)
+		return ret;
+
+	if (alrm->enabled)
+		return max8998_rtc_start_alarm(info);
+
+	return 0;
+}
+
+static int max8998_rtc_alarm_irq_enable(struct device *dev,
+					unsigned int enabled)
+{
+	struct max8998_rtc_info *info = dev_get_drvdata(dev);
+
+	if (enabled)
+		return max8998_rtc_start_alarm(info);
+	else
+		return max8998_rtc_stop_alarm(info);
+}
+
+static irqreturn_t max8998_rtc_alarm_irq(int irq, void *data)
+{
+	struct max8998_rtc_info *info = data;
+
+	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+	return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops max8998_rtc_ops = {
+	.read_time = max8998_rtc_read_time,
+	.set_time = max8998_rtc_set_time,
+	.read_alarm = max8998_rtc_read_alarm,
+	.set_alarm = max8998_rtc_set_alarm,
+	.alarm_irq_enable = max8998_rtc_alarm_irq_enable,
+};
+
+static int __devinit max8998_rtc_probe(struct platform_device *pdev)
+{
+	struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
+	struct max8998_rtc_info *info;
+	int ret;
+
+	info = kzalloc(sizeof(struct max8998_rtc_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = &pdev->dev;
+	info->max8998 = max8998;
+	info->rtc = max8998->rtc;
+	info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0;
+
+	info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev,
+			&max8998_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(info->rtc_dev)) {
+		ret = PTR_ERR(info->rtc_dev);
+		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+		goto out_rtc;
+	}
+
+	platform_set_drvdata(pdev, info);
+
+	ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
+			"rtc-alarm0", info);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
+			info->irq, ret);
+
+	return 0;
+
+out_rtc:
+	kfree(info);
+	return ret;
+}
+
+static int __devexit max8998_rtc_remove(struct platform_device *pdev)
+{
+	struct max8998_rtc_info *info = platform_get_drvdata(pdev);
+
+	if (info) {
+		free_irq(info->irq, info);
+		rtc_device_unregister(info->rtc_dev);
+		kfree(info);
+	}
+
+	return 0;
+}
+
+static struct platform_driver max8998_rtc_driver = {
+	.driver		= {
+		.name	= "max8998-rtc",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= max8998_rtc_probe,
+	.remove		= __devexit_p(max8998_rtc_remove),
+};
+
+static int __init max8998_rtc_init(void)
+{
+	return platform_driver_register(&max8998_rtc_driver);
+}
+module_init(max8998_rtc_init);
+
+static void __exit max8998_rtc_exit(void)
+{
+	platform_driver_unregister(&max8998_rtc_driver);
+}
+module_exit(max8998_rtc_exit);
+
+MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("Maxim MAX8998 RTC driver");
+MODULE_LICENSE("GPL");

+ 0 - 428
drivers/rtc/rtc-mc13783.c

@@ -1,428 +0,0 @@
-/*
- * Real Time Clock driver for Freescale MC13783 PMIC
- *
- * (C) 2009 Sascha Hauer, Pengutronix
- * (C) 2009 Uwe Kleine-Koenig, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/mfd/mc13783.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/rtc.h>
-
-#define DRIVER_NAME "mc13783-rtc"
-
-#define MC13783_RTCTOD	20
-#define MC13783_RTCTODA	21
-#define MC13783_RTCDAY	22
-#define MC13783_RTCDAYA	23
-
-struct mc13783_rtc {
-	struct rtc_device *rtc;
-	struct mc13783 *mc13783;
-	int valid;
-};
-
-static int mc13783_rtc_irq_enable_unlocked(struct device *dev,
-		unsigned int enabled, int irq)
-{
-	struct mc13783_rtc *priv = dev_get_drvdata(dev);
-	int (*func)(struct mc13783 *mc13783, int irq);
-
-	if (!priv->valid)
-		return -ENODATA;
-
-	func = enabled ? mc13783_irq_unmask : mc13783_irq_mask;
-	return func(priv->mc13783, irq);
-}
-
-static int mc13783_rtc_irq_enable(struct device *dev,
-		unsigned int enabled, int irq)
-{
-	struct mc13783_rtc *priv = dev_get_drvdata(dev);
-	int ret;
-
-	mc13783_lock(priv->mc13783);
-
-	ret = mc13783_rtc_irq_enable_unlocked(dev, enabled, irq);
-
-	mc13783_unlock(priv->mc13783);
-
-	return ret;
-}
-
-static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
-	struct mc13783_rtc *priv = dev_get_drvdata(dev);
-	unsigned int seconds, days1, days2;
-	unsigned long s1970;
-	int ret;
-
-	mc13783_lock(priv->mc13783);
-
-	if (!priv->valid) {
-		ret = -ENODATA;
-		goto out;
-	}
-
-	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days1);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTOD, &seconds);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days2);
-out:
-	mc13783_unlock(priv->mc13783);
-
-	if (ret)
-		return ret;
-
-	if (days2 == days1 + 1) {
-		if (seconds >= 86400 / 2)
-			days2 = days1;
-		else
-			days1 = days2;
-	}
-
-	if (days1 != days2)
-		return -EIO;
-
-	s1970 = days1 * 86400 + seconds;
-
-	rtc_time_to_tm(s1970, tm);
-
-	return rtc_valid_tm(tm);
-}
-
-static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs)
-{
-	struct mc13783_rtc *priv = dev_get_drvdata(dev);
-	unsigned int seconds, days;
-	unsigned int alarmseconds;
-	int ret;
-
-	seconds = secs % 86400;
-	days = secs / 86400;
-
-	mc13783_lock(priv->mc13783);
-
-	/*
-	 * temporarily invalidate alarm to prevent triggering it when the day is
-	 * already updated while the time isn't yet.
-	 */
-	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &alarmseconds);
-	if (unlikely(ret))
-		goto out;
-
-	if (alarmseconds < 86400) {
-		ret = mc13783_reg_write(priv->mc13783,
-				MC13783_RTCTODA, 0x1ffff);
-		if (unlikely(ret))
-			goto out;
-	}
-
-	/*
-	 * write seconds=0 to prevent a day switch between writing days
-	 * and seconds below
-	 */
-	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAY, days);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, seconds);
-	if (unlikely(ret))
-		goto out;
-
-	/* restore alarm */
-	if (alarmseconds < 86400) {
-		ret = mc13783_reg_write(priv->mc13783,
-				MC13783_RTCTODA, alarmseconds);
-		if (unlikely(ret))
-			goto out;
-	}
-
-	ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_RTCRST);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_irq_unmask(priv->mc13783, MC13783_IRQ_RTCRST);
-out:
-	priv->valid = !ret;
-
-	mc13783_unlock(priv->mc13783);
-
-	return ret;
-}
-
-static int mc13783_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-{
-	struct mc13783_rtc *priv = dev_get_drvdata(dev);
-	unsigned seconds, days;
-	unsigned long s1970;
-	int enabled, pending;
-	int ret;
-
-	mc13783_lock(priv->mc13783);
-
-	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &seconds);
-	if (unlikely(ret))
-		goto out;
-	if (seconds >= 86400) {
-		ret = -ENODATA;
-		goto out;
-	}
-
-	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_TODA,
-			&enabled, &pending);
-
-out:
-	mc13783_unlock(priv->mc13783);
-
-	if (ret)
-		return ret;
-
-	alarm->enabled = enabled;
-	alarm->pending = pending;
-
-	s1970 = days * 86400 + seconds;
-
-	rtc_time_to_tm(s1970, &alarm->time);
-	dev_dbg(dev, "%s: %lu\n", __func__, s1970);
-
-	return 0;
-}
-
-static int mc13783_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-{
-	struct mc13783_rtc *priv = dev_get_drvdata(dev);
-	unsigned long s1970;
-	unsigned seconds, days;
-	int ret;
-
-	mc13783_lock(priv->mc13783);
-
-	/* disable alarm to prevent false triggering */
-	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, 0x1ffff);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_TODA);
-	if (unlikely(ret))
-		goto out;
-
-	ret = rtc_tm_to_time(&alarm->time, &s1970);
-	if (unlikely(ret))
-		goto out;
-
-	dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff",
-			s1970);
-
-	ret = mc13783_rtc_irq_enable_unlocked(dev, alarm->enabled,
-			MC13783_IRQ_TODA);
-	if (unlikely(ret))
-		goto out;
-
-	seconds = s1970 % 86400;
-	days = s1970 / 86400;
-
-	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAYA, days);
-	if (unlikely(ret))
-		goto out;
-
-	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, seconds);
-
-out:
-	mc13783_unlock(priv->mc13783);
-
-	return ret;
-}
-
-static irqreturn_t mc13783_rtc_alarm_handler(int irq, void *dev)
-{
-	struct mc13783_rtc *priv = dev;
-	struct mc13783 *mc13783 = priv->mc13783;
-
-	dev_dbg(&priv->rtc->dev, "Alarm\n");
-
-	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
-
-	mc13783_irq_ack(mc13783, irq);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev)
-{
-	struct mc13783_rtc *priv = dev;
-	struct mc13783 *mc13783 = priv->mc13783;
-
-	dev_dbg(&priv->rtc->dev, "1HZ\n");
-
-	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
-
-	mc13783_irq_ack(mc13783, irq);
-
-	return IRQ_HANDLED;
-}
-
-static int mc13783_rtc_update_irq_enable(struct device *dev,
-		unsigned int enabled)
-{
-	return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_1HZ);
-}
-
-static int mc13783_rtc_alarm_irq_enable(struct device *dev,
-		unsigned int enabled)
-{
-	return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_TODA);
-}
-
-static const struct rtc_class_ops mc13783_rtc_ops = {
-	.read_time = mc13783_rtc_read_time,
-	.set_mmss = mc13783_rtc_set_mmss,
-	.read_alarm = mc13783_rtc_read_alarm,
-	.set_alarm = mc13783_rtc_set_alarm,
-	.alarm_irq_enable = mc13783_rtc_alarm_irq_enable,
-	.update_irq_enable = mc13783_rtc_update_irq_enable,
-};
-
-static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev)
-{
-	struct mc13783_rtc *priv = dev;
-	struct mc13783 *mc13783 = priv->mc13783;
-
-	dev_dbg(&priv->rtc->dev, "RTCRST\n");
-	priv->valid = 0;
-
-	mc13783_irq_mask(mc13783, irq);
-
-	return IRQ_HANDLED;
-}
-
-static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct mc13783_rtc *priv;
-	struct mc13783 *mc13783;
-	int rtcrst_pending;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	mc13783 = dev_get_drvdata(pdev->dev.parent);
-	priv->mc13783 = mc13783;
-
-	platform_set_drvdata(pdev, priv);
-
-	mc13783_lock(mc13783);
-
-	ret = mc13783_irq_request(mc13783, MC13783_IRQ_RTCRST,
-			mc13783_rtc_reset_handler, DRIVER_NAME, priv);
-	if (ret)
-		goto err_reset_irq_request;
-
-	ret = mc13783_irq_status(mc13783, MC13783_IRQ_RTCRST,
-			NULL, &rtcrst_pending);
-	if (ret)
-		goto err_reset_irq_status;
-
-	priv->valid = !rtcrst_pending;
-
-	ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_1HZ,
-			mc13783_rtc_update_handler, DRIVER_NAME, priv);
-	if (ret)
-		goto err_update_irq_request;
-
-	ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_TODA,
-			mc13783_rtc_alarm_handler, DRIVER_NAME, priv);
-	if (ret)
-		goto err_alarm_irq_request;
-
-	priv->rtc = rtc_device_register(pdev->name,
-			&pdev->dev, &mc13783_rtc_ops, THIS_MODULE);
-	if (IS_ERR(priv->rtc)) {
-		ret = PTR_ERR(priv->rtc);
-
-		mc13783_irq_free(mc13783, MC13783_IRQ_TODA, priv);
-err_alarm_irq_request:
-
-		mc13783_irq_free(mc13783, MC13783_IRQ_1HZ, priv);
-err_update_irq_request:
-
-err_reset_irq_status:
-
-		mc13783_irq_free(mc13783, MC13783_IRQ_RTCRST, priv);
-err_reset_irq_request:
-
-		platform_set_drvdata(pdev, NULL);
-		kfree(priv);
-	}
-
-	mc13783_unlock(mc13783);
-
-	return ret;
-}
-
-static int __devexit mc13783_rtc_remove(struct platform_device *pdev)
-{
-	struct mc13783_rtc *priv = platform_get_drvdata(pdev);
-
-	mc13783_lock(priv->mc13783);
-
-	rtc_device_unregister(priv->rtc);
-
-	mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv);
-	mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv);
-	mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv);
-
-	mc13783_unlock(priv->mc13783);
-
-	platform_set_drvdata(pdev, NULL);
-
-	kfree(priv);
-
-	return 0;
-}
-
-static struct platform_driver mc13783_rtc_driver = {
-	.remove = __devexit_p(mc13783_rtc_remove),
-	.driver = {
-		.name = DRIVER_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init mc13783_rtc_init(void)
-{
-	return platform_driver_probe(&mc13783_rtc_driver, &mc13783_rtc_probe);
-}
-module_init(mc13783_rtc_init);
-
-static void __exit mc13783_rtc_exit(void)
-{
-	platform_driver_unregister(&mc13783_rtc_driver);
-}
-module_exit(mc13783_rtc_exit);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("RTC driver for Freescale MC13783 PMIC");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRIVER_NAME);

+ 437 - 0
drivers/rtc/rtc-mc13xxx.c

@@ -0,0 +1,437 @@
+/*
+ * Real Time Clock driver for Freescale MC13XXX PMIC
+ *
+ * (C) 2009 Sascha Hauer, Pengutronix
+ * (C) 2009 Uwe Kleine-Koenig, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/mfd/mc13xxx.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/rtc.h>
+
+#define DRIVER_NAME "mc13xxx-rtc"
+
+#define MC13XXX_RTCTOD	20
+#define MC13XXX_RTCTODA	21
+#define MC13XXX_RTCDAY	22
+#define MC13XXX_RTCDAYA	23
+
+struct mc13xxx_rtc {
+	struct rtc_device *rtc;
+	struct mc13xxx *mc13xxx;
+	int valid;
+};
+
+static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev,
+		unsigned int enabled, int irq)
+{
+	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
+	int (*func)(struct mc13xxx *mc13xxx, int irq);
+
+	if (!priv->valid)
+		return -ENODATA;
+
+	func = enabled ? mc13xxx_irq_unmask : mc13xxx_irq_mask;
+	return func(priv->mc13xxx, irq);
+}
+
+static int mc13xxx_rtc_irq_enable(struct device *dev,
+		unsigned int enabled, int irq)
+{
+	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
+	int ret;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq);
+
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
+	unsigned int seconds, days1, days2;
+	unsigned long s1970;
+	int ret;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	if (!priv->valid) {
+		ret = -ENODATA;
+		goto out;
+	}
+
+	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2);
+out:
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	if (days2 == days1 + 1) {
+		if (seconds >= 86400 / 2)
+			days2 = days1;
+		else
+			days1 = days2;
+	}
+
+	if (days1 != days2)
+		return -EIO;
+
+	s1970 = days1 * 86400 + seconds;
+
+	rtc_time_to_tm(s1970, tm);
+
+	return rtc_valid_tm(tm);
+}
+
+static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
+	unsigned int seconds, days;
+	unsigned int alarmseconds;
+	int ret;
+
+	seconds = secs % 86400;
+	days = secs / 86400;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	/*
+	 * temporarily invalidate alarm to prevent triggering it when the day is
+	 * already updated while the time isn't yet.
+	 */
+	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &alarmseconds);
+	if (unlikely(ret))
+		goto out;
+
+	if (alarmseconds < 86400) {
+		ret = mc13xxx_reg_write(priv->mc13xxx,
+				MC13XXX_RTCTODA, 0x1ffff);
+		if (unlikely(ret))
+			goto out;
+	}
+
+	/*
+	 * write seconds=0 to prevent a day switch between writing days
+	 * and seconds below
+	 */
+	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, 0);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAY, days);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, seconds);
+	if (unlikely(ret))
+		goto out;
+
+	/* restore alarm */
+	if (alarmseconds < 86400) {
+		ret = mc13xxx_reg_write(priv->mc13xxx,
+				MC13XXX_RTCTODA, alarmseconds);
+		if (unlikely(ret))
+			goto out;
+	}
+
+	ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
+out:
+	priv->valid = !ret;
+
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
+	unsigned seconds, days;
+	unsigned long s1970;
+	int enabled, pending;
+	int ret;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds);
+	if (unlikely(ret))
+		goto out;
+	if (seconds >= 86400) {
+		ret = -ENODATA;
+		goto out;
+	}
+
+	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_irq_status(priv->mc13xxx, MC13XXX_IRQ_TODA,
+			&enabled, &pending);
+
+out:
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	alarm->enabled = enabled;
+	alarm->pending = pending;
+
+	s1970 = days * 86400 + seconds;
+
+	rtc_time_to_tm(s1970, &alarm->time);
+	dev_dbg(dev, "%s: %lu\n", __func__, s1970);
+
+	return 0;
+}
+
+static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
+	unsigned long s1970;
+	unsigned seconds, days;
+	int ret;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	/* disable alarm to prevent false triggering */
+	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, 0x1ffff);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TODA);
+	if (unlikely(ret))
+		goto out;
+
+	ret = rtc_tm_to_time(&alarm->time, &s1970);
+	if (unlikely(ret))
+		goto out;
+
+	dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff",
+			s1970);
+
+	ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled,
+			MC13XXX_IRQ_TODA);
+	if (unlikely(ret))
+		goto out;
+
+	seconds = s1970 % 86400;
+	days = s1970 / 86400;
+
+	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days);
+	if (unlikely(ret))
+		goto out;
+
+	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, seconds);
+
+out:
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)
+{
+	struct mc13xxx_rtc *priv = dev;
+	struct mc13xxx *mc13xxx = priv->mc13xxx;
+
+	dev_dbg(&priv->rtc->dev, "Alarm\n");
+
+	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
+
+	mc13xxx_irq_ack(mc13xxx, irq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
+{
+	struct mc13xxx_rtc *priv = dev;
+	struct mc13xxx *mc13xxx = priv->mc13xxx;
+
+	dev_dbg(&priv->rtc->dev, "1HZ\n");
+
+	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
+
+	mc13xxx_irq_ack(mc13xxx, irq);
+
+	return IRQ_HANDLED;
+}
+
+static int mc13xxx_rtc_update_irq_enable(struct device *dev,
+		unsigned int enabled)
+{
+	return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_1HZ);
+}
+
+static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
+		unsigned int enabled)
+{
+	return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA);
+}
+
+static const struct rtc_class_ops mc13xxx_rtc_ops = {
+	.read_time = mc13xxx_rtc_read_time,
+	.set_mmss = mc13xxx_rtc_set_mmss,
+	.read_alarm = mc13xxx_rtc_read_alarm,
+	.set_alarm = mc13xxx_rtc_set_alarm,
+	.alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable,
+	.update_irq_enable = mc13xxx_rtc_update_irq_enable,
+};
+
+static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)
+{
+	struct mc13xxx_rtc *priv = dev;
+	struct mc13xxx *mc13xxx = priv->mc13xxx;
+
+	dev_dbg(&priv->rtc->dev, "RTCRST\n");
+	priv->valid = 0;
+
+	mc13xxx_irq_mask(mc13xxx, irq);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct mc13xxx_rtc *priv;
+	struct mc13xxx *mc13xxx;
+	int rtcrst_pending;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mc13xxx = dev_get_drvdata(pdev->dev.parent);
+	priv->mc13xxx = mc13xxx;
+
+	platform_set_drvdata(pdev, priv);
+
+	mc13xxx_lock(mc13xxx);
+
+	ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST,
+			mc13xxx_rtc_reset_handler, DRIVER_NAME, priv);
+	if (ret)
+		goto err_reset_irq_request;
+
+	ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST,
+			NULL, &rtcrst_pending);
+	if (ret)
+		goto err_reset_irq_status;
+
+	priv->valid = !rtcrst_pending;
+
+	ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ,
+			mc13xxx_rtc_update_handler, DRIVER_NAME, priv);
+	if (ret)
+		goto err_update_irq_request;
+
+	ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA,
+			mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv);
+	if (ret)
+		goto err_alarm_irq_request;
+
+	priv->rtc = rtc_device_register(pdev->name,
+			&pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE);
+	if (IS_ERR(priv->rtc)) {
+		ret = PTR_ERR(priv->rtc);
+
+		mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
+err_alarm_irq_request:
+
+		mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv);
+err_update_irq_request:
+
+err_reset_irq_status:
+
+		mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
+err_reset_irq_request:
+
+		platform_set_drvdata(pdev, NULL);
+		kfree(priv);
+	}
+
+	mc13xxx_unlock(mc13xxx);
+
+	return ret;
+}
+
+static int __devexit mc13xxx_rtc_remove(struct platform_device *pdev)
+{
+	struct mc13xxx_rtc *priv = platform_get_drvdata(pdev);
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	rtc_device_unregister(priv->rtc);
+
+	mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv);
+	mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_1HZ, priv);
+	mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv);
+
+	mc13xxx_unlock(priv->mc13xxx);
+
+	platform_set_drvdata(pdev, NULL);
+
+	kfree(priv);
+
+	return 0;
+}
+
+const struct platform_device_id mc13xxx_rtc_idtable[] = {
+	{
+		.name = "mc13783-rtc",
+	}, {
+		.name = "mc13892-rtc",
+	},
+};
+
+static struct platform_driver mc13xxx_rtc_driver = {
+	.id_table = mc13xxx_rtc_idtable,
+	.remove = __devexit_p(mc13xxx_rtc_remove),
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mc13xxx_rtc_init(void)
+{
+	return platform_driver_probe(&mc13xxx_rtc_driver, &mc13xxx_rtc_probe);
+}
+module_init(mc13xxx_rtc_init);
+
+static void __exit mc13xxx_rtc_exit(void)
+{
+	platform_driver_unregister(&mc13xxx_rtc_driver);
+}
+module_exit(mc13xxx_rtc_exit);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);

+ 9 - 4
drivers/usb/otg/twl4030-usb.c

@@ -124,7 +124,6 @@
 #define PHY_DPLL_CLK			(1 << 0)
 #define PHY_DPLL_CLK			(1 << 0)
 
 
 /* In module TWL4030_MODULE_PM_MASTER */
 /* In module TWL4030_MODULE_PM_MASTER */
-#define PROTECT_KEY			0x0E
 #define STS_HW_CONDITIONS		0x0F
 #define STS_HW_CONDITIONS		0x0F
 
 
 /* In module TWL4030_MODULE_PM_RECEIVER */
 /* In module TWL4030_MODULE_PM_RECEIVER */
@@ -418,8 +417,13 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
 static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
 static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
 {
 {
 	/* Enable writing to power configuration registers */
 	/* Enable writing to power configuration registers */
-	twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
-	twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY);
+	twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG1,
+			TWL4030_PM_MASTER_PROTECT_KEY);
+
+	twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			TWL4030_PM_MASTER_KEY_CFG2,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 
 
 	/* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/
 	/* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/
 	/*twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/
 	/*twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/
@@ -455,7 +459,8 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
 	twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
 	twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
 
 
 	/* disable access to power configuration registers */
 	/* disable access to power configuration registers */
-	twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
+	twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
+			TWL4030_PM_MASTER_PROTECT_KEY);
 
 
 	return 0;
 	return 0;
 
 

+ 77 - 0
include/linux/i2c/twl.h

@@ -141,6 +141,16 @@
 #define TWL6030_CHARGER_CTRL_INT_MASK 	0x10
 #define TWL6030_CHARGER_CTRL_INT_MASK 	0x10
 #define TWL6030_CHARGER_FAULT_INT_MASK 	0x60
 #define TWL6030_CHARGER_FAULT_INT_MASK 	0x60
 
 
+#define TWL6030_MMCCTRL		0xEE
+#define VMMC_AUTO_OFF			(0x1 << 3)
+#define SW_FC				(0x1 << 2)
+#define STS_MMC			0x1
+
+#define TWL6030_CFG_INPUT_PUPD3	0xF2
+#define MMC_PU				(0x1 << 3)
+#define MMC_PD				(0x1 << 2)
+
+
 
 
 #define TWL4030_CLASS_ID 		0x4030
 #define TWL4030_CLASS_ID 		0x4030
 #define TWL6030_CLASS_ID 		0x6030
 #define TWL6030_CLASS_ID 		0x6030
@@ -173,6 +183,27 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
 int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
 int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
 
 
+/* Card detect Configuration for MMC1 Controller on OMAP4 */
+#ifdef CONFIG_TWL4030_CORE
+int twl6030_mmc_card_detect_config(void);
+#else
+static inline int twl6030_mmc_card_detect_config(void)
+{
+	pr_debug("twl6030_mmc_card_detect_config not supported\n");
+	return 0;
+}
+#endif
+
+/* MMC1 Controller on OMAP4 uses Phoenix irq for Card detect */
+#ifdef CONFIG_TWL4030_CORE
+int twl6030_mmc_card_detect(struct device *dev, int slot);
+#else
+static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
+{
+	pr_debug("Call back twl6030_mmc_card_detect not supported\n");
+	return -EIO;
+}
+#endif
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
 /*
 /*
@@ -357,6 +388,52 @@ int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
 
 
 /*----------------------------------------------------------------------*/
 /*----------------------------------------------------------------------*/
 
 
+/*
+ * PM Master module register offsets (use TWL4030_MODULE_PM_MASTER)
+ */
+
+#define TWL4030_PM_MASTER_CFG_P1_TRANSITION	0x00
+#define TWL4030_PM_MASTER_CFG_P2_TRANSITION	0x01
+#define TWL4030_PM_MASTER_CFG_P3_TRANSITION	0x02
+#define TWL4030_PM_MASTER_CFG_P123_TRANSITION	0x03
+#define TWL4030_PM_MASTER_STS_BOOT		0x04
+#define TWL4030_PM_MASTER_CFG_BOOT		0x05
+#define TWL4030_PM_MASTER_SHUNDAN		0x06
+#define TWL4030_PM_MASTER_BOOT_BCI		0x07
+#define TWL4030_PM_MASTER_CFG_PWRANA1		0x08
+#define TWL4030_PM_MASTER_CFG_PWRANA2		0x09
+#define TWL4030_PM_MASTER_BACKUP_MISC_STS	0x0b
+#define TWL4030_PM_MASTER_BACKUP_MISC_CFG	0x0c
+#define TWL4030_PM_MASTER_BACKUP_MISC_TST	0x0d
+#define TWL4030_PM_MASTER_PROTECT_KEY		0x0e
+#define TWL4030_PM_MASTER_STS_HW_CONDITIONS	0x0f
+#define TWL4030_PM_MASTER_P1_SW_EVENTS		0x10
+#define TWL4030_PM_MASTER_P2_SW_EVENTS		0x11
+#define TWL4030_PM_MASTER_P3_SW_EVENTS		0x12
+#define TWL4030_PM_MASTER_STS_P123_STATE	0x13
+#define TWL4030_PM_MASTER_PB_CFG		0x14
+#define TWL4030_PM_MASTER_PB_WORD_MSB		0x15
+#define TWL4030_PM_MASTER_PB_WORD_LSB		0x16
+#define TWL4030_PM_MASTER_SEQ_ADD_W2P		0x1c
+#define TWL4030_PM_MASTER_SEQ_ADD_P2A		0x1d
+#define TWL4030_PM_MASTER_SEQ_ADD_A2W		0x1e
+#define TWL4030_PM_MASTER_SEQ_ADD_A2S		0x1f
+#define TWL4030_PM_MASTER_SEQ_ADD_S2A12		0x20
+#define TWL4030_PM_MASTER_SEQ_ADD_S2A3		0x21
+#define TWL4030_PM_MASTER_SEQ_ADD_WARM		0x22
+#define TWL4030_PM_MASTER_MEMORY_ADDRESS	0x23
+#define TWL4030_PM_MASTER_MEMORY_DATA		0x24
+
+#define TWL4030_PM_MASTER_KEY_CFG1		0xc0
+#define TWL4030_PM_MASTER_KEY_CFG2		0x0c
+
+#define TWL4030_PM_MASTER_KEY_TST1		0xe0
+#define TWL4030_PM_MASTER_KEY_TST2		0x0e
+
+#define TWL4030_PM_MASTER_GLOBAL_TST		0xb6
+
+/*----------------------------------------------------------------------*/
+
 /* Power bus message definitions */
 /* Power bus message definitions */
 
 
 /* The TWL4030/5030 splits its power-management resources (the various
 /* The TWL4030/5030 splits its power-management resources (the various

+ 1 - 1
include/linux/mfd/88pm860x.h

@@ -138,7 +138,7 @@ enum {
 	PM8607_ID_RG_MAX,
 	PM8607_ID_RG_MAX,
 };
 };
 
 
-#define PM8607_VERSION			(0x40)	/* 8607 chip ID */
+/* 8607 chip ID is 0x40 or 0x50 */
 #define PM8607_VERSION_MASK		(0xF0)	/* 8607 chip ID mask */
 #define PM8607_VERSION_MASK		(0xF0)	/* 8607 chip ID mask */
 
 
 /* Interrupt Registers */
 /* Interrupt Registers */

+ 24 - 4
include/linux/mfd/ab8500.h

@@ -9,6 +9,29 @@
 
 
 #include <linux/device.h>
 #include <linux/device.h>
 
 
+/*
+ * AB8500 bank addresses
+ */
+#define AB8500_SYS_CTRL1_BLOCK	0x1
+#define AB8500_SYS_CTRL2_BLOCK	0x2
+#define AB8500_REGU_CTRL1	0x3
+#define AB8500_REGU_CTRL2	0x4
+#define AB8500_USB		0x5
+#define AB8500_TVOUT		0x6
+#define AB8500_DBI		0x7
+#define AB8500_ECI_AV_ACC	0x8
+#define AB8500_RESERVED		0x9
+#define AB8500_GPADC		0xA
+#define AB8500_CHARGER		0xB
+#define AB8500_GAS_GAUGE	0xC
+#define AB8500_AUDIO		0xD
+#define AB8500_INTERRUPT	0xE
+#define AB8500_RTC		0xF
+#define AB8500_MISC		0x10
+#define AB8500_DEBUG		0x12
+#define AB8500_PROD_TEST	0x13
+#define AB8500_OTP_EMUL		0x15
+
 /*
 /*
  * Interrupts
  * Interrupts
  */
  */
@@ -99,6 +122,7 @@ struct ab8500 {
 	int		revision;
 	int		revision;
 	int		irq_base;
 	int		irq_base;
 	int		irq;
 	int		irq;
+	u8		chip_id;
 
 
 	int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
 	int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
 	int (*read) (struct ab8500 *a8500, u16 addr);
 	int (*read) (struct ab8500 *a8500, u16 addr);
@@ -124,10 +148,6 @@ struct ab8500_platform_data {
 	struct regulator_init_data *regulator[AB8500_NUM_REGULATORS];
 	struct regulator_init_data *regulator[AB8500_NUM_REGULATORS];
 };
 };
 
 
-extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data);
-extern int ab8500_read(struct ab8500 *a8500, u16 addr);
-extern int ab8500_set_bits(struct ab8500 *a8500, u16 addr, u8 mask, u8 data);
-
 extern int __devinit ab8500_init(struct ab8500 *ab8500);
 extern int __devinit ab8500_init(struct ab8500 *ab8500);
 extern int __devexit ab8500_exit(struct ab8500 *ab8500);
 extern int __devexit ab8500_exit(struct ab8500 *ab8500);
 
 

+ 2 - 2
include/linux/mfd/abx500.h

@@ -6,8 +6,7 @@
  *
  *
  * ABX500 core access functions.
  * ABX500 core access functions.
  * The abx500 interface is used for the Analog Baseband chip
  * The abx500 interface is used for the Analog Baseband chip
- * ab3100, ab3550, ab5500 and possibly comming. It is not used for
- * ab4500 and ab8500 since they are another family of chip.
+ * ab3100, ab3550, ab5500, and ab8500.
  *
  *
  * Author: Mattias Wallin <mattias.wallin@stericsson.com>
  * Author: Mattias Wallin <mattias.wallin@stericsson.com>
  * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
  * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
@@ -230,4 +229,5 @@ struct abx500_ops {
 };
 };
 
 
 int abx500_register_ops(struct device *core_dev, struct abx500_ops *ops);
 int abx500_register_ops(struct device *core_dev, struct abx500_ops *ops);
+void abx500_remove_ops(struct device *dev);
 #endif
 #endif

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

@@ -44,6 +44,9 @@ struct mfd_cell {
 	 */
 	 */
 	int			num_resources;
 	int			num_resources;
 	const struct resource	*resources;
 	const struct resource	*resources;
+
+	/* don't check for resource conflicts */
+	bool			ignore_resource_conflicts;
 };
 };
 
 
 extern int mfd_add_devices(struct device *parent, int id,
 extern int mfd_add_devices(struct device *parent, int id,

+ 96 - 33
include/linux/mfd/max8998-private.h

@@ -1,5 +1,5 @@
 /*
 /*
- * max8698.h - Voltage regulator driver for the Maxim 8998
+ * max8998.h - Voltage regulator driver for the Maxim 8998
  *
  *
  *  Copyright (C) 2009-2010 Samsung Electrnoics
  *  Copyright (C) 2009-2010 Samsung Electrnoics
  *  Kyungmin Park <kyungmin.park@samsung.com>
  *  Kyungmin Park <kyungmin.park@samsung.com>
@@ -23,6 +23,8 @@
 #ifndef __LINUX_MFD_MAX8998_PRIV_H
 #ifndef __LINUX_MFD_MAX8998_PRIV_H
 #define __LINUX_MFD_MAX8998_PRIV_H
 #define __LINUX_MFD_MAX8998_PRIV_H
 
 
+#define MAX8998_NUM_IRQ_REGS	4
+
 /* MAX 8998 registers */
 /* MAX 8998 registers */
 enum {
 enum {
 	MAX8998_REG_IRQ1,
 	MAX8998_REG_IRQ1,
@@ -46,12 +48,12 @@ enum {
 	MAX8998_REG_ONOFF2,
 	MAX8998_REG_ONOFF2,
 	MAX8998_REG_ONOFF3,
 	MAX8998_REG_ONOFF3,
 	MAX8998_REG_ONOFF4,
 	MAX8998_REG_ONOFF4,
-	MAX8998_REG_BUCK1_DVSARM1,
-	MAX8998_REG_BUCK1_DVSARM2,
-	MAX8998_REG_BUCK1_DVSARM3,
-	MAX8998_REG_BUCK1_DVSARM4,
-	MAX8998_REG_BUCK2_DVSINT1,
-	MAX8998_REG_BUCK2_DVSINT2,
+	MAX8998_REG_BUCK1_VOLTAGE1,
+	MAX8998_REG_BUCK1_VOLTAGE2,
+	MAX8998_REG_BUCK1_VOLTAGE3,
+	MAX8998_REG_BUCK1_VOLTAGE4,
+	MAX8998_REG_BUCK2_VOLTAGE1,
+	MAX8998_REG_BUCK2_VOLTAGE2,
 	MAX8998_REG_BUCK3,
 	MAX8998_REG_BUCK3,
 	MAX8998_REG_BUCK4,
 	MAX8998_REG_BUCK4,
 	MAX8998_REG_LDO2_LDO3,
 	MAX8998_REG_LDO2_LDO3,
@@ -72,41 +74,102 @@ enum {
 	MAX8998_REG_LBCNFG2,
 	MAX8998_REG_LBCNFG2,
 };
 };
 
 
+/* IRQ definitions */
+enum {
+	MAX8998_IRQ_DCINF,
+	MAX8998_IRQ_DCINR,
+	MAX8998_IRQ_JIGF,
+	MAX8998_IRQ_JIGR,
+	MAX8998_IRQ_PWRONF,
+	MAX8998_IRQ_PWRONR,
+
+	MAX8998_IRQ_WTSREVNT,
+	MAX8998_IRQ_SMPLEVNT,
+	MAX8998_IRQ_ALARM1,
+	MAX8998_IRQ_ALARM0,
+
+	MAX8998_IRQ_ONKEY1S,
+	MAX8998_IRQ_TOPOFFR,
+	MAX8998_IRQ_DCINOVPR,
+	MAX8998_IRQ_CHGRSTF,
+	MAX8998_IRQ_DONER,
+	MAX8998_IRQ_CHGFAULT,
+
+	MAX8998_IRQ_LOBAT1,
+	MAX8998_IRQ_LOBAT2,
+
+	MAX8998_IRQ_NR,
+};
+
+/* MAX8998 various variants */
+enum {
+	TYPE_MAX8998 = 0, /* Default */
+	TYPE_LP3974,	/* National version of MAX8998 */
+	TYPE_LP3979,	/* Added AVS */
+};
+
+#define MAX8998_IRQ_DCINF_MASK		(1 << 2)
+#define MAX8998_IRQ_DCINR_MASK		(1 << 3)
+#define MAX8998_IRQ_JIGF_MASK		(1 << 4)
+#define MAX8998_IRQ_JIGR_MASK		(1 << 5)
+#define MAX8998_IRQ_PWRONF_MASK		(1 << 6)
+#define MAX8998_IRQ_PWRONR_MASK		(1 << 7)
+
+#define MAX8998_IRQ_WTSREVNT_MASK	(1 << 0)
+#define MAX8998_IRQ_SMPLEVNT_MASK	(1 << 1)
+#define MAX8998_IRQ_ALARM1_MASK		(1 << 2)
+#define MAX8998_IRQ_ALARM0_MASK		(1 << 3)
+
+#define MAX8998_IRQ_ONKEY1S_MASK	(1 << 0)
+#define MAX8998_IRQ_TOPOFFR_MASK	(1 << 2)
+#define MAX8998_IRQ_DCINOVPR_MASK	(1 << 3)
+#define MAX8998_IRQ_CHGRSTF_MASK	(1 << 4)
+#define MAX8998_IRQ_DONER_MASK		(1 << 5)
+#define MAX8998_IRQ_CHGFAULT_MASK	(1 << 7)
+
+#define MAX8998_IRQ_LOBAT1_MASK		(1 << 0)
+#define MAX8998_IRQ_LOBAT2_MASK		(1 << 1)
+
+#define MAX8998_ENRAMP                  (1 << 4)
+
 /**
 /**
  * struct max8998_dev - max8998 master device for sub-drivers
  * struct max8998_dev - max8998 master device for sub-drivers
  * @dev: master device of the chip (can be used to access platform data)
  * @dev: master device of the chip (can be used to access platform data)
- * @i2c_client: i2c client private data
- * @dev_read():	chip register read function
- * @dev_write(): chip register write function
- * @dev_update(): chip register update function
+ * @i2c: i2c client private data for regulator
+ * @rtc: i2c client private data for rtc
  * @iolock: mutex for serializing io access
  * @iolock: mutex for serializing io access
+ * @irqlock: mutex for buslock
+ * @irq_base: base IRQ number for max8998, required for IRQs
+ * @irq: generic IRQ number for max8998
+ * @ono: power onoff IRQ number for max8998
+ * @irq_masks_cur: currently active value
+ * @irq_masks_cache: cached hardware value
+ * @type: indicate which max8998 "variant" is used
  */
  */
-
 struct max8998_dev {
 struct max8998_dev {
 	struct device *dev;
 	struct device *dev;
-	struct i2c_client *i2c_client;
-	int (*dev_read)(struct max8998_dev *max8998, u8 reg, u8 *dest);
-	int (*dev_write)(struct max8998_dev *max8998, u8 reg, u8 val);
-	int (*dev_update)(struct max8998_dev *max8998, u8 reg, u8 val, u8 mask);
+	struct i2c_client *i2c;
+	struct i2c_client *rtc;
 	struct mutex iolock;
 	struct mutex iolock;
+	struct mutex irqlock;
+
+	int irq_base;
+	int irq;
+	int ono;
+	u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
+	u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
+	int type;
 };
 };
 
 
-static inline int max8998_read_reg(struct max8998_dev *max8998, u8 reg,
-				   u8 *value)
-{
-	return max8998->dev_read(max8998, reg, value);
-}
-
-static inline int max8998_write_reg(struct max8998_dev *max8998, u8 reg,
-				    u8 value)
-{
-	return max8998->dev_write(max8998, reg, value);
-}
-
-static inline int max8998_update_reg(struct max8998_dev *max8998, u8 reg,
-				     u8 value, u8 mask)
-{
-	return max8998->dev_update(max8998, reg, value, mask);
-}
+int max8998_irq_init(struct max8998_dev *max8998);
+void max8998_irq_exit(struct max8998_dev *max8998);
+
+extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
+extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count,
+		u8 *buf);
+extern int max8998_write_reg(struct i2c_client *i2c, u8 reg, u8 value);
+extern int max8998_bulk_write(struct i2c_client *i2c, u8 reg, int count,
+		u8 *buf);
+extern int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask);
 
 
 #endif /*  __LINUX_MFD_MAX8998_PRIV_H */
 #endif /*  __LINUX_MFD_MAX8998_PRIV_H */

+ 19 - 4
include/linux/mfd/max8998.h

@@ -1,5 +1,5 @@
 /*
 /*
- * max8698.h - Voltage regulator driver for the Maxim 8998
+ * max8998.h - Voltage regulator driver for the Maxim 8998
  *
  *
  *  Copyright (C) 2009-2010 Samsung Electrnoics
  *  Copyright (C) 2009-2010 Samsung Electrnoics
  *  Kyungmin Park <kyungmin.park@samsung.com>
  *  Kyungmin Park <kyungmin.park@samsung.com>
@@ -66,13 +66,28 @@ struct max8998_regulator_data {
 
 
 /**
 /**
  * struct max8998_board - packages regulator init data
  * struct max8998_board - packages regulator init data
- * @num_regulators: number of regultors used
  * @regulators: array of defined regulators
  * @regulators: array of defined regulators
+ * @num_regulators: number of regultors used
+ * @irq_base: base IRQ number for max8998, required for IRQs
+ * @ono: power onoff IRQ number for max8998
+ * @buck1_max_voltage1: BUCK1 maximum alowed voltage register 1
+ * @buck1_max_voltage2: BUCK1 maximum alowed voltage register 2
+ * @buck2_max_voltage: BUCK2 maximum alowed voltage
+ * @buck1_set1: BUCK1 gpio pin 1 to set output voltage
+ * @buck1_set2: BUCK1 gpio pin 2 to set output voltage
+ * @buck2_set3: BUCK2 gpio pin to set output voltage
  */
  */
-
 struct max8998_platform_data {
 struct max8998_platform_data {
-	int				num_regulators;
 	struct max8998_regulator_data	*regulators;
 	struct max8998_regulator_data	*regulators;
+	int				num_regulators;
+	int				irq_base;
+	int				ono;
+	int                             buck1_max_voltage1;
+	int                             buck1_max_voltage2;
+	int                             buck2_max_voltage;
+	int				buck1_set1;
+	int				buck1_set2;
+	int				buck2_set3;
 };
 };
 
 
 #endif /*  __LINUX_MFD_MAX8998_H */
 #endif /*  __LINUX_MFD_MAX8998_H */

+ 98 - 141
include/linux/mfd/mc13783.h

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2009 Pengutronix
+ * Copyright 2009-2010 Pengutronix
  * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
  * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
  *
  *
  * This program is free software; you can redistribute it and/or modify it under
  * This program is free software; you can redistribute it and/or modify it under
@@ -9,48 +9,83 @@
 #ifndef __LINUX_MFD_MC13783_H
 #ifndef __LINUX_MFD_MC13783_H
 #define __LINUX_MFD_MC13783_H
 #define __LINUX_MFD_MC13783_H
 
 
-#include <linux/interrupt.h>
+#include <linux/mfd/mc13xxx.h>
 
 
 struct mc13783;
 struct mc13783;
 
 
-void mc13783_lock(struct mc13783 *mc13783);
-void mc13783_unlock(struct mc13783 *mc13783);
+struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783);
 
 
-int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val);
-int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val);
-int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
-		u32 mask, u32 val);
+static inline void mc13783_lock(struct mc13783 *mc13783)
+{
+	mc13xxx_lock(mc13783_to_mc13xxx(mc13783));
+}
+
+static inline void mc13783_unlock(struct mc13783 *mc13783)
+{
+	mc13xxx_unlock(mc13783_to_mc13xxx(mc13783));
+}
+
+static inline int mc13783_reg_read(struct mc13783 *mc13783,
+		unsigned int offset, u32 *val)
+{
+	return mc13xxx_reg_read(mc13783_to_mc13xxx(mc13783), offset, val);
+}
+
+static inline int mc13783_reg_write(struct mc13783 *mc13783,
+		unsigned int offset, u32 val)
+{
+	return mc13xxx_reg_write(mc13783_to_mc13xxx(mc13783), offset, val);
+}
+
+static inline int mc13783_reg_rmw(struct mc13783 *mc13783,
+		unsigned int offset, u32 mask, u32 val)
+{
+	return mc13xxx_reg_rmw(mc13783_to_mc13xxx(mc13783), offset, mask, val);
+}
 
 
-int mc13783_get_flags(struct mc13783 *mc13783);
+static inline int mc13783_get_flags(struct mc13783 *mc13783)
+{
+	return mc13xxx_get_flags(mc13783_to_mc13xxx(mc13783));
+}
 
 
-int mc13783_irq_request(struct mc13783 *mc13783, int irq,
-		irq_handler_t handler, const char *name, void *dev);
-int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,
-		irq_handler_t handler, const char *name, void *dev);
-int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev);
+static inline int mc13783_irq_request(struct mc13783 *mc13783, int irq,
+		irq_handler_t handler, const char *name, void *dev)
+{
+	return mc13xxx_irq_request(mc13783_to_mc13xxx(mc13783), irq,
+			handler, name, dev);
+}
 
 
-int mc13783_irq_mask(struct mc13783 *mc13783, int irq);
-int mc13783_irq_unmask(struct mc13783 *mc13783, int irq);
-int mc13783_irq_status(struct mc13783 *mc13783, int irq,
-		int *enabled, int *pending);
-int mc13783_irq_ack(struct mc13783 *mc13783, int irq);
+static inline int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,
+		irq_handler_t handler, const char *name, void *dev)
+{
+	return mc13xxx_irq_request_nounmask(mc13783_to_mc13xxx(mc13783), irq,
+			handler, name, dev);
+}
 
 
-static inline int mc13783_mask(struct mc13783 *mc13783, int irq) __deprecated;
-static inline int mc13783_mask(struct mc13783 *mc13783, int irq)
+static inline int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev)
 {
 {
-	return mc13783_irq_mask(mc13783, irq);
+	return mc13xxx_irq_free(mc13783_to_mc13xxx(mc13783), irq, dev);
 }
 }
 
 
-static inline int mc13783_unmask(struct mc13783 *mc13783, int irq) __deprecated;
-static inline int mc13783_unmask(struct mc13783 *mc13783, int irq)
+static inline int mc13783_irq_mask(struct mc13783 *mc13783, int irq)
 {
 {
-	return mc13783_irq_unmask(mc13783, irq);
+	return mc13xxx_irq_mask(mc13783_to_mc13xxx(mc13783), irq);
 }
 }
 
 
-static inline int mc13783_ackirq(struct mc13783 *mc13783, int irq) __deprecated;
-static inline int mc13783_ackirq(struct mc13783 *mc13783, int irq)
+static inline int mc13783_irq_unmask(struct mc13783 *mc13783, int irq)
 {
 {
-	return mc13783_irq_ack(mc13783, irq);
+	return mc13xxx_irq_unmask(mc13783_to_mc13xxx(mc13783), irq);
+}
+static inline int mc13783_irq_status(struct mc13783 *mc13783, int irq,
+		int *enabled, int *pending)
+{
+	return mc13xxx_irq_status(mc13783_to_mc13xxx(mc13783),
+			irq, enabled, pending);
+}
+
+static inline int mc13783_irq_ack(struct mc13783 *mc13783, int irq)
+{
+	return mc13xxx_irq_ack(mc13783_to_mc13xxx(mc13783), irq);
 }
 }
 
 
 #define MC13783_ADC0		43
 #define MC13783_ADC0		43
@@ -66,96 +101,18 @@ static inline int mc13783_ackirq(struct mc13783 *mc13783, int irq)
 					MC13783_ADC0_TSMOD1 | \
 					MC13783_ADC0_TSMOD1 | \
 					MC13783_ADC0_TSMOD2)
 					MC13783_ADC0_TSMOD2)
 
 
-struct mc13783_led_platform_data {
-#define MC13783_LED_MD		0
-#define MC13783_LED_AD		1
-#define MC13783_LED_KP		2
-#define MC13783_LED_R1		3
-#define MC13783_LED_G1		4
-#define MC13783_LED_B1		5
-#define MC13783_LED_R2		6
-#define MC13783_LED_G2		7
-#define MC13783_LED_B2		8
-#define MC13783_LED_R3		9
-#define MC13783_LED_G3		10
-#define MC13783_LED_B3		11
-#define MC13783_LED_MAX MC13783_LED_B3
-	int id;
-	const char *name;
-	const char *default_trigger;
-
-/* Three or two bits current selection depending on the led */
-	char max_current;
-};
-
-struct mc13783_leds_platform_data {
-	int num_leds;
-	struct mc13783_led_platform_data *led;
-
-#define MC13783_LED_TRIODE_MD	(1 << 0)
-#define MC13783_LED_TRIODE_AD	(1 << 1)
-#define MC13783_LED_TRIODE_KP	(1 << 2)
-#define MC13783_LED_BOOST_EN	(1 << 3)
-#define MC13783_LED_TC1HALF	(1 << 4)
-#define MC13783_LED_SLEWLIMTC	(1 << 5)
-#define MC13783_LED_SLEWLIMBL	(1 << 6)
-#define MC13783_LED_TRIODE_TC1	(1 << 7)
-#define MC13783_LED_TRIODE_TC2	(1 << 8)
-#define MC13783_LED_TRIODE_TC3	(1 << 9)
-	int flags;
-
-#define MC13783_LED_AB_DISABLED		0
-#define MC13783_LED_AB_MD1		1
-#define MC13783_LED_AB_MD12		2
-#define MC13783_LED_AB_MD123		3
-#define MC13783_LED_AB_MD1234		4
-#define MC13783_LED_AB_MD1234_AD1	5
-#define MC13783_LED_AB_MD1234_AD12	6
-#define MC13783_LED_AB_MD1_AD		7
-	char abmode;
-
-#define MC13783_LED_ABREF_200MV	0
-#define MC13783_LED_ABREF_400MV	1
-#define MC13783_LED_ABREF_600MV	2
-#define MC13783_LED_ABREF_800MV	3
-	char abref;
-
-#define MC13783_LED_PERIOD_10MS		0
-#define MC13783_LED_PERIOD_100MS	1
-#define MC13783_LED_PERIOD_500MS	2
-#define MC13783_LED_PERIOD_2S		3
-	char bl_period;
-	char tc1_period;
-	char tc2_period;
-	char tc3_period;
-};
-
-/* to be cleaned up */
-struct regulator_init_data;
-
-struct mc13783_regulator_init_data {
-	int id;
-	struct regulator_init_data *init_data;
-};
-
-struct mc13783_regulator_platform_data {
-	int num_regulators;
-	struct mc13783_regulator_init_data *regulators;
-};
-
-struct mc13783_platform_data {
-	int num_regulators;
-	struct mc13783_regulator_init_data *regulators;
-	struct mc13783_leds_platform_data *leds;
-
-#define MC13783_USE_TOUCHSCREEN (1 << 0)
-#define MC13783_USE_CODEC	(1 << 1)
-#define MC13783_USE_ADC		(1 << 2)
-#define MC13783_USE_RTC		(1 << 3)
-#define MC13783_USE_REGULATOR	(1 << 4)
-#define MC13783_USE_LED		(1 << 5)
-	unsigned int flags;
-};
+#define mc13783_regulator_init_data mc13xxx_regulator_init_data
+#define mc13783_regulator_platform_data mc13xxx_regulator_platform_data
+#define mc13783_led_platform_data mc13xxx_led_platform_data
+#define mc13783_leds_platform_data mc13xxx_leds_platform_data
+
+#define mc13783_platform_data mc13xxx_platform_data
+#define MC13783_USE_TOUCHSCREEN	MC13XXX_USE_TOUCHSCREEN
+#define MC13783_USE_CODEC	MC13XXX_USE_CODEC
+#define MC13783_USE_ADC		MC13XXX_USE_ADC
+#define MC13783_USE_RTC		MC13XXX_USE_RTC
+#define MC13783_USE_REGULATOR	MC13XXX_USE_REGULATOR
+#define MC13783_USE_LED		MC13XXX_USE_LED
 
 
 #define MC13783_ADC_MODE_TS		1
 #define MC13783_ADC_MODE_TS		1
 #define MC13783_ADC_MODE_SINGLE_CHAN	2
 #define MC13783_ADC_MODE_SINGLE_CHAN	2
@@ -199,46 +156,46 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
 #define	MC13783_REGU_PWGT1SPI	31
 #define	MC13783_REGU_PWGT1SPI	31
 #define	MC13783_REGU_PWGT2SPI	32
 #define	MC13783_REGU_PWGT2SPI	32
 
 
-#define MC13783_IRQ_ADCDONE	0
-#define MC13783_IRQ_ADCBISDONE	1
-#define MC13783_IRQ_TS		2
+#define MC13783_IRQ_ADCDONE	MC13XXX_IRQ_ADCDONE
+#define MC13783_IRQ_ADCBISDONE	MC13XXX_IRQ_ADCBISDONE
+#define MC13783_IRQ_TS		MC13XXX_IRQ_TS
 #define MC13783_IRQ_WHIGH	3
 #define MC13783_IRQ_WHIGH	3
 #define MC13783_IRQ_WLOW	4
 #define MC13783_IRQ_WLOW	4
-#define MC13783_IRQ_CHGDET	6
+#define MC13783_IRQ_CHGDET	MC13XXX_IRQ_CHGDET
 #define MC13783_IRQ_CHGOV	7
 #define MC13783_IRQ_CHGOV	7
-#define MC13783_IRQ_CHGREV	8
-#define MC13783_IRQ_CHGSHORT	9
-#define MC13783_IRQ_CCCV	10
-#define MC13783_IRQ_CHGCURR	11
-#define MC13783_IRQ_BPON	12
-#define MC13783_IRQ_LOBATL	13
-#define MC13783_IRQ_LOBATH	14
+#define MC13783_IRQ_CHGREV	MC13XXX_IRQ_CHGREV
+#define MC13783_IRQ_CHGSHORT	MC13XXX_IRQ_CHGSHORT
+#define MC13783_IRQ_CCCV	MC13XXX_IRQ_CCCV
+#define MC13783_IRQ_CHGCURR	MC13XXX_IRQ_CHGCURR
+#define MC13783_IRQ_BPON	MC13XXX_IRQ_BPON
+#define MC13783_IRQ_LOBATL	MC13XXX_IRQ_LOBATL
+#define MC13783_IRQ_LOBATH	MC13XXX_IRQ_LOBATH
 #define MC13783_IRQ_UDP		15
 #define MC13783_IRQ_UDP		15
 #define MC13783_IRQ_USB		16
 #define MC13783_IRQ_USB		16
 #define MC13783_IRQ_ID		19
 #define MC13783_IRQ_ID		19
 #define MC13783_IRQ_SE1		21
 #define MC13783_IRQ_SE1		21
 #define MC13783_IRQ_CKDET	22
 #define MC13783_IRQ_CKDET	22
 #define MC13783_IRQ_UDM		23
 #define MC13783_IRQ_UDM		23
-#define MC13783_IRQ_1HZ		24
-#define MC13783_IRQ_TODA	25
+#define MC13783_IRQ_1HZ		MC13XXX_IRQ_1HZ
+#define MC13783_IRQ_TODA	MC13XXX_IRQ_TODA
 #define MC13783_IRQ_ONOFD1	27
 #define MC13783_IRQ_ONOFD1	27
 #define MC13783_IRQ_ONOFD2	28
 #define MC13783_IRQ_ONOFD2	28
 #define MC13783_IRQ_ONOFD3	29
 #define MC13783_IRQ_ONOFD3	29
-#define MC13783_IRQ_SYSRST	30
-#define MC13783_IRQ_RTCRST	31
-#define MC13783_IRQ_PC		32
-#define MC13783_IRQ_WARM	33
-#define MC13783_IRQ_MEMHLD	34
+#define MC13783_IRQ_SYSRST	MC13XXX_IRQ_SYSRST
+#define MC13783_IRQ_RTCRST	MC13XXX_IRQ_RTCRST
+#define MC13783_IRQ_PC		MC13XXX_IRQ_PC
+#define MC13783_IRQ_WARM	MC13XXX_IRQ_WARM
+#define MC13783_IRQ_MEMHLD	MC13XXX_IRQ_MEMHLD
 #define MC13783_IRQ_PWRRDY	35
 #define MC13783_IRQ_PWRRDY	35
-#define MC13783_IRQ_THWARNL	36
-#define MC13783_IRQ_THWARNH	37
-#define MC13783_IRQ_CLK		38
+#define MC13783_IRQ_THWARNL	MC13XXX_IRQ_THWARNL
+#define MC13783_IRQ_THWARNH	MC13XXX_IRQ_THWARNH
+#define MC13783_IRQ_CLK		MC13XXX_IRQ_CLK
 #define MC13783_IRQ_SEMAF	39
 #define MC13783_IRQ_SEMAF	39
 #define MC13783_IRQ_MC2B	41
 #define MC13783_IRQ_MC2B	41
 #define MC13783_IRQ_HSDET	42
 #define MC13783_IRQ_HSDET	42
 #define MC13783_IRQ_HSL		43
 #define MC13783_IRQ_HSL		43
 #define MC13783_IRQ_ALSPTH	44
 #define MC13783_IRQ_ALSPTH	44
 #define MC13783_IRQ_AHSSHORT	45
 #define MC13783_IRQ_AHSSHORT	45
-#define MC13783_NUM_IRQ		46
+#define MC13783_NUM_IRQ		MC13XXX_NUM_IRQ
 
 
-#endif /* __LINUX_MFD_MC13783_H */
+#endif /* ifndef __LINUX_MFD_MC13783_H */

+ 154 - 0
include/linux/mfd/mc13xxx.h

@@ -0,0 +1,154 @@
+/*
+ * Copyright 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#ifndef __LINUX_MFD_MC13XXX_H
+#define __LINUX_MFD_MC13XXX_H
+
+#include <linux/interrupt.h>
+
+struct mc13xxx;
+
+void mc13xxx_lock(struct mc13xxx *mc13xxx);
+void mc13xxx_unlock(struct mc13xxx *mc13xxx);
+
+int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val);
+int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val);
+int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
+		u32 mask, u32 val);
+
+int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
+
+int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq,
+		irq_handler_t handler, const char *name, void *dev);
+int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq,
+		irq_handler_t handler, const char *name, void *dev);
+int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev);
+
+int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq);
+int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq);
+int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq,
+		int *enabled, int *pending);
+int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq);
+
+int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
+
+#define MC13XXX_IRQ_ADCDONE	0
+#define MC13XXX_IRQ_ADCBISDONE	1
+#define MC13XXX_IRQ_TS		2
+#define MC13XXX_IRQ_CHGDET	6
+#define MC13XXX_IRQ_CHGREV	8
+#define MC13XXX_IRQ_CHGSHORT	9
+#define MC13XXX_IRQ_CCCV	10
+#define MC13XXX_IRQ_CHGCURR	11
+#define MC13XXX_IRQ_BPON	12
+#define MC13XXX_IRQ_LOBATL	13
+#define MC13XXX_IRQ_LOBATH	14
+#define MC13XXX_IRQ_1HZ		24
+#define MC13XXX_IRQ_TODA	25
+#define MC13XXX_IRQ_SYSRST	30
+#define MC13XXX_IRQ_RTCRST	31
+#define MC13XXX_IRQ_PC		32
+#define MC13XXX_IRQ_WARM	33
+#define MC13XXX_IRQ_MEMHLD	34
+#define MC13XXX_IRQ_THWARNL	36
+#define MC13XXX_IRQ_THWARNH	37
+#define MC13XXX_IRQ_CLK		38
+
+#define MC13XXX_NUM_IRQ		46
+
+struct regulator_init_data;
+
+struct mc13xxx_regulator_init_data {
+	int id;
+	struct regulator_init_data *init_data;
+};
+
+struct mc13xxx_regulator_platform_data {
+	int num_regulators;
+	struct mc13xxx_regulator_init_data *regulators;
+};
+
+struct mc13xxx_led_platform_data {
+#define MC13783_LED_MD		0
+#define MC13783_LED_AD		1
+#define MC13783_LED_KP		2
+#define MC13783_LED_R1		3
+#define MC13783_LED_G1		4
+#define MC13783_LED_B1		5
+#define MC13783_LED_R2		6
+#define MC13783_LED_G2		7
+#define MC13783_LED_B2		8
+#define MC13783_LED_R3		9
+#define MC13783_LED_G3		10
+#define MC13783_LED_B3		11
+#define MC13783_LED_MAX MC13783_LED_B3
+	int id;
+	const char *name;
+	const char *default_trigger;
+
+/* Three or two bits current selection depending on the led */
+	char max_current;
+};
+
+struct mc13xxx_leds_platform_data {
+	int num_leds;
+	struct mc13xxx_led_platform_data *led;
+
+#define MC13783_LED_TRIODE_MD	(1 << 0)
+#define MC13783_LED_TRIODE_AD	(1 << 1)
+#define MC13783_LED_TRIODE_KP	(1 << 2)
+#define MC13783_LED_BOOST_EN	(1 << 3)
+#define MC13783_LED_TC1HALF	(1 << 4)
+#define MC13783_LED_SLEWLIMTC	(1 << 5)
+#define MC13783_LED_SLEWLIMBL	(1 << 6)
+#define MC13783_LED_TRIODE_TC1	(1 << 7)
+#define MC13783_LED_TRIODE_TC2	(1 << 8)
+#define MC13783_LED_TRIODE_TC3	(1 << 9)
+	int flags;
+
+#define MC13783_LED_AB_DISABLED		0
+#define MC13783_LED_AB_MD1		1
+#define MC13783_LED_AB_MD12		2
+#define MC13783_LED_AB_MD123		3
+#define MC13783_LED_AB_MD1234		4
+#define MC13783_LED_AB_MD1234_AD1	5
+#define MC13783_LED_AB_MD1234_AD12	6
+#define MC13783_LED_AB_MD1_AD		7
+	char abmode;
+
+#define MC13783_LED_ABREF_200MV	0
+#define MC13783_LED_ABREF_400MV	1
+#define MC13783_LED_ABREF_600MV	2
+#define MC13783_LED_ABREF_800MV	3
+	char abref;
+
+#define MC13783_LED_PERIOD_10MS		0
+#define MC13783_LED_PERIOD_100MS	1
+#define MC13783_LED_PERIOD_500MS	2
+#define MC13783_LED_PERIOD_2S		3
+	char bl_period;
+	char tc1_period;
+	char tc2_period;
+	char tc3_period;
+};
+
+struct mc13xxx_platform_data {
+#define MC13XXX_USE_TOUCHSCREEN (1 << 0)
+#define MC13XXX_USE_CODEC	(1 << 1)
+#define MC13XXX_USE_ADC		(1 << 2)
+#define MC13XXX_USE_RTC		(1 << 3)
+#define MC13XXX_USE_REGULATOR	(1 << 4)
+#define MC13XXX_USE_LED		(1 << 5)
+	unsigned int flags;
+
+	int num_regulators;
+	struct mc13xxx_regulator_init_data *regulators;
+	struct mc13xxx_leds_platform_data *leds;
+};
+
+#endif /* ifndef __LINUX_MFD_MC13XXX_H */

+ 7 - 0
include/linux/mfd/pcf50633/core.h

@@ -227,4 +227,11 @@ static inline struct pcf50633 *dev_to_pcf50633(struct device *dev)
 	return dev_get_drvdata(dev);
 	return dev_get_drvdata(dev);
 }
 }
 
 
+int pcf50633_irq_init(struct pcf50633 *pcf, int irq);
+void pcf50633_irq_free(struct pcf50633 *pcf);
+#ifdef CONFIG_PM
+int pcf50633_irq_suspend(struct pcf50633 *pcf);
+int pcf50633_irq_resume(struct pcf50633 *pcf);
+#endif
+
 #endif
 #endif

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

@@ -7,8 +7,10 @@ struct sh_mobile_sdhi_info {
 	int dma_slave_tx;
 	int dma_slave_tx;
 	int dma_slave_rx;
 	int dma_slave_rx;
 	unsigned long tmio_flags;
 	unsigned long tmio_flags;
+	unsigned long tmio_caps;
 	u32 tmio_ocr_mask;	/* available MMC voltages */
 	u32 tmio_ocr_mask;	/* available MMC voltages */
 	void (*set_pwr)(struct platform_device *pdev, int state);
 	void (*set_pwr)(struct platform_device *pdev, int state);
+	int (*get_cd)(struct platform_device *pdev);
 };
 };
 
 
 #endif /* __SH_MOBILE_SDHI_H__ */
 #endif /* __SH_MOBILE_SDHI_H__ */

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

@@ -112,13 +112,19 @@ struct stmpe_keypad_platform_data {
 	bool no_autorepeat;
 	bool no_autorepeat;
 };
 };
 
 
+#define STMPE_GPIO_NOREQ_811_TOUCH	(0xf0)
+
 /**
 /**
  * struct stmpe_gpio_platform_data - STMPE GPIO platform data
  * struct stmpe_gpio_platform_data - STMPE GPIO platform data
  * @gpio_base: first gpio number assigned.  A maximum of
  * @gpio_base: first gpio number assigned.  A maximum of
  *	       %STMPE_NR_GPIOS GPIOs will be allocated.
  *	       %STMPE_NR_GPIOS GPIOs will be allocated.
+ * @norequest_mask: bitmask specifying which GPIOs should _not_ be
+ *		    requestable due to different usage (e.g. touch, keypad)
+ *		    STMPE_GPIO_NOREQ_* macros can be used here.
  */
  */
 struct stmpe_gpio_platform_data {
 struct stmpe_gpio_platform_data {
 	int gpio_base;
 	int gpio_base;
+	unsigned norequest_mask;
 	void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
 	void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
 	void (*remove)(struct stmpe *stmpe, unsigned gpio_base);
 	void (*remove)(struct stmpe *stmpe, unsigned gpio_base);
 };
 };

+ 6 - 0
include/linux/mfd/tmio.h

@@ -52,6 +52,11 @@
 
 
 /* tmio MMC platform flags */
 /* tmio MMC platform flags */
 #define TMIO_MMC_WRPROTECT_DISABLE	(1 << 0)
 #define TMIO_MMC_WRPROTECT_DISABLE	(1 << 0)
+/*
+ * Some controllers can support a 2-byte block size when the bus width
+ * is configured in 4-bit mode.
+ */
+#define TMIO_MMC_BLKSZ_2BYTES		(1 << 1)
 
 
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
@@ -74,6 +79,7 @@ struct tmio_mmc_data {
 	struct tmio_mmc_dma		*dma;
 	struct tmio_mmc_dma		*dma;
 	void (*set_pwr)(struct platform_device *host, int state);
 	void (*set_pwr)(struct platform_device *host, int state);
 	void (*set_clk_div)(struct platform_device *host, int state);
 	void (*set_clk_div)(struct platform_device *host, int state);
+	int (*get_cd)(struct platform_device *host);
 };
 };
 
 
 /*
 /*

+ 31 - 0
include/linux/mfd/tps6586x.h

@@ -18,6 +18,36 @@ enum {
 	TPS6586X_ID_LDO_RTC,
 	TPS6586X_ID_LDO_RTC,
 };
 };
 
 
+enum {
+	TPS6586X_INT_PLDO_0,
+	TPS6586X_INT_PLDO_1,
+	TPS6586X_INT_PLDO_2,
+	TPS6586X_INT_PLDO_3,
+	TPS6586X_INT_PLDO_4,
+	TPS6586X_INT_PLDO_5,
+	TPS6586X_INT_PLDO_6,
+	TPS6586X_INT_PLDO_7,
+	TPS6586X_INT_COMP_DET,
+	TPS6586X_INT_ADC,
+	TPS6586X_INT_PLDO_8,
+	TPS6586X_INT_PLDO_9,
+	TPS6586X_INT_PSM_0,
+	TPS6586X_INT_PSM_1,
+	TPS6586X_INT_PSM_2,
+	TPS6586X_INT_PSM_3,
+	TPS6586X_INT_RTC_ALM1,
+	TPS6586X_INT_ACUSB_OVP,
+	TPS6586X_INT_USB_DET,
+	TPS6586X_INT_AC_DET,
+	TPS6586X_INT_BAT_DET,
+	TPS6586X_INT_CHG_STAT,
+	TPS6586X_INT_CHG_TEMP,
+	TPS6586X_INT_PP,
+	TPS6586X_INT_RESUME,
+	TPS6586X_INT_LOW_SYS,
+	TPS6586X_INT_RTC_ALM2,
+};
+
 struct tps6586x_subdev_info {
 struct tps6586x_subdev_info {
 	int		id;
 	int		id;
 	const char	*name;
 	const char	*name;
@@ -29,6 +59,7 @@ struct tps6586x_platform_data {
 	struct tps6586x_subdev_info *subdevs;
 	struct tps6586x_subdev_info *subdevs;
 
 
 	int gpio_base;
 	int gpio_base;
+	int irq_base;
 };
 };
 
 
 /*
 /*

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

@@ -238,6 +238,15 @@ struct regulator_dev;
 
 
 #define WM831X_NUM_IRQ_REGS 5
 #define WM831X_NUM_IRQ_REGS 5
 
 
+enum wm831x_parent {
+	WM8310 = 0x8310,
+	WM8311 = 0x8311,
+	WM8312 = 0x8312,
+	WM8320 = 0x8320,
+	WM8321 = 0x8321,
+	WM8325 = 0x8325,
+};
+
 struct wm831x {
 struct wm831x {
 	struct mutex io_lock;
 	struct mutex io_lock;
 
 
@@ -285,6 +294,9 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
 int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
 int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
 		     int count, u16 *buf);
 		     int count, u16 *buf);
 
 
+int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq);
+void wm831x_device_exit(struct wm831x *wm831x);
+int wm831x_device_suspend(struct wm831x *wm831x);
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 void wm831x_irq_exit(struct wm831x *wm831x);
 void wm831x_irq_exit(struct wm831x *wm831x);
 
 

+ 1 - 0
include/linux/mmc/sh_mmcif.h

@@ -34,6 +34,7 @@
 struct sh_mmcif_plat_data {
 struct sh_mmcif_plat_data {
 	void (*set_pwr)(struct platform_device *pdev, int state);
 	void (*set_pwr)(struct platform_device *pdev, int state);
 	void (*down_pwr)(struct platform_device *pdev);
 	void (*down_pwr)(struct platform_device *pdev);
+	int (*get_cd)(struct platform_device *pdef);
 	u8	sup_pclk;	/* 1 :SH7757, 0: SH7724/SH7372 */
 	u8	sup_pclk;	/* 1 :SH7757, 0: SH7724/SH7372 */
 	unsigned long caps;
 	unsigned long caps;
 	u32	ocr;
 	u32	ocr;