Merge branch 'for-next' of git://git.o-hand.com/linux-mfd
Linus Torvalds [Tue, 6 Jan 2009 03:04:09 +0000 (19:04 -0800)]
* 'for-next' of git://git.o-hand.com/linux-mfd: (30 commits)
  mfd: Fix section mismatch in da903x
  mfd: move drivers/i2c/chips/menelaus.c to drivers/mfd
  mfd: move drivers/i2c/chips/tps65010.c to drivers/mfd
  mfd: dm355evm msp430 driver
  mfd: Add missing break from wm3850-core
  mfd: Add WM8351 support
  mfd: Support configurable numbers of DCDCs and ISINKs on WM8350
  mfd: Handle missing WM8350 platform data
  mfd: Add WM8352 support
  mfd: Use irq_to_desc in twl4030 code
  power_supply: Add Dialog DA9030 battery charger driver
  mfd: Dialog DA9030 battery charger MFD driver
  mfd: Register WM8400 codec device
  mfd: Pass driver_data onto child devices
  mfd: Fix twl4030-core.c build error
  mfd: twl4030 regulator bug fixes
  mfd: twl4030: create some regulator devices
  mfd: twl4030: cleanup symbols and OMAP dependency
  mfd: twl4030: simplified child creation code
  power_supply: Add battery health reporting for WM8350
  ...

29 files changed:
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/da903x.c
drivers/mfd/dm355evm_msp.c [new file with mode: 0644]
drivers/mfd/menelaus.c [moved from drivers/i2c/chips/menelaus.c with 100% similarity]
drivers/mfd/mfd-core.c
drivers/mfd/tps65010.c [moved from drivers/i2c/chips/tps65010.c with 100% similarity]
drivers/mfd/twl4030-core.c
drivers/mfd/twl4030-irq.c
drivers/mfd/wm8350-core.c
drivers/mfd/wm8350-i2c.c
drivers/mfd/wm8350-regmap.c
drivers/mfd/wm8400-core.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/da9030_battery.c [new file with mode: 0644]
drivers/power/power_supply_sysfs.c
drivers/power/wm8350_power.c [new file with mode: 0644]
drivers/regulator/wm8350-regulator.c
include/linux/i2c/dm355evm_msp.h [new file with mode: 0644]
include/linux/i2c/twl4030.h
include/linux/mfd/da903x.h
include/linux/mfd/wm8350/comparator.h
include/linux/mfd/wm8350/core.h
include/linux/mfd/wm8350/pmic.h
include/linux/mfd/wm8350/supply.h
include/linux/power_supply.h

index 4c35702..864ac56 100644 (file)
@@ -126,19 +126,6 @@ config ISP1301_OMAP
          This driver can also be built as a module.  If so, the module
          will be called isp1301_omap.
 
-config TPS65010
-       tristate "TPS6501x Power Management chips"
-       depends on GPIOLIB
-       default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
-       help
-         If you say yes here you get support for the TPS6501x series of
-         Power Management chips.  These include voltage regulators,
-         lithium ion/polymer battery charging, and other features that
-         are often used in portable devices like cell phones and cameras.
-
-         This driver can also be built as a module.  If so, the module
-         will be called tps65010.
-
 config SENSORS_MAX6875
        tristate "Maxim MAX6875 Power supply supervisor"
        depends on EXPERIMENTAL
@@ -164,16 +151,6 @@ config SENSORS_TSL2550
          This driver can also be built as a module.  If so, the module
          will be called tsl2550.
 
-config MENELAUS
-       bool "TWL92330/Menelaus PM chip"
-       depends on I2C=y && ARCH_OMAP24XX
-       help
-         If you say yes here you get support for the Texas Instruments
-         TWL92330/Menelaus Power Management chip. This include voltage
-         regulators, Dual slot memory card tranceivers, real-time clock
-         and other features that are often used in portable devices like
-         cell phones and PDAs.
-
 config MCU_MPC8349EMITX
        tristate "MPC8349E-mITX MCU driver"
        depends on I2C && PPC_83xx
index 23d2a31..8b95f41 100644 (file)
@@ -19,8 +19,6 @@ obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
 obj-$(CONFIG_PCF8575)          += pcf8575.o
 obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_ISP1301_OMAP)     += isp1301_omap.o
-obj-$(CONFIG_TPS65010)         += tps65010.o
-obj-$(CONFIG_MENELAUS)         += menelaus.o
 obj-$(CONFIG_SENSORS_TSL2550)  += tsl2550.o
 obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
 
index 2572773..416f9e7 100644 (file)
@@ -34,6 +34,14 @@ config MFD_ASIC3
          This driver supports the ASIC3 multifunction chip found on many
          PDAs (mainly iPAQ and HTC based ones)
 
+config MFD_DM355EVM_MSP
+       bool "DaVinci DM355 EVM microcontroller"
+       depends on I2C && MACH_DAVINCI_DM355_EVM
+       help
+         This driver supports the MSP430 microcontroller used on these
+         boards.  MSP430 firmware manages resets and power sequencing,
+         inputs from buttons and the IR remote, LEDs, an RTC, and more.
+
 config HTC_EGPIO
        bool "HTC EGPIO support"
        depends on GENERIC_HARDIRQS && GPIOLIB && ARM
@@ -61,9 +69,32 @@ config UCB1400_CORE
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_core.
 
+config TPS65010
+       tristate "TPS6501x Power Management chips"
+       depends on I2C && GPIOLIB
+       default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
+       help
+         If you say yes here you get support for the TPS6501x series of
+         Power Management chips.  These include voltage regulators,
+         lithium ion/polymer battery charging, and other features that
+         are often used in portable devices like cell phones and cameras.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tps65010.
+
+config MENELAUS
+       bool "Texas Instruments TWL92330/Menelaus PM chip"
+       depends on I2C=y && ARCH_OMAP24XX
+       help
+         If you say yes here you get support for the Texas Instruments
+         TWL92330/Menelaus Power Management chip. This include voltage
+         regulators, Dual slot memory card tranceivers, real-time clock
+         and other features that are often used in portable devices like
+         cell phones and PDAs.
+
 config TWL4030_CORE
        bool "Texas Instruments TWL4030/TPS659x0 Support"
-       depends on I2C=y && GENERIC_HARDIRQS && (ARCH_OMAP2 || ARCH_OMAP3)
+       depends on I2C=y && GENERIC_HARDIRQS
        help
          Say yes here if you have TWL4030 family chip on your board.
          This core driver provides register access and IRQ handling
@@ -116,6 +147,7 @@ config PMIC_DA903X
 
 config MFD_WM8400
        tristate "Support Wolfson Microelectronics WM8400"
+       select MFD_CORE
        depends on I2C
        help
          Support for the Wolfson Microelecronics WM8400 PMIC and audio
@@ -142,6 +174,38 @@ config MFD_WM8350_CONFIG_MODE_3
        bool
        depends on MFD_WM8350
 
+config MFD_WM8351_CONFIG_MODE_0
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8351_CONFIG_MODE_1
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8351_CONFIG_MODE_2
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8351_CONFIG_MODE_3
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_0
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_1
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_2
+       bool
+       depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_3
+       bool
+       depends on MFD_WM8350
+
 config MFD_WM8350_I2C
        tristate "Support Wolfson Microelectronics WM8350 with I2C"
        select MFD_WM8350
index 9a5ad8a..0c9418b 100644 (file)
@@ -8,6 +8,8 @@ obj-$(CONFIG_MFD_ASIC3)         += asic3.o
 obj-$(CONFIG_HTC_EGPIO)                += htc-egpio.o
 obj-$(CONFIG_HTC_PASIC3)       += htc-pasic3.o
 
+obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
+
 obj-$(CONFIG_MFD_T7L66XB)      += t7l66xb.o
 obj-$(CONFIG_MFD_TC6387XB)     += tc6387xb.o
 obj-$(CONFIG_MFD_TC6393XB)     += tc6393xb.o
@@ -17,6 +19,9 @@ wm8350-objs                   := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
 obj-$(CONFIG_MFD_WM8350)       += wm8350.o
 obj-$(CONFIG_MFD_WM8350_I2C)   += wm8350-i2c.o
 
+obj-$(CONFIG_TPS65010)         += tps65010.o
+obj-$(CONFIG_MENELAUS)         += menelaus.o
+
 obj-$(CONFIG_TWL4030_CORE)     += twl4030-core.o twl4030-irq.o
 
 obj-$(CONFIG_MFD_CORE)         += mfd-core.o
@@ -31,4 +36,4 @@ obj-$(CONFIG_MCP_UCB1200)     += ucb1x00-assabet.o
 endif
 obj-$(CONFIG_UCB1400_CORE)     += ucb1400_core.o
 
-obj-$(CONFIG_PMIC_DA903X)      += da903x.o
\ No newline at end of file
+obj-$(CONFIG_PMIC_DA903X)      += da903x.o
index 0b5bd85..99f8dcf 100644 (file)
@@ -151,12 +151,24 @@ int da903x_write(struct device *dev, int reg, uint8_t val)
 }
 EXPORT_SYMBOL_GPL(da903x_write);
 
+int da903x_writes(struct device *dev, int reg, int len, uint8_t *val)
+{
+       return __da903x_writes(to_i2c_client(dev), reg, len, val);
+}
+EXPORT_SYMBOL_GPL(da903x_writes);
+
 int da903x_read(struct device *dev, int reg, uint8_t *val)
 {
        return __da903x_read(to_i2c_client(dev), reg, val);
 }
 EXPORT_SYMBOL_GPL(da903x_read);
 
+int da903x_reads(struct device *dev, int reg, int len, uint8_t *val)
+{
+       return __da903x_reads(to_i2c_client(dev), reg, len, val);
+}
+EXPORT_SYMBOL_GPL(da903x_reads);
+
 int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
 {
        struct da903x_chip *chip = dev_get_drvdata(dev);
@@ -435,13 +447,13 @@ static const struct i2c_device_id da903x_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, da903x_id_table);
 
-static int __devexit __remove_subdev(struct device *dev, void *unused)
+static int __remove_subdev(struct device *dev, void *unused)
 {
        platform_device_unregister(to_platform_device(dev));
        return 0;
 }
 
-static int __devexit da903x_remove_subdevs(struct da903x_chip *chip)
+static int da903x_remove_subdevs(struct da903x_chip *chip)
 {
        return device_for_each_child(chip->dev, NULL, __remove_subdev);
 }
diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c
new file mode 100644 (file)
index 0000000..4214b3f
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * dm355evm_msp.c - driver for MSP430 firmware on DM355EVM board
+ *
+ * Copyright (C) 2008 David Brownell
+ *
+ * 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/init.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/i2c.h>
+#include <linux/i2c/dm355evm_msp.h>
+
+
+/*
+ * The DM355 is a DaVinci chip with video support but no C64+ DSP.  Its
+ * EVM board has an MSP430 programmed with firmware for various board
+ * support functions.  This driver exposes some of them directly, and
+ * supports other drivers (e.g. RTC, input) for more complex access.
+ *
+ * Because this firmware is entirely board-specific, this file embeds
+ * knowledge that would be passed as platform_data in a generic driver.
+ *
+ * This driver was tested with firmware revision A4.
+ */
+
+#if defined(CONFIG_KEYBOARD_DM355EVM) \
+               || defined(CONFIG_KEYBOARD_DM355EVM_MODULE)
+#define msp_has_keyboard()     true
+#else
+#define msp_has_keyboard()     false
+#endif
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#define msp_has_leds()         true
+#else
+#define msp_has_leds()         false
+#endif
+
+#if defined(CONFIG_RTC_DRV_DM355EVM) || defined(CONFIG_RTC_DRV_DM355EVM_MODULE)
+#define msp_has_rtc()          true
+#else
+#define msp_has_rtc()          false
+#endif
+
+#if defined(CONFIG_VIDEO_TVP514X) || defined(CONFIG_VIDEO_TVP514X_MODULE)
+#define msp_has_tvp()          true
+#else
+#define msp_has_tvp()          false
+#endif
+
+
+/*----------------------------------------------------------------------*/
+
+/* REVISIT for paranoia's sake, retry reads/writes on error */
+
+static struct i2c_client *msp430;
+
+/**
+ * dm355evm_msp_write - Writes a register in dm355evm_msp
+ * @value: the value to be written
+ * @reg: register address
+ *
+ * Returns result of operation - 0 is success, else negative errno
+ */
+int dm355evm_msp_write(u8 value, u8 reg)
+{
+       return i2c_smbus_write_byte_data(msp430, reg, value);
+}
+EXPORT_SYMBOL(dm355evm_msp_write);
+
+/**
+ * dm355evm_msp_read - Reads a register from dm355evm_msp
+ * @reg: register address
+ *
+ * Returns result of operation - value, or negative errno
+ */
+int dm355evm_msp_read(u8 reg)
+{
+       return i2c_smbus_read_byte_data(msp430, reg);
+}
+EXPORT_SYMBOL(dm355evm_msp_read);
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Many of the msp430 pins are just used as fixed-direction GPIOs.
+ * We could export a few more of them this way, if we wanted.
+ */
+#define MSP_GPIO(bit,reg)      ((DM355EVM_MSP_ ## reg) << 3 | (bit))
+
+static const u8 msp_gpios[] = {
+       /* eight leds */
+       MSP_GPIO(0, LED), MSP_GPIO(1, LED),
+       MSP_GPIO(2, LED), MSP_GPIO(3, LED),
+       MSP_GPIO(4, LED), MSP_GPIO(5, LED),
+       MSP_GPIO(6, LED), MSP_GPIO(7, LED),
+       /* SW6 and the NTSC/nPAL jumper */
+       MSP_GPIO(0, SWITCH1), MSP_GPIO(1, SWITCH1),
+       MSP_GPIO(2, SWITCH1), MSP_GPIO(3, SWITCH1),
+       MSP_GPIO(4, SWITCH1),
+};
+
+#define MSP_GPIO_REG(offset)   (msp_gpios[(offset)] >> 3)
+#define MSP_GPIO_MASK(offset)  BIT(msp_gpios[(offset)] & 0x07)
+
+static int msp_gpio_in(struct gpio_chip *chip, unsigned offset)
+{
+       switch (MSP_GPIO_REG(offset)) {
+       case DM355EVM_MSP_SWITCH1:
+       case DM355EVM_MSP_SWITCH2:
+       case DM355EVM_MSP_SDMMC:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static u8 msp_led_cache;
+
+static int msp_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       int reg, status;
+
+       reg = MSP_GPIO_REG(offset);
+       status = dm355evm_msp_read(reg);
+       if (status < 0)
+               return status;
+       if (reg == DM355EVM_MSP_LED)
+               msp_led_cache = status;
+       return status & MSP_GPIO_MASK(offset);
+}
+
+static int msp_gpio_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+       int mask, bits;
+
+       /* NOTE:  there are some other signals that could be
+        * packaged as output GPIOs, but they aren't as useful
+        * as the LEDs ... so for now we don't.
+        */
+       if (MSP_GPIO_REG(offset) != DM355EVM_MSP_LED)
+               return -EINVAL;
+
+       mask = MSP_GPIO_MASK(offset);
+       bits = msp_led_cache;
+
+       bits &= ~mask;
+       if (value)
+               bits |= mask;
+       msp_led_cache = bits;
+
+       return dm355evm_msp_write(bits, DM355EVM_MSP_LED);
+}
+
+static void msp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       msp_gpio_out(chip, offset, value);
+}
+
+static struct gpio_chip dm355evm_msp_gpio = {
+       .label                  = "dm355evm_msp",
+       .owner                  = THIS_MODULE,
+       .direction_input        = msp_gpio_in,
+       .get                    = msp_gpio_get,
+       .direction_output       = msp_gpio_out,
+       .set                    = msp_gpio_set,
+       .base                   = -EINVAL,              /* dynamic assignment */
+       .ngpio                  = ARRAY_SIZE(msp_gpios),
+       .can_sleep              = true,
+};
+
+/*----------------------------------------------------------------------*/
+
+static struct device *add_child(struct i2c_client *client, const char *name,
+               void *pdata, unsigned pdata_len,
+               bool can_wakeup, int irq)
+{
+       struct platform_device  *pdev;
+       int                     status;
+
+       pdev = platform_device_alloc(name, -1);
+       if (!pdev) {
+               dev_dbg(&client->dev, "can't alloc dev\n");
+               status = -ENOMEM;
+               goto err;
+       }
+
+       device_init_wakeup(&pdev->dev, can_wakeup);
+       pdev->dev.parent = &client->dev;
+
+       if (pdata) {
+               status = platform_device_add_data(pdev, pdata, pdata_len);
+               if (status < 0) {
+                       dev_dbg(&pdev->dev, "can't add platform_data\n");
+                       goto err;
+               }
+       }
+
+       if (irq) {
+               struct resource r = {
+                       .start = irq,
+                       .flags = IORESOURCE_IRQ,
+               };
+
+               status = platform_device_add_resources(pdev, &r, 1);
+               if (status < 0) {
+                       dev_dbg(&pdev->dev, "can't add irq\n");
+                       goto err;
+               }
+       }
+
+       status = platform_device_add(pdev);
+
+err:
+       if (status < 0) {
+               platform_device_put(pdev);
+               dev_err(&client->dev, "can't add %s dev\n", name);
+               return ERR_PTR(status);
+       }
+       return &pdev->dev;
+}
+
+static int add_children(struct i2c_client *client)
+{
+       static const struct {
+               int offset;
+               char *label;
+       } config_inputs[] = {
+               /* 8 == right after the LEDs */
+               { 8 + 0, "sw6_1", },
+               { 8 + 1, "sw6_2", },
+               { 8 + 2, "sw6_3", },
+               { 8 + 3, "sw6_4", },
+               { 8 + 4, "NTSC/nPAL", },
+       };
+
+       struct device   *child;
+       int             status;
+       int             i;
+
+       /* GPIO-ish stuff */
+       dm355evm_msp_gpio.dev = &client->dev;
+       status = gpiochip_add(&dm355evm_msp_gpio);
+       if (status < 0)
+               return status;
+
+       /* LED output */
+       if (msp_has_leds()) {
+#define GPIO_LED(l)    .name = l, .active_low = true
+               static struct gpio_led evm_leds[] = {
+                       { GPIO_LED("dm355evm::ds14"),
+                               .default_trigger = "heartbeat", },
+                       { GPIO_LED("dm355evm::ds15"),
+                               .default_trigger = "mmc0", },
+                       { GPIO_LED("dm355evm::ds16"),
+                               /* could also be a CE-ATA drive */
+                               .default_trigger = "mmc1", },
+                       { GPIO_LED("dm355evm::ds17"),
+                               .default_trigger = "nand-disk", },
+                       { GPIO_LED("dm355evm::ds18"), },
+                       { GPIO_LED("dm355evm::ds19"), },
+                       { GPIO_LED("dm355evm::ds20"), },
+                       { GPIO_LED("dm355evm::ds21"), },
+               };
+#undef GPIO_LED
+
+               struct gpio_led_platform_data evm_led_data = {
+                       .num_leds       = ARRAY_SIZE(evm_leds),
+                       .leds           = evm_leds,
+               };
+
+               for (i = 0; i < ARRAY_SIZE(evm_leds); i++)
+                       evm_leds[i].gpio = i + dm355evm_msp_gpio.base;
+
+               /* NOTE:  these are the only fully programmable LEDs
+                * on the board, since GPIO-61/ds22 (and many signals
+                * going to DC7) must be used for AEMIF address lines
+                * unless the top 1 GB of NAND is unused...
+                */
+               child = add_child(client, "leds-gpio",
+                               &evm_led_data, sizeof(evm_led_data),
+                               false, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       /* configuration inputs */
+       for (i = 0; i < ARRAY_SIZE(config_inputs); i++) {
+               int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset;
+
+               gpio_request(gpio, config_inputs[i].label);
+               gpio_direction_input(gpio);
+
+               /* make it easy for userspace to see these */
+               gpio_export(gpio, false);
+       }
+
+       /* RTC is a 32 bit counter, no alarm */
+       if (msp_has_rtc()) {
+               child = add_child(client, "rtc-dm355evm",
+                               NULL, 0, false, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       /* input from buttons and IR remote (uses the IRQ) */
+       if (msp_has_keyboard()) {
+               child = add_child(client, "dm355evm_keys",
+                               NULL, 0, true, client->irq);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       return 0;
+}
+
+/*----------------------------------------------------------------------*/
+
+static void dm355evm_command(unsigned command)
+{
+       int status;
+
+       status = dm355evm_msp_write(command, DM355EVM_MSP_COMMAND);
+       if (status < 0)
+               dev_err(&msp430->dev, "command %d failure %d\n",
+                               command, status);
+}
+
+static void dm355evm_power_off(void)
+{
+       dm355evm_command(MSP_COMMAND_POWEROFF);
+}
+
+static int dm355evm_msp_remove(struct i2c_client *client)
+{
+       pm_power_off = NULL;
+       msp430 = NULL;
+       return 0;
+}
+
+static int
+dm355evm_msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int             status;
+       const char      *video = msp_has_tvp() ? "TVP5146" : "imager";
+
+       if (msp430)
+               return -EBUSY;
+       msp430 = client;
+
+       /* display revision status; doubles as sanity check */
+       status = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
+       if (status < 0)
+               goto fail;
+       dev_info(&client->dev, "firmware v.%02X, %s as video-in\n",
+                       status, video);
+
+       /* mux video input:  either tvp5146 or some external imager */
+       status = dm355evm_msp_write(msp_has_tvp() ? 0 : MSP_VIDEO_IMAGER,
+                       DM355EVM_MSP_VIDEO_IN);
+       if (status < 0)
+               dev_warn(&client->dev, "error %d muxing %s as video-in\n",
+                       status, video);
+
+       /* init LED cache, and turn off the LEDs */
+       msp_led_cache = 0xff;
+       dm355evm_msp_write(msp_led_cache, DM355EVM_MSP_LED);
+
+       /* export capabilities we support */
+       status = add_children(client);
+       if (status < 0)
+               goto fail;
+
+       /* PM hookup */
+       pm_power_off = dm355evm_power_off;
+
+       return 0;
+
+fail:
+       /* FIXME remove children ... */
+       dm355evm_msp_remove(client);
+       return status;
+}
+
+static const struct i2c_device_id dm355evm_msp_ids[] = {
+       { "dm355evm_msp", 0 },
+       { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(i2c, dm355evm_msp_ids);
+
+static struct i2c_driver dm355evm_msp_driver = {
+       .driver.name    = "dm355evm_msp",
+       .id_table       = dm355evm_msp_ids,
+       .probe          = dm355evm_msp_probe,
+       .remove         = dm355evm_msp_remove,
+};
+
+static int __init dm355evm_msp_init(void)
+{
+       return i2c_add_driver(&dm355evm_msp_driver);
+}
+subsys_initcall(dm355evm_msp_init);
+
+static void __exit dm355evm_msp_exit(void)
+{
+       i2c_del_driver(&dm355evm_msp_driver);
+}
+module_exit(dm355evm_msp_exit);
+
+MODULE_DESCRIPTION("Interface to MSP430 firmware on DM355EVM");
+MODULE_LICENSE("GPL");
index 6c0d1be..54ddf37 100644 (file)
@@ -34,6 +34,7 @@ static int mfd_add_device(struct device *parent, int id,
                goto fail_device;
 
        pdev->dev.parent = parent;
+       platform_set_drvdata(pdev, cell->driver_data);
 
        ret = platform_device_add_data(pdev,
                        cell->platform_data, cell->data_size);
index dd843c4..b59c385 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 
+#include <linux/regulator/machine.h>
+
 #include <linux/i2c.h>
 #include <linux/i2c/twl4030.h>
 
 #define twl_has_gpio() false
 #endif
 
+#if defined(CONFIG_REGULATOR_TWL4030) \
+       || defined(CONFIG_REGULATOR_TWL4030_MODULE)
+#define twl_has_regulator()    true
+#else
+#define twl_has_regulator()    false
+#endif
+
 #if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
 #define twl_has_madc() true
 #else
 #define HIGH_PERF_SQ                   (1 << 3)
 
 
+/* chip-specific feature flags, for i2c_device_id.driver_data */
+#define TWL4030_VAUX2          BIT(0)  /* pre-5030 voltage ranges */
+#define TPS_SUBSET             BIT(1)  /* tps659[23]0 have fewer LDOs */
+
 /*----------------------------------------------------------------------*/
 
 /* is driver active, bound to a chip? */
@@ -225,7 +238,7 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
  *
  * Returns the result of operation - 0 is success
  */
-int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
 {
        int ret;
        int sid;
@@ -274,7 +287,7 @@ EXPORT_SYMBOL(twl4030_i2c_write);
  *
  * Returns result of operation - num_bytes is success else failure.
  */
-int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
 {
        int ret;
        u8 val;
@@ -352,258 +365,258 @@ EXPORT_SYMBOL(twl4030_i2c_read_u8);
 
 /*----------------------------------------------------------------------*/
 
-/*
- * NOTE:  We know the first 8 IRQs after pdata->base_irq are
- * for the PIH, and the next are for the PWR_INT SIH, since
- * that's how twl_init_irq() sets things up.
- */
-
-static int add_children(struct twl4030_platform_data *pdata)
+static struct device *
+add_numbered_child(unsigned chip, const char *name, int num,
+               void *pdata, unsigned pdata_len,
+               bool can_wakeup, int irq0, int irq1)
 {
-       struct platform_device  *pdev = NULL;
-       struct twl4030_client   *twl = NULL;
-       int                     status = 0;
+       struct platform_device  *pdev;
+       struct twl4030_client   *twl = &twl4030_modules[chip];
+       int                     status;
+
+       pdev = platform_device_alloc(name, num);
+       if (!pdev) {
+               dev_dbg(&twl->client->dev, "can't alloc dev\n");
+               status = -ENOMEM;
+               goto err;
+       }
 
-       if (twl_has_bci() && pdata->bci) {
-               twl = &twl4030_modules[3];
+       device_init_wakeup(&pdev->dev, can_wakeup);
+       pdev->dev.parent = &twl->client->dev;
 
-               pdev = platform_device_alloc("twl4030_bci", -1);
-               if (!pdev) {
-                       pr_debug("%s: can't alloc bci dev\n", DRIVER_NAME);
-                       status = -ENOMEM;
+       if (pdata) {
+               status = platform_device_add_data(pdev, pdata, pdata_len);
+               if (status < 0) {
+                       dev_dbg(&pdev->dev, "can't add platform_data\n");
                        goto err;
                }
+       }
 
-               if (status == 0) {
-                       pdev->dev.parent = &twl->client->dev;
-                       status = platform_device_add_data(pdev, pdata->bci,
-                                       sizeof(*pdata->bci));
-                       if (status < 0) {
-                               dev_dbg(&twl->client->dev,
-                                       "can't add bci data, %d\n",
-                                       status);
-                               goto err;
-                       }
-               }
-
-               if (status == 0) {
-                       struct resource r = {
-                               .start = pdata->irq_base + 8 + 1,
-                               .flags = IORESOURCE_IRQ,
-                       };
-
-                       status = platform_device_add_resources(pdev, &r, 1);
-               }
-
-               if (status == 0)
-                       status = platform_device_add(pdev);
+       if (irq0) {
+               struct resource r[2] = {
+                       { .start = irq0, .flags = IORESOURCE_IRQ, },
+                       { .start = irq1, .flags = IORESOURCE_IRQ, },
+               };
 
+               status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
                if (status < 0) {
-                       platform_device_put(pdev);
-                       dev_dbg(&twl->client->dev,
-                                       "can't create bci dev, %d\n",
-                                       status);
+                       dev_dbg(&pdev->dev, "can't add irqs\n");
                        goto err;
                }
        }
 
-       if (twl_has_gpio() && pdata->gpio) {
-               twl = &twl4030_modules[1];
+       status = platform_device_add(pdev);
 
-               pdev = platform_device_alloc("twl4030_gpio", -1);
-               if (!pdev) {
-                       pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME);
-                       status = -ENOMEM;
-                       goto err;
-               }
+err:
+       if (status < 0) {
+               platform_device_put(pdev);
+               dev_err(&twl->client->dev, "can't add %s dev\n", name);
+               return ERR_PTR(status);
+       }
+       return &pdev->dev;
+}
 
-               /* more driver model init */
-               if (status == 0) {
-                       pdev->dev.parent = &twl->client->dev;
-                       /* device_init_wakeup(&pdev->dev, 1); */
-
-                       status = platform_device_add_data(pdev, pdata->gpio,
-                                       sizeof(*pdata->gpio));
-                       if (status < 0) {
-                               dev_dbg(&twl->client->dev,
-                                       "can't add gpio data, %d\n",
-                                       status);
-                               goto err;
-                       }
-               }
+static inline struct device *add_child(unsigned chip, const char *name,
+               void *pdata, unsigned pdata_len,
+               bool can_wakeup, int irq0, int irq1)
+{
+       return add_numbered_child(chip, name, -1, pdata, pdata_len,
+               can_wakeup, irq0, irq1);
+}
 
-               /* GPIO module IRQ */
-               if (status == 0) {
-                       struct resource r = {
-                               .start = pdata->irq_base + 0,
-                               .flags = IORESOURCE_IRQ,
-                       };
+static struct device *
+add_regulator_linked(int num, struct regulator_init_data *pdata,
+               struct regulator_consumer_supply *consumers,
+               unsigned num_consumers)
+{
+       /* regulator framework demands init_data ... */
+       if (!pdata)
+               return NULL;
 
-                       status = platform_device_add_resources(pdev, &r, 1);
-               }
+       if (consumers) {
+               pdata->consumer_supplies = consumers;
+               pdata->num_consumer_supplies = num_consumers;
+       }
 
-               if (status == 0)
-                       status = platform_device_add(pdev);
+       /* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
+       return add_numbered_child(3, "twl4030_reg", num,
+               pdata, sizeof(*pdata), false, 0, 0);
+}
 
-               if (status < 0) {
-                       platform_device_put(pdev);
-                       dev_dbg(&twl->client->dev,
-                                       "can't create gpio dev, %d\n",
-                                       status);
-                       goto err;
-               }
+static struct device *
+add_regulator(int num, struct regulator_init_data *pdata)
+{
+       return add_regulator_linked(num, pdata, NULL, 0);
+}
+
+/*
+ * NOTE:  We know the first 8 IRQs after pdata->base_irq are
+ * for the PIH, and the next are for the PWR_INT SIH, since
+ * that's how twl_init_irq() sets things up.
+ */
+
+static int
+add_children(struct twl4030_platform_data *pdata, unsigned long features)
+{
+       struct device   *child;
+       struct device   *usb_transceiver = NULL;
+
+       if (twl_has_bci() && pdata->bci && !(features & TPS_SUBSET)) {
+               child = add_child(3, "twl4030_bci",
+                               pdata->bci, sizeof(*pdata->bci),
+                               false,
+                               /* irq0 = CHG_PRES, irq1 = BCI */
+                               pdata->irq_base + 8 + 1, pdata->irq_base + 2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (twl_has_gpio() && pdata->gpio) {
+               child = add_child(1, "twl4030_gpio",
+                               pdata->gpio, sizeof(*pdata->gpio),
+                               false, pdata->irq_base + 0, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
        }
 
        if (twl_has_keypad() && pdata->keypad) {
-               pdev = platform_device_alloc("twl4030_keypad", -1);
-               if (pdev) {
-                       twl = &twl4030_modules[2];
-                       pdev->dev.parent = &twl->client->dev;
-                       device_init_wakeup(&pdev->dev, 1);
-                       status = platform_device_add_data(pdev, pdata->keypad,
-                                       sizeof(*pdata->keypad));
-                       if (status < 0) {
-                               dev_dbg(&twl->client->dev,
-                                       "can't add keypad data, %d\n",
-                                       status);
-                               platform_device_put(pdev);
-                               goto err;
-                       }
-                       status = platform_device_add(pdev);
-                       if (status < 0) {
-                               platform_device_put(pdev);
-                               dev_dbg(&twl->client->dev,
-                                               "can't create keypad dev, %d\n",
-                                               status);
-                               goto err;
-                       }
-               } else {
-                       pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
-                       status = -ENOMEM;
-                       goto err;
-               }
+               child = add_child(2, "twl4030_keypad",
+                               pdata->keypad, sizeof(*pdata->keypad),
+                               true, pdata->irq_base + 1, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
        }
 
        if (twl_has_madc() && pdata->madc) {
-               pdev = platform_device_alloc("twl4030_madc", -1);
-               if (pdev) {
-                       twl = &twl4030_modules[2];
-                       pdev->dev.parent = &twl->client->dev;
-                       device_init_wakeup(&pdev->dev, 1);
-                       status = platform_device_add_data(pdev, pdata->madc,
-                                       sizeof(*pdata->madc));
-                       if (status < 0) {
-                               platform_device_put(pdev);
-                               dev_dbg(&twl->client->dev,
-                                       "can't add madc data, %d\n",
-                                       status);
-                               goto err;
-                       }
-                       status = platform_device_add(pdev);
-                       if (status < 0) {
-                               platform_device_put(pdev);
-                               dev_dbg(&twl->client->dev,
-                                               "can't create madc dev, %d\n",
-                                               status);
-                               goto err;
-                       }
-               } else {
-                       pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
-                       status = -ENOMEM;
-                       goto err;
-               }
+               child = add_child(2, "twl4030_madc",
+                               pdata->madc, sizeof(*pdata->madc),
+                               true, pdata->irq_base + 3, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
        }
 
        if (twl_has_rtc()) {
-               twl = &twl4030_modules[3];
-
-               pdev = platform_device_alloc("twl4030_rtc", -1);
-               if (!pdev) {
-                       pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
-                       status = -ENOMEM;
-               } else {
-                       pdev->dev.parent = &twl->client->dev;
-                       device_init_wakeup(&pdev->dev, 1);
-               }
-
                /*
-                * REVISIT platform_data here currently might use of
+                * REVISIT platform_data here currently might expose the
                 * "msecure" line ... but for now we just expect board
-                * setup to tell the chip "we are secure" at all times.
+                * setup to tell the chip "it's always ok to SET_TIME".
                 * Eventually, Linux might become more aware of such
                 * HW security concerns, and "least privilege".
                 */
-
-               /* RTC module IRQ */
-               if (status == 0) {
-                       struct resource r = {
-                               .start = pdata->irq_base + 8 + 3,
-                               .flags = IORESOURCE_IRQ,
-                       };
-
-                       status = platform_device_add_resources(pdev, &r, 1);
-               }
-
-               if (status == 0)
-                       status = platform_device_add(pdev);
-
-               if (status < 0) {
-                       platform_device_put(pdev);
-                       dev_dbg(&twl->client->dev,
-                                       "can't create rtc dev, %d\n",
-                                       status);
-                       goto err;
-               }
+               child = add_child(3, "twl4030_rtc",
+                               NULL, 0,
+                               true, pdata->irq_base + 8 + 3, 0);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
        }
 
        if (twl_has_usb() && pdata->usb) {
-               twl = &twl4030_modules[0];
-
-               pdev = platform_device_alloc("twl4030_usb", -1);
-               if (!pdev) {
-                       pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
-                       status = -ENOMEM;
-                       goto err;
-               }
-
-               if (status == 0) {
-                       pdev->dev.parent = &twl->client->dev;
-                       device_init_wakeup(&pdev->dev, 1);
-                       status = platform_device_add_data(pdev, pdata->usb,
-                                       sizeof(*pdata->usb));
-                       if (status < 0) {
-                               platform_device_put(pdev);
-                               dev_dbg(&twl->client->dev,
-                                       "can't add usb data, %d\n",
-                                       status);
-                               goto err;
-                       }
-               }
-
-               if (status == 0) {
-                       struct resource r = {
-                               .start = pdata->irq_base + 8 + 2,
-                               .flags = IORESOURCE_IRQ,
-                       };
+               child = add_child(0, "twl4030_usb",
+                               pdata->usb, sizeof(*pdata->usb),
+                               true,
+                               /* irq0 = USB_PRES, irq1 = USB */
+                               pdata->irq_base + 8 + 2, pdata->irq_base + 4);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               /* we need to connect regulators to this transceiver */
+               usb_transceiver = child;
+       }
 
-                       status = platform_device_add_resources(pdev, &r, 1);
-               }
+       if (twl_has_regulator()) {
+               /*
+               child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+               */
+
+               child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator((features & TWL4030_VAUX2)
+                                       ? TWL4030_REG_VAUX2_4030
+                                       : TWL4030_REG_VAUX2,
+                               pdata->vaux2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
 
-               if (status == 0)
-                       status = platform_device_add(pdev);
+       if (twl_has_regulator() && usb_transceiver) {
+               static struct regulator_consumer_supply usb1v5 = {
+                       .supply =       "usb1v5",
+               };
+               static struct regulator_consumer_supply usb1v8 = {
+                       .supply =       "usb1v8",
+               };
+               static struct regulator_consumer_supply usb3v1 = {
+                       .supply =       "usb3v1",
+               };
+
+               /* this is a template that gets copied */
+               struct regulator_init_data usb_fixed = {
+                       .constraints.valid_modes_mask =
+                                 REGULATOR_MODE_NORMAL
+                               | REGULATOR_MODE_STANDBY,
+                       .constraints.valid_ops_mask =
+                                 REGULATOR_CHANGE_MODE
+                               | REGULATOR_CHANGE_STATUS,
+               };
+
+               usb1v5.dev = usb_transceiver;
+               usb1v8.dev = usb_transceiver;
+               usb3v1.dev = usb_transceiver;
+
+               child = add_regulator_linked(TWL4030_REG_VUSB1V5, &usb_fixed,
+                               &usb1v5, 1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator_linked(TWL4030_REG_VUSB1V8, &usb_fixed,
+                               &usb1v8, 1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator_linked(TWL4030_REG_VUSB3V1, &usb_fixed,
+                               &usb3v1, 1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
 
-               if (status < 0) {
-                       platform_device_put(pdev);
-                       dev_dbg(&twl->client->dev,
-                                       "can't create usb dev, %d\n",
-                                       status);
-               }
+       /* maybe add LDOs that are omitted on cost-reduced parts */
+       if (twl_has_regulator() && !(features & TPS_SUBSET)) {
+               /*
+               child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+               */
+
+               child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
        }
 
-err:
-       if (status)
-               pr_err("failed to add twl4030's children (status %d)\n", status);
-       return status;
+       return 0;
 }
 
 /*----------------------------------------------------------------------*/
@@ -645,12 +658,7 @@ static void __init clocks_init(void)
                osc = clk_get(NULL, "osc_ck");
        else
                osc = clk_get(NULL, "osc_sys_ck");
-#else
-       /* REVISIT for non-OMAP systems, pass the clock rate from
-        * board init code, using platform_data.
-        */
-       osc = ERR_PTR(-EIO);
-#endif
+
        if (IS_ERR(osc)) {
                printk(KERN_WARNING "Skipping twl4030 internal clock init and "
                                "using bootloader value (unknown osc rate)\n");
@@ -660,6 +668,18 @@ static void __init clocks_init(void)
        rate = clk_get_rate(osc);
        clk_put(osc);
 
+#else
+       /* REVISIT for non-OMAP systems, pass the clock rate from
+        * board init code, using platform_data.
+        */
+       osc = ERR_PTR(-EIO);
+
+       printk(KERN_WARNING "Skipping twl4030 internal clock init and "
+              "using bootloader value (unknown osc rate)\n");
+
+       return;
+#endif
+
        switch (rate) {
        case 19200000:
                ctrl = HFCLK_FREQ_19p2_MHZ;
@@ -764,7 +784,7 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
                        goto fail;
        }
 
-       status = add_children(pdata);
+       status = add_children(pdata, id->driver_data);
 fail:
        if (status < 0)
                twl4030_remove(client);
@@ -772,11 +792,11 @@ fail:
 }
 
 static const struct i2c_device_id twl4030_ids[] = {
-       { "twl4030", 0 },       /* "Triton 2" */
-       { "tps65950", 0 },      /* catalog version of twl4030 */
-       { "tps65930", 0 },      /* fewer LDOs and DACs; no charger */
-       { "tps65920", 0 },      /* fewer LDOs; no codec or charger */
-       { "twl5030", 0 },       /* T2 updated */
+       { "twl4030", TWL4030_VAUX2 },   /* "Triton 2" */
+       { "twl5030", 0 },               /* T2 updated */
+       { "tps65950", 0 },              /* catalog version of twl5030 */
+       { "tps65930", TPS_SUBSET },     /* fewer LDOs and DACs; no charger */
+       { "tps65920", TPS_SUBSET },     /* fewer LDOs; no codec or charger */
        { /* end of list */ },
 };
 MODULE_DEVICE_TABLE(i2c, twl4030_ids);
index fae868a..b108760 100644 (file)
@@ -180,10 +180,15 @@ static struct completion irq_event;
 static int twl4030_irq_thread(void *data)
 {
        long irq = (long)data;
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_to_desc(irq);
        static unsigned i2c_errors;
        const static unsigned max_i2c_errors = 100;
 
+       if (!desc) {
+               pr_err("twl4030: Invalid IRQ: %ld\n", irq);
+               return -EINVAL;
+       }
+
        current->flags |= PF_NOFREEZE;
 
        while (!kthread_should_stop()) {
@@ -215,7 +220,13 @@ static int twl4030_irq_thread(void *data)
                                pih_isr;
                                pih_isr >>= 1, module_irq++) {
                        if (pih_isr & 0x1) {
-                               irq_desc_t *d = irq_desc + module_irq;
+                               struct irq_desc *d = irq_to_desc(module_irq);
+
+                               if (!d) {
+                                       pr_err("twl4030: Invalid SIH IRQ: %d\n",
+                                              module_irq);
+                                       return -EINVAL;
+                               }
 
                                /* These can't be masked ... always warn
                                 * if we get any surprises.
@@ -452,10 +463,16 @@ static void twl4030_sih_do_edge(struct work_struct *work)
        /* Modify only the bits we know must change */
        while (edge_change) {
                int             i = fls(edge_change) - 1;
-               struct irq_desc *d = irq_desc + i + agent->irq_base;
+               struct irq_desc *d = irq_to_desc(i + agent->irq_base);
                int             byte = 1 + (i >> 2);
                int             off = (i & 0x3) * 2;
 
+               if (!d) {
+                       pr_err("twl4030: Invalid IRQ: %d\n",
+                              i + agent->irq_base);
+                       return;
+               }
+
                bytes[byte] &= ~(0x03 << off);
 
                spin_lock_irq(&d->lock);
@@ -512,9 +529,14 @@ static void twl4030_sih_unmask(unsigned irq)
 static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
 {
        struct sih_agent *sih = get_irq_chip_data(irq);
-       struct irq_desc *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
+       if (!desc) {
+               pr_err("twl4030: Invalid IRQ: %d\n", irq);
+               return -EINVAL;
+       }
+
        if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
                return -EINVAL;
 
index 0d47fb9..3a273cc 100644 (file)
@@ -63,7 +63,6 @@
  */
 static DEFINE_MUTEX(io_mutex);
 static DEFINE_MUTEX(reg_lock_mutex);
-static DEFINE_MUTEX(auxadc_mutex);
 
 /* Perform a physical read from the device.
  */
@@ -299,6 +298,13 @@ int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
 }
 EXPORT_SYMBOL_GPL(wm8350_block_write);
 
+/**
+ * wm8350_reg_lock()
+ *
+ * The WM8350 has a hardware lock which can be used to prevent writes to
+ * some registers (generally those which can cause particularly serious
+ * problems if misused).  This function enables that lock.
+ */
 int wm8350_reg_lock(struct wm8350 *wm8350)
 {
        u16 key = WM8350_LOCK_KEY;
@@ -314,6 +320,15 @@ int wm8350_reg_lock(struct wm8350 *wm8350)
 }
 EXPORT_SYMBOL_GPL(wm8350_reg_lock);
 
+/**
+ * wm8350_reg_unlock()
+ *
+ * The WM8350 has a hardware lock which can be used to prevent writes to
+ * some registers (generally those which can cause particularly serious
+ * problems if misused).  This function disables that lock so updates
+ * can be performed.  For maximum safety this should be done only when
+ * required.
+ */
 int wm8350_reg_unlock(struct wm8350 *wm8350)
 {
        u16 key = WM8350_UNLOCK_KEY;
@@ -1066,38 +1081,158 @@ int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
 }
 EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
 
+int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
+{
+       u16 reg, result = 0;
+       int tries = 5;
+
+       if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP)
+               return -EINVAL;
+       if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP
+           && (scale != 0 || vref != 0))
+               return -EINVAL;
+
+       mutex_lock(&wm8350->auxadc_mutex);
+
+       /* Turn on the ADC */
+       reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+       wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA);
+
+       if (scale || vref) {
+               reg = scale << 13;
+               reg |= vref << 12;
+               wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg);
+       }
+
+       reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+       reg |= 1 << channel | WM8350_AUXADC_POLL;
+       wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);
+
+       do {
+               schedule_timeout_interruptible(1);
+               reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+       } while (tries-- && (reg & WM8350_AUXADC_POLL));
+
+       if (!tries)
+               dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
+       else
+               result = wm8350_reg_read(wm8350,
+                                        WM8350_AUX1_READBACK + channel);
+
+       /* Turn off the ADC */
+       reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+       wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5,
+                        reg & ~WM8350_AUXADC_ENA);
+
+       mutex_unlock(&wm8350->auxadc_mutex);
+
+       return result & WM8350_AUXADC_DATA1_MASK;
+}
+EXPORT_SYMBOL_GPL(wm8350_read_auxadc);
+
 /*
  * Cache is always host endian.
  */
-static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
+static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
 {
        int i, ret = 0;
        u16 value;
        const u16 *reg_map;
 
-       switch (mode) {
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+       switch (type) {
        case 0:
-               reg_map = wm8350_mode0_defaults;
-               break;
+               switch (mode) {
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+               case 0:
+                       reg_map = wm8350_mode0_defaults;
+                       break;
 #endif
 #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
-       case 1:
-               reg_map = wm8350_mode1_defaults;
-               break;
+               case 1:
+                       reg_map = wm8350_mode1_defaults;
+                       break;
 #endif
 #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
-       case 2:
-               reg_map = wm8350_mode2_defaults;
-               break;
+               case 2:
+                       reg_map = wm8350_mode2_defaults;
+                       break;
 #endif
 #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
-       case 3:
-               reg_map = wm8350_mode3_defaults;
+               case 3:
+                       reg_map = wm8350_mode3_defaults;
+                       break;
+#endif
+               default:
+                       dev_err(wm8350->dev,
+                               "WM8350 configuration mode %d not supported\n",
+                               mode);
+                       return -EINVAL;
+               }
+               break;
+
+       case 1:
+               switch (mode) {
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
+               case 0:
+                       reg_map = wm8351_mode0_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
+               case 1:
+                       reg_map = wm8351_mode1_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
+               case 2:
+                       reg_map = wm8351_mode2_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
+               case 3:
+                       reg_map = wm8351_mode3_defaults;
+                       break;
+#endif
+               default:
+                       dev_err(wm8350->dev,
+                               "WM8351 configuration mode %d not supported\n",
+                               mode);
+                       return -EINVAL;
+               }
                break;
+
+       case 2:
+               switch (mode) {
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
+               case 0:
+                       reg_map = wm8352_mode0_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
+               case 1:
+                       reg_map = wm8352_mode1_defaults;
+                       break;
 #endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
+               case 2:
+                       reg_map = wm8352_mode2_defaults;
+                       break;
+#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
+               case 3:
+                       reg_map = wm8352_mode3_defaults;
+                       break;
+#endif
+               default:
+                       dev_err(wm8350->dev,
+                               "WM8352 configuration mode %d not supported\n",
+                               mode);
+                       return -EINVAL;
+               }
+               break;
+
        default:
-               dev_err(wm8350->dev, "Configuration mode %d not supported\n",
+               dev_err(wm8350->dev,
+                       "WM835x configuration mode %d not supported\n",
                        mode);
                return -EINVAL;
        }
@@ -1163,53 +1298,113 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
                       struct wm8350_platform_data *pdata)
 {
        int ret = -EINVAL;
-       u16 id1, id2, mask, mode;
+       u16 id1, id2, mask_rev;
+       u16 cust_id, mode, chip_rev;
 
        /* get WM8350 revision and config mode */
        wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
        wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
+       wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev), &mask_rev);
 
        id1 = be16_to_cpu(id1);
        id2 = be16_to_cpu(id2);
+       mask_rev = be16_to_cpu(mask_rev);
 
-       if (id1 == 0x6143) {
-               switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
+       if (id1 != 0x6143) {
+               dev_err(wm8350->dev,
+                       "Device with ID %x is not a WM8350\n", id1);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       mode = id2 & WM8350_CONF_STS_MASK >> 10;
+       cust_id = id2 & WM8350_CUST_ID_MASK;
+       chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
+       dev_info(wm8350->dev,
+                "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n",
+                mode, cust_id, mask_rev, chip_rev);
+
+       if (cust_id != 0) {
+               dev_err(wm8350->dev, "Unsupported CUST_ID\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       switch (mask_rev) {
+       case 0:
+               wm8350->pmic.max_dcdc = WM8350_DCDC_6;
+               wm8350->pmic.max_isink = WM8350_ISINK_B;
+
+               switch (chip_rev) {
                case WM8350_REV_E:
-                       dev_info(wm8350->dev, "Found Rev E device\n");
-                       wm8350->rev = WM8350_REV_E;
+                       dev_info(wm8350->dev, "WM8350 Rev E\n");
                        break;
                case WM8350_REV_F:
-                       dev_info(wm8350->dev, "Found Rev F device\n");
-                       wm8350->rev = WM8350_REV_F;
+                       dev_info(wm8350->dev, "WM8350 Rev F\n");
                        break;
                case WM8350_REV_G:
-                       dev_info(wm8350->dev, "Found Rev G device\n");
-                       wm8350->rev = WM8350_REV_G;
+                       dev_info(wm8350->dev, "WM8350 Rev G\n");
+                       wm8350->power.rev_g_coeff = 1;
+                       break;
+               case WM8350_REV_H:
+                       dev_info(wm8350->dev, "WM8350 Rev H\n");
+                       wm8350->power.rev_g_coeff = 1;
                        break;
                default:
                        /* For safety we refuse to run on unknown hardware */
-                       dev_info(wm8350->dev, "Found unknown rev\n");
+                       dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n");
                        ret = -ENODEV;
                        goto err;
                }
-       } else {
-               dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
-                        id1);
+               break;
+
+       case 1:
+               wm8350->pmic.max_dcdc = WM8350_DCDC_4;
+               wm8350->pmic.max_isink = WM8350_ISINK_A;
+
+               switch (chip_rev) {
+               case 0:
+                       dev_info(wm8350->dev, "WM8351 Rev A\n");
+                       wm8350->power.rev_g_coeff = 1;
+                       break;
+
+               default:
+                       dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n");
+                       ret = -ENODEV;
+                       goto err;
+               }
+               break;
+
+       case 2:
+               wm8350->pmic.max_dcdc = WM8350_DCDC_6;
+               wm8350->pmic.max_isink = WM8350_ISINK_B;
+
+               switch (chip_rev) {
+               case 0:
+                       dev_info(wm8350->dev, "WM8352 Rev A\n");
+                       wm8350->power.rev_g_coeff = 1;
+                       break;
+
+               default:
+                       dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n");
+                       ret = -ENODEV;
+                       goto err;
+               }
+               break;
+
+       default:
+               dev_err(wm8350->dev, "Unknown MASK_REV\n");
                ret = -ENODEV;
                goto err;
        }
 
-       mode = id2 & WM8350_CONF_STS_MASK >> 10;
-       mask = id2 & WM8350_CUST_ID_MASK;
-       dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask);
-
-       ret = wm8350_create_cache(wm8350, mode);
+       ret = wm8350_create_cache(wm8350, mask_rev, mode);
        if (ret < 0) {
-               printk(KERN_ERR "wm8350: failed to create register cache\n");
+               dev_err(wm8350->dev, "Failed to create register cache\n");
                return ret;
        }
 
-       if (pdata->init) {
+       if (pdata && pdata->init) {
                ret = pdata->init(wm8350);
                if (ret != 0) {
                        dev_err(wm8350->dev, "Platform init() failed: %d\n",
@@ -1218,6 +1413,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
                }
        }
 
+       mutex_init(&wm8350->auxadc_mutex);
        mutex_init(&wm8350->irq_mutex);
        INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
        if (irq) {
index 3e0ce0e..8d8c932 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * wm8350-i2c.c  --  Generic I2C driver for Wolfson WM8350 PMIC
  *
- * This driver defines and configures the WM8350 for the Freescale i.MX32ADS.
- *
  * Copyright 2007, 2008 Wolfson Microelectronics PLC.
  *
  * Author: Liam Girdwood
@@ -99,6 +97,8 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
 
 static const struct i2c_device_id wm8350_i2c_id[] = {
        { "wm8350", 0 },
+       { "wm8351", 0 },
+       { "wm8352", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id);
index 974678d..68887b8 100644 (file)
@@ -1074,6 +1074,2102 @@ const u16 wm8350_mode3_defaults[] = {
 };
 #endif
 
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode0_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0001,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0004,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x0000,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0FFC,     /* R134 - GPIO Configuration (i/o) */
+       0x0FFC,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0013,     /* R140 - GPIO Function Select 1 */
+       0x0000,     /* R141 - GPIO Function Select 2 */
+       0x0000,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 */
+       0x0000,     /* R175 */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0000,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0000,     /* R186 - DCDC3 Control */
+       0x0000,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0000,     /* R189 - DCDC4 Control */
+       0x0000,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 */
+       0x0000,     /* R193 */
+       0x0000,     /* R194 */
+       0x0000,     /* R195 */
+       0x0000,     /* R196 */
+       0x0006,     /* R197 */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001C,     /* R200 - LDO1 Control */
+       0x0000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x001B,     /* R203 - LDO2 Control */
+       0x0000,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001B,     /* R206 - LDO3 Control */
+       0x0000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001B,     /* R209 - LDO4 Control */
+       0x0000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 - FLL Test 1 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x0000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x1000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode1_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0001,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0204,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x0000,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0CFB,     /* R134 - GPIO Configuration (i/o) */
+       0x0C1F,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0300,     /* R140 - GPIO Function Select 1 */
+       0x1110,     /* R141 - GPIO Function Select 2 */
+       0x0013,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 */
+       0x0000,     /* R175 */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0C00,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0026,     /* R186 - DCDC3 Control */
+       0x0400,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0062,     /* R189 - DCDC4 Control */
+       0x0800,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 */
+       0x0000,     /* R193 */
+       0x0000,     /* R194 */
+       0x000A,     /* R195 */
+       0x1000,     /* R196 */
+       0x0006,     /* R197 */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x0006,     /* R200 - LDO1 Control */
+       0x0000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x0010,     /* R203 - LDO2 Control */
+       0x0C00,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001F,     /* R206 - LDO3 Control */
+       0x0800,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x000A,     /* R209 - LDO4 Control */
+       0x0800,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 - FLL Test 1 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x1000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x1000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode2_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0001,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0214,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x0110,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x09FA,     /* R134 - GPIO Configuration (i/o) */
+       0x0DF6,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x1310,     /* R140 - GPIO Function Select 1 */
+       0x0003,     /* R141 - GPIO Function Select 2 */
+       0x2000,     /* R142 - GPIO Function Select 3 */
+       0x0000,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 */
+       0x0000,     /* R175 */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x001A,     /* R180 - DCDC1 Control */
+       0x0800,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0056,     /* R186 - DCDC3 Control */
+       0x0400,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0026,     /* R189 - DCDC4 Control */
+       0x0C00,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 */
+       0x0000,     /* R193 */
+       0x0000,     /* R194 */
+       0x0026,     /* R195 */
+       0x0C00,     /* R196 */
+       0x0006,     /* R197 */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001C,     /* R200 - LDO1 Control */
+       0x0400,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x0010,     /* R203 - LDO2 Control */
+       0x0C00,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x0015,     /* R206 - LDO3 Control */
+       0x0000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001A,     /* R209 - LDO4 Control */
+       0x0000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 - FLL Test 1 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x0000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x1000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode3_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0001,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0204,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0010,     /* R129 - GPIO Pin pull up Control */
+       0x0000,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0BFB,     /* R134 - GPIO Configuration (i/o) */
+       0x0FFD,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0310,     /* R140 - GPIO Function Select 1 */
+       0x0001,     /* R141 - GPIO Function Select 2 */
+       0x2300,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 */
+       0x0000,     /* R175 */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0400,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0026,     /* R186 - DCDC3 Control */
+       0x0800,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0062,     /* R189 - DCDC4 Control */
+       0x1400,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 */
+       0x0000,     /* R193 */
+       0x0000,     /* R194 */
+       0x0026,     /* R195 */
+       0x0400,     /* R196 */
+       0x0006,     /* R197 */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x0006,     /* R200 - LDO1 Control */
+       0x0C00,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x0016,     /* R203 - LDO2 Control */
+       0x0000,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x0019,     /* R206 - LDO3 Control */
+       0x0000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001A,     /* R209 - LDO4 Control */
+       0x1000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 - FLL Test 1 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x0000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x1000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode0_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0002,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0004,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x0000,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0FFC,     /* R134 - GPIO Configuration (i/o) */
+       0x0FFC,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0013,     /* R140 - GPIO Function Select 1 */
+       0x0000,     /* R141 - GPIO Function Select 2 */
+       0x0000,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0000,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0000,     /* R186 - DCDC3 Control */
+       0x0000,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0000,     /* R189 - DCDC4 Control */
+       0x0000,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0000,     /* R195 - DCDC6 Control */
+       0x0000,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001C,     /* R200 - LDO1 Control */
+       0x0000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x001B,     /* R203 - LDO2 Control */
+       0x0000,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001B,     /* R206 - LDO3 Control */
+       0x0000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001B,     /* R209 - LDO4 Control */
+       0x0000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x0000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x5000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+       0x5100,     /* R252 */
+       0x1000,     /* R253 - DCDC6 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode1_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0002,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0204,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x0000,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0BFB,     /* R134 - GPIO Configuration (i/o) */
+       0x0FFF,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0300,     /* R140 - GPIO Function Select 1 */
+       0x0000,     /* R141 - GPIO Function Select 2 */
+       0x2300,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x0062,     /* R180 - DCDC1 Control */
+       0x0400,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0006,     /* R186 - DCDC3 Control */
+       0x0800,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x0006,     /* R189 - DCDC4 Control */
+       0x0C00,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0026,     /* R195 - DCDC6 Control */
+       0x1000,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x0002,     /* R200 - LDO1 Control */
+       0x0000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x001A,     /* R203 - LDO2 Control */
+       0x0000,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001F,     /* R206 - LDO3 Control */
+       0x0000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001F,     /* R209 - LDO4 Control */
+       0x0000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x0000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x5000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+       0x5100,     /* R252 */
+       0x1000,     /* R253 - DCDC6 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode2_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0002,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0204,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0000,     /* R129 - GPIO Pin pull up Control */
+       0x0110,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x09DA,     /* R134 - GPIO Configuration (i/o) */
+       0x0DD6,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x1310,     /* R140 - GPIO Function Select 1 */
+       0x0033,     /* R141 - GPIO Function Select 2 */
+       0x2000,     /* R142 - GPIO Function Select 3 */
+       0x0000,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x000E,     /* R180 - DCDC1 Control */
+       0x0800,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0056,     /* R186 - DCDC3 Control */
+       0x1800,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x000E,     /* R189 - DCDC4 Control */
+       0x1000,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0026,     /* R195 - DCDC6 Control */
+       0x0C00,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001C,     /* R200 - LDO1 Control */
+       0x0000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x0006,     /* R203 - LDO2 Control */
+       0x0400,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x001C,     /* R206 - LDO3 Control */
+       0x1400,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x001A,     /* R209 - LDO4 Control */
+       0x0000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x0000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x5000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+       0x5100,     /* R252 */
+       0x1000,     /* R253 - DCDC6 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode3_defaults[] = {
+       0x6143,     /* R0   - Reset/ID */
+       0x0000,     /* R1   - ID */
+       0x0002,     /* R2   - Revision */
+       0x1C02,     /* R3   - System Control 1 */
+       0x0204,     /* R4   - System Control 2 */
+       0x0000,     /* R5   - System Hibernate */
+       0x8A00,     /* R6   - Interface Control */
+       0x0000,     /* R7 */
+       0x8000,     /* R8   - Power mgmt (1) */
+       0x0000,     /* R9   - Power mgmt (2) */
+       0x0000,     /* R10  - Power mgmt (3) */
+       0x2000,     /* R11  - Power mgmt (4) */
+       0x0E00,     /* R12  - Power mgmt (5) */
+       0x0000,     /* R13  - Power mgmt (6) */
+       0x0000,     /* R14  - Power mgmt (7) */
+       0x0000,     /* R15 */
+       0x0000,     /* R16  - RTC Seconds/Minutes */
+       0x0100,     /* R17  - RTC Hours/Day */
+       0x0101,     /* R18  - RTC Date/Month */
+       0x1400,     /* R19  - RTC Year */
+       0x0000,     /* R20  - Alarm Seconds/Minutes */
+       0x0000,     /* R21  - Alarm Hours/Day */
+       0x0000,     /* R22  - Alarm Date/Month */
+       0x0320,     /* R23  - RTC Time Control */
+       0x0000,     /* R24  - System Interrupts */
+       0x0000,     /* R25  - Interrupt Status 1 */
+       0x0000,     /* R26  - Interrupt Status 2 */
+       0x0000,     /* R27 */
+       0x0000,     /* R28  - Under Voltage Interrupt status */
+       0x0000,     /* R29  - Over Current Interrupt status */
+       0x0000,     /* R30  - GPIO Interrupt Status */
+       0x0000,     /* R31  - Comparator Interrupt Status */
+       0x3FFF,     /* R32  - System Interrupts Mask */
+       0x0000,     /* R33  - Interrupt Status 1 Mask */
+       0x0000,     /* R34  - Interrupt Status 2 Mask */
+       0x0000,     /* R35 */
+       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
+       0x0000,     /* R37  - Over Current Interrupt status Mask */
+       0x0000,     /* R38  - GPIO Interrupt Status Mask */
+       0x0000,     /* R39  - Comparator Interrupt Status Mask */
+       0x0040,     /* R40  - Clock Control 1 */
+       0x0000,     /* R41  - Clock Control 2 */
+       0x3A00,     /* R42  - FLL Control 1 */
+       0x7086,     /* R43  - FLL Control 2 */
+       0xC226,     /* R44  - FLL Control 3 */
+       0x0000,     /* R45  - FLL Control 4 */
+       0x0000,     /* R46 */
+       0x0000,     /* R47 */
+       0x0000,     /* R48  - DAC Control */
+       0x0000,     /* R49 */
+       0x00C0,     /* R50  - DAC Digital Volume L */
+       0x00C0,     /* R51  - DAC Digital Volume R */
+       0x0000,     /* R52 */
+       0x0040,     /* R53  - DAC LR Rate */
+       0x0000,     /* R54  - DAC Clock Control */
+       0x0000,     /* R55 */
+       0x0000,     /* R56 */
+       0x0000,     /* R57 */
+       0x4000,     /* R58  - DAC Mute */
+       0x0000,     /* R59  - DAC Mute Volume */
+       0x0000,     /* R60  - DAC Side */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x8000,     /* R64  - ADC Control */
+       0x0000,     /* R65 */
+       0x00C0,     /* R66  - ADC Digital Volume L */
+       0x00C0,     /* R67  - ADC Digital Volume R */
+       0x0000,     /* R68  - ADC Divider */
+       0x0000,     /* R69 */
+       0x0040,     /* R70  - ADC LR Rate */
+       0x0000,     /* R71 */
+       0x0303,     /* R72  - Input Control */
+       0x0000,     /* R73  - IN3 Input Control */
+       0x0000,     /* R74  - Mic Bias Control */
+       0x0000,     /* R75 */
+       0x0000,     /* R76  - Output Control */
+       0x0000,     /* R77  - Jack Detect */
+       0x0000,     /* R78  - Anti Pop Control */
+       0x0000,     /* R79 */
+       0x0040,     /* R80  - Left Input Volume */
+       0x0040,     /* R81  - Right Input Volume */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84 */
+       0x0000,     /* R85 */
+       0x0000,     /* R86 */
+       0x0000,     /* R87 */
+       0x0800,     /* R88  - Left Mixer Control */
+       0x1000,     /* R89  - Right Mixer Control */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92  - OUT3 Mixer Control */
+       0x0000,     /* R93  - OUT4 Mixer Control */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96  - Output Left Mixer Volume */
+       0x0000,     /* R97  - Output Right Mixer Volume */
+       0x0000,     /* R98  - Input Mixer Volume L */
+       0x0000,     /* R99  - Input Mixer Volume R */
+       0x0000,     /* R100 - Input Mixer Volume */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x00E4,     /* R104 - OUT1L Volume */
+       0x00E4,     /* R105 - OUT1R Volume */
+       0x00E4,     /* R106 - OUT2L Volume */
+       0x02E4,     /* R107 - OUT2R Volume */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 - BEEP Volume */
+       0x0A00,     /* R112 - AI Formating */
+       0x0000,     /* R113 - ADC DAC COMP */
+       0x0020,     /* R114 - AI ADC Control */
+       0x0020,     /* R115 - AI DAC Control */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x1FFF,     /* R128 - GPIO Debounce */
+       0x0010,     /* R129 - GPIO Pin pull up Control */
+       0x0000,     /* R130 - GPIO Pull down Control */
+       0x0000,     /* R131 - GPIO Interrupt Mode */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 - GPIO Control */
+       0x0BFB,     /* R134 - GPIO Configuration (i/o) */
+       0x0FFD,     /* R135 - GPIO Pin Polarity / Type */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0310,     /* R140 - GPIO Function Select 1 */
+       0x0001,     /* R141 - GPIO Function Select 2 */
+       0x2300,     /* R142 - GPIO Function Select 3 */
+       0x0003,     /* R143 - GPIO Function Select 4 */
+       0x0000,     /* R144 - Digitiser Control (1) */
+       0x0002,     /* R145 - Digitiser Control (2) */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x7000,     /* R152 - AUX1 Readback */
+       0x7000,     /* R153 - AUX2 Readback */
+       0x7000,     /* R154 - AUX3 Readback */
+       0x7000,     /* R155 - AUX4 Readback */
+       0x0000,     /* R156 - USB Voltage Readback */
+       0x0000,     /* R157 - LINE Voltage Readback */
+       0x0000,     /* R158 - BATT Voltage Readback */
+       0x0000,     /* R159 - Chip Temp Readback */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 - Generic Comparator Control */
+       0x0000,     /* R164 - Generic comparator 1 */
+       0x0000,     /* R165 - Generic comparator 2 */
+       0x0000,     /* R166 - Generic comparator 3 */
+       0x0000,     /* R167 - Generic comparator 4 */
+       0xA00F,     /* R168 - Battery Charger Control 1 */
+       0x0B06,     /* R169 - Battery Charger Control 2 */
+       0x0000,     /* R170 - Battery Charger Control 3 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 - Current Sink Driver A */
+       0x0000,     /* R173 - CSA Flash control */
+       0x0000,     /* R174 - Current Sink Driver B */
+       0x0000,     /* R175 - CSB Flash control */
+       0x0000,     /* R176 - DCDC/LDO requested */
+       0x032D,     /* R177 - DCDC Active options */
+       0x0000,     /* R178 - DCDC Sleep options */
+       0x0025,     /* R179 - Power-check comparator */
+       0x0006,     /* R180 - DCDC1 Control */
+       0x0400,     /* R181 - DCDC1 Timeouts */
+       0x1006,     /* R182 - DCDC1 Low Power */
+       0x0018,     /* R183 - DCDC2 Control */
+       0x0000,     /* R184 - DCDC2 Timeouts */
+       0x0000,     /* R185 */
+       0x0050,     /* R186 - DCDC3 Control */
+       0x0C00,     /* R187 - DCDC3 Timeouts */
+       0x0006,     /* R188 - DCDC3 Low Power */
+       0x000E,     /* R189 - DCDC4 Control */
+       0x0400,     /* R190 - DCDC4 Timeouts */
+       0x0006,     /* R191 - DCDC4 Low Power */
+       0x0008,     /* R192 - DCDC5 Control */
+       0x0000,     /* R193 - DCDC5 Timeouts */
+       0x0000,     /* R194 */
+       0x0029,     /* R195 - DCDC6 Control */
+       0x0800,     /* R196 - DCDC6 Timeouts */
+       0x0006,     /* R197 - DCDC6 Low Power */
+       0x0000,     /* R198 */
+       0x0003,     /* R199 - Limit Switch Control */
+       0x001D,     /* R200 - LDO1 Control */
+       0x1000,     /* R201 - LDO1 Timeouts */
+       0x001C,     /* R202 - LDO1 Low Power */
+       0x0017,     /* R203 - LDO2 Control */
+       0x1000,     /* R204 - LDO2 Timeouts */
+       0x001C,     /* R205 - LDO2 Low Power */
+       0x0006,     /* R206 - LDO3 Control */
+       0x1000,     /* R207 - LDO3 Timeouts */
+       0x001C,     /* R208 - LDO3 Low Power */
+       0x0010,     /* R209 - LDO4 Control */
+       0x1000,     /* R210 - LDO4 Timeouts */
+       0x001C,     /* R211 - LDO4 Low Power */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 - VCC_FAULT Masks */
+       0x001F,     /* R216 - Main Bandgap Control */
+       0x0000,     /* R217 - OSC Control */
+       0x9000,     /* R218 - RTC Tick Control */
+       0x0000,     /* R219 - Security1 */
+       0x4000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 - Signal overrides */
+       0x0000,     /* R225 - DCDC/LDO status */
+       0x0000,     /* R226 - Charger Overides/status */
+       0x0000,     /* R227 - misc overrides */
+       0x0000,     /* R228 - Supply overrides/status 1 */
+       0x0000,     /* R229 - Supply overrides/status 2 */
+       0xE000,     /* R230 - GPIO Pin Status */
+       0x0000,     /* R231 - comparotor overrides */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 - State Machine status */
+       0x1200,     /* R234 */
+       0x0000,     /* R235 */
+       0x8000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0003,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0004,     /* R243 */
+       0x0300,     /* R244 */
+       0x0000,     /* R245 */
+       0x0200,     /* R246 */
+       0x0000,     /* R247 */
+       0x1000,     /* R248 - DCDC1 Test Controls */
+       0x5000,     /* R249 */
+       0x1000,     /* R250 - DCDC3 Test Controls */
+       0x1000,     /* R251 - DCDC4 Test Controls */
+       0x5100,     /* R252 */
+       0x1000,     /* R253 - DCDC6 Test Controls */
+};
+#endif
+
 /* The register defaults for the config mode used must be compiled in but
  * due to the impact on kernel size it is possible to disable
  */
@@ -1307,14 +3403,14 @@ const struct wm8350_reg_access wm8350_reg_io_map[] = {
        { 0xFF3F, 0xE03F, 0x0000 }, /* R216 - Main Bandgap Control */
        { 0xEF2F, 0xE02F, 0x0000 }, /* R217 - OSC Control */
        { 0xF3FF, 0xB3FF, 0xc000 }, /* R218 - RTC Tick Control */
-       { 0xFFFF, 0xFFFF, 0xFFFF }, /* R219 */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R219 - Security */
        { 0x09FF, 0x01FF, 0x0000 }, /* R220 - RAM BIST 1 */
        { 0x0000, 0x0000, 0x0000 }, /* R221 */
        { 0xFFFF, 0xFFFF, 0xFFFF }, /* R222 */
        { 0xFFFF, 0xFFFF, 0xFFFF }, /* R223 */
        { 0x0000, 0x0000, 0x0000 }, /* R224 */
        { 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */
-       { 0x0000, 0x0000, 0x0000 }, /* R226 */
+       { 0x0000, 0x0000, 0xFFFF }, /* R226 - Charger status */
        { 0x0000, 0x0000, 0xFFFF }, /* R227 */
        { 0x0000, 0x0000, 0x0000 }, /* R228 */
        { 0x0000, 0x0000, 0x0000 }, /* R229 */
index 6a0cedb..cf30d06 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/bug.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/wm8400-private.h>
 #include <linux/mfd/wm8400-audio.h>
 
@@ -239,6 +240,16 @@ void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
 }
 EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
 
+static int wm8400_register_codec(struct wm8400 *wm8400)
+{
+       struct mfd_cell cell = {
+               .name = "wm8400-codec",
+               .driver_data = wm8400,
+       };
+
+       return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
+}
+
 /*
  * wm8400_init - Generic initialisation
  *
@@ -296,24 +307,32 @@ static int wm8400_init(struct wm8400 *wm8400,
        reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
        dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
 
+       ret = wm8400_register_codec(wm8400);
+       if (ret != 0) {
+               dev_err(wm8400->dev, "Failed to register codec\n");
+               goto err_children;
+       }
+
        if (pdata && pdata->platform_init) {
                ret = pdata->platform_init(wm8400->dev);
-               if (ret != 0)
+               if (ret != 0) {
                        dev_err(wm8400->dev, "Platform init failed: %d\n",
                                ret);
+                       goto err_children;
+               }
        } else
                dev_warn(wm8400->dev, "No platform initialisation supplied\n");
 
+       return 0;
+
+err_children:
+       mfd_remove_devices(wm8400->dev);
        return ret;
 }
 
 static void wm8400_release(struct wm8400 *wm8400)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8400->regulators); i++)
-               if (wm8400->regulators[i].name)
-                       platform_device_unregister(&wm8400->regulators[i]);
+       mfd_remove_devices(wm8400->dev);
 }
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
index 8e0c2b4..6684724 100644 (file)
@@ -29,6 +29,13 @@ config APM_POWER
          Say Y here to enable support APM status emulation using
          battery class devices.
 
+config WM8350_POWER
+        tristate "WM8350 PMU support"
+        depends on MFD_WM8350
+        help
+          Say Y here to enable support for the power management unit
+         provided by the Wolfson Microelectronics WM8350 PMIC.
+
 config BATTERY_DS2760
        tristate "DS2760 battery driver (HP iPAQ & others)"
        select W1
@@ -68,4 +75,11 @@ config BATTERY_BQ27x00
        help
          Say Y here to enable support for batteries with BQ27200(I2C) chip.
 
+config BATTERY_DA9030
+       tristate "DA9030 battery driver"
+       depends on PMIC_DA903X
+       help
+         Say Y here to enable support for batteries charger integrated into
+         DA9030 PMIC.
+
 endif # POWER_SUPPLY
index e8f1ece..eebb155 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_SUPPLY)    += power_supply.o
 
 obj-$(CONFIG_PDA_POWER)                += pda_power.o
 obj-$(CONFIG_APM_POWER)                += apm_power.o
+obj-$(CONFIG_WM8350_POWER)     += wm8350_power.o
 
 obj-$(CONFIG_BATTERY_DS2760)   += ds2760_battery.o
 obj-$(CONFIG_BATTERY_PMU)      += pmu_battery.o
@@ -23,3 +24,4 @@ obj-$(CONFIG_BATTERY_OLPC)    += olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)     += tosa_battery.o
 obj-$(CONFIG_BATTERY_WM97XX)   += wm97xx_battery.o
 obj-$(CONFIG_BATTERY_BQ27x00)  += bq27x00_battery.o
+obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c
new file mode 100644 (file)
index 0000000..1662bb0
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * Battery charger driver for Dialog Semiconductor DA9030
+ *
+ * Copyright (C) 2008 Compulab, Ltd.
+ *     Mike Rapoport <mike@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/da903x.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#define DA9030_STATUS_CHDET    (1 << 3)
+
+#define DA9030_FAULT_LOG               0x0a
+#define DA9030_FAULT_LOG_OVER_TEMP     (1 << 7)
+#define DA9030_FAULT_LOG_VBAT_OVER     (1 << 4)
+
+#define DA9030_CHARGE_CONTROL          0x28
+#define DA9030_CHRG_CHARGER_ENABLE     (1 << 7)
+
+#define DA9030_ADC_MAN_CONTROL         0x30
+#define DA9030_ADC_TBATREF_ENABLE      (1 << 5)
+#define DA9030_ADC_LDO_INT_ENABLE      (1 << 4)
+
+#define DA9030_ADC_AUTO_CONTROL                0x31
+#define DA9030_ADC_TBAT_ENABLE         (1 << 5)
+#define DA9030_ADC_VBAT_IN_TXON                (1 << 4)
+#define DA9030_ADC_VCH_ENABLE          (1 << 3)
+#define DA9030_ADC_ICH_ENABLE          (1 << 2)
+#define DA9030_ADC_VBAT_ENABLE         (1 << 1)
+#define DA9030_ADC_AUTO_SLEEP_ENABLE   (1 << 0)
+
+#define DA9030_VBATMON         0x32
+#define DA9030_VBATMONTXON     0x33
+#define DA9030_TBATHIGHP       0x34
+#define DA9030_TBATHIGHN       0x35
+#define DA9030_TBATLOW         0x36
+
+#define DA9030_VBAT_RES                0x41
+#define DA9030_VBATMIN_RES     0x42
+#define DA9030_VBATMINTXON_RES 0x43
+#define DA9030_ICHMAX_RES      0x44
+#define DA9030_ICHMIN_RES      0x45
+#define DA9030_ICHAVERAGE_RES  0x46
+#define DA9030_VCHMAX_RES      0x47
+#define DA9030_VCHMIN_RES      0x48
+#define DA9030_TBAT_RES                0x49
+
+struct da9030_adc_res {
+       uint8_t vbat_res;
+       uint8_t vbatmin_res;
+       uint8_t vbatmintxon;
+       uint8_t ichmax_res;
+       uint8_t ichmin_res;
+       uint8_t ichaverage_res;
+       uint8_t vchmax_res;
+       uint8_t vchmin_res;
+       uint8_t tbat_res;
+       uint8_t adc_in4_res;
+       uint8_t adc_in5_res;
+};
+
+struct da9030_battery_thresholds {
+       int tbat_low;
+       int tbat_high;
+       int tbat_restart;
+
+       int vbat_low;
+       int vbat_crit;
+       int vbat_charge_start;
+       int vbat_charge_stop;
+       int vbat_charge_restart;
+
+       int vcharge_min;
+       int vcharge_max;
+};
+
+struct da9030_charger {
+       struct power_supply psy;
+
+       struct device *master;
+
+       struct da9030_adc_res adc;
+       struct delayed_work work;
+       unsigned int interval;
+
+       struct power_supply_info *battery_info;
+
+       struct da9030_battery_thresholds thresholds;
+
+       unsigned int charge_milliamp;
+       unsigned int charge_millivolt;
+
+       /* charger status */
+       bool chdet;
+       uint8_t fault;
+       int mA;
+       int mV;
+       bool is_on;
+
+       struct notifier_block nb;
+
+       /* platform callbacks for battery low and critical events */
+       void (*battery_low)(void);
+       void (*battery_critical)(void);
+
+       struct dentry *debug_file;
+};
+
+static inline int da9030_reg_to_mV(int reg)
+{
+       return ((reg * 2650) >> 8) + 2650;
+}
+
+static inline int da9030_millivolt_to_reg(int mV)
+{
+       return ((mV - 2650) << 8) / 2650;
+}
+
+static inline int da9030_reg_to_mA(int reg)
+{
+       return ((reg * 24000) >> 8) / 15;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int bat_debug_show(struct seq_file *s, void *data)
+{
+       struct da9030_charger *charger = s->private;
+
+       seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off");
+       if (charger->chdet) {
+               seq_printf(s, "iset = %dmA, vset = %dmV\n",
+                          charger->mA, charger->mV);
+       }
+
+       seq_printf(s, "vbat_res = %d (%dmV)\n",
+                  charger->adc.vbat_res,
+                  da9030_reg_to_mV(charger->adc.vbat_res));
+       seq_printf(s, "vbatmin_res = %d (%dmV)\n",
+                  charger->adc.vbatmin_res,
+                  da9030_reg_to_mV(charger->adc.vbatmin_res));
+       seq_printf(s, "vbatmintxon = %d (%dmV)\n",
+                  charger->adc.vbatmintxon,
+                  da9030_reg_to_mV(charger->adc.vbatmintxon));
+       seq_printf(s, "ichmax_res = %d (%dmA)\n",
+                  charger->adc.ichmax_res,
+                  da9030_reg_to_mV(charger->adc.ichmax_res));
+       seq_printf(s, "ichmin_res = %d (%dmA)\n",
+                  charger->adc.ichmin_res,
+                  da9030_reg_to_mA(charger->adc.ichmin_res));
+       seq_printf(s, "ichaverage_res = %d (%dmA)\n",
+                  charger->adc.ichaverage_res,
+                  da9030_reg_to_mA(charger->adc.ichaverage_res));
+       seq_printf(s, "vchmax_res = %d (%dmV)\n",
+                  charger->adc.vchmax_res,
+                  da9030_reg_to_mA(charger->adc.vchmax_res));
+       seq_printf(s, "vchmin_res = %d (%dmV)\n",
+                  charger->adc.vchmin_res,
+                  da9030_reg_to_mV(charger->adc.vchmin_res));
+
+       return 0;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, bat_debug_show, inode->i_private);
+}
+
+static const struct file_operations bat_debug_fops = {
+       .open           = debug_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
+{
+       charger->debug_file = debugfs_create_file("charger", 0666, 0, charger,
+                                                &bat_debug_fops);
+       return charger->debug_file;
+}
+
+static void da9030_bat_remove_debugfs(struct da9030_charger *charger)
+{
+       debugfs_remove(charger->debug_file);
+}
+#else
+static inline struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
+{
+       return NULL;
+}
+static inline void da9030_bat_remove_debugfs(struct da9030_charger *charger)
+{
+}
+#endif
+
+static inline void da9030_read_adc(struct da9030_charger *charger,
+                                  struct da9030_adc_res *adc)
+{
+       da903x_reads(charger->master, DA9030_VBAT_RES,
+                    sizeof(*adc), (uint8_t *)adc);
+}
+
+static void da9030_charger_update_state(struct da9030_charger *charger)
+{
+       uint8_t val;
+
+       da903x_read(charger->master, DA9030_CHARGE_CONTROL, &val);
+       charger->is_on = (val & DA9030_CHRG_CHARGER_ENABLE) ? 1 : 0;
+       charger->mA = ((val >> 3) & 0xf) * 100;
+       charger->mV = (val & 0x7) * 50 + 4000;
+
+       da9030_read_adc(charger, &charger->adc);
+       da903x_read(charger->master, DA9030_FAULT_LOG, &charger->fault);
+       charger->chdet = da903x_query_status(charger->master,
+                                                    DA9030_STATUS_CHDET);
+}
+
+static void da9030_set_charge(struct da9030_charger *charger, int on)
+{
+       uint8_t val;
+
+       if (on) {
+               val = DA9030_CHRG_CHARGER_ENABLE;
+               val |= (charger->charge_milliamp / 100) << 3;
+               val |= (charger->charge_millivolt - 4000) / 50;
+               charger->is_on = 1;
+       } else {
+               val = 0;
+               charger->is_on = 0;
+       }
+
+       da903x_write(charger->master, DA9030_CHARGE_CONTROL, val);
+}
+
+static void da9030_charger_check_state(struct da9030_charger *charger)
+{
+       da9030_charger_update_state(charger);
+
+       /* we wake or boot with external power on */
+       if (!charger->is_on) {
+               if ((charger->chdet) &&
+                   (charger->adc.vbat_res <
+                    charger->thresholds.vbat_charge_start)) {
+                       da9030_set_charge(charger, 1);
+               }
+       } else {
+               if (charger->adc.vbat_res >=
+                   charger->thresholds.vbat_charge_stop) {
+                       da9030_set_charge(charger, 0);
+                       da903x_write(charger->master, DA9030_VBATMON,
+                                      charger->thresholds.vbat_charge_restart);
+               } else if (charger->adc.vbat_res >
+                          charger->thresholds.vbat_low) {
+                       /* we are charging and passed LOW_THRESH,
+                          so upate DA9030 VBAT threshold
+                        */
+                       da903x_write(charger->master, DA9030_VBATMON,
+                                    charger->thresholds.vbat_low);
+               }
+               if (charger->adc.vchmax_res > charger->thresholds.vcharge_max ||
+                   charger->adc.vchmin_res < charger->thresholds.vcharge_min ||
+                   /* Tempreture readings are negative */
+                   charger->adc.tbat_res < charger->thresholds.tbat_high ||
+                   charger->adc.tbat_res > charger->thresholds.tbat_low) {
+                       /* disable charger */
+                       da9030_set_charge(charger, 0);
+               }
+       }
+}
+
+static void da9030_charging_monitor(struct work_struct *work)
+{
+       struct da9030_charger *charger;
+
+       charger = container_of(work, struct da9030_charger, work.work);
+
+       da9030_charger_check_state(charger);
+
+       /* reschedule for the next time */
+       schedule_delayed_work(&charger->work, charger->interval);
+}
+
+static enum power_supply_property da9030_battery_props[] = {
+       POWER_SUPPLY_PROP_MODEL_NAME,
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_AVG,
+};
+
+static void da9030_battery_check_status(struct da9030_charger *charger,
+                                   union power_supply_propval *val)
+{
+       if (charger->chdet) {
+               if (charger->is_on)
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       } else {
+               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+}
+
+static void da9030_battery_check_health(struct da9030_charger *charger,
+                                   union power_supply_propval *val)
+{
+       if (charger->fault & DA9030_FAULT_LOG_OVER_TEMP)
+               val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+       else if (charger->fault & DA9030_FAULT_LOG_VBAT_OVER)
+               val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+       else
+               val->intval = POWER_SUPPLY_HEALTH_GOOD;
+}
+
+static int da9030_battery_get_property(struct power_supply *psy,
+                                  enum power_supply_property psp,
+                                  union power_supply_propval *val)
+{
+       struct da9030_charger *charger;
+       charger = container_of(psy, struct da9030_charger, psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               da9030_battery_check_status(charger, val);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               da9030_battery_check_health(charger, val);
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = charger->battery_info->technology;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               val->intval = charger->battery_info->voltage_max_design;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = charger->battery_info->voltage_min_design;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = da9030_reg_to_mV(charger->adc.vbat_res) * 1000;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               val->intval =
+                       da9030_reg_to_mA(charger->adc.ichaverage_res) * 1000;
+               break;
+       case POWER_SUPPLY_PROP_MODEL_NAME:
+               val->strval = charger->battery_info->name;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void da9030_battery_vbat_event(struct da9030_charger *charger)
+{
+       da9030_read_adc(charger, &charger->adc);
+
+       if (charger->is_on)
+               return;
+
+       if (charger->adc.vbat_res < charger->thresholds.vbat_low) {
+               /* set VBAT threshold for critical */
+               da903x_write(charger->master, DA9030_VBATMON,
+                            charger->thresholds.vbat_crit);
+               if (charger->battery_low)
+                       charger->battery_low();
+       } else if (charger->adc.vbat_res <
+                  charger->thresholds.vbat_crit) {
+               /* notify the system of battery critical */
+               if (charger->battery_critical)
+                       charger->battery_critical();
+       }
+}
+
+static int da9030_battery_event(struct notifier_block *nb, unsigned long event,
+                               void *data)
+{
+       struct da9030_charger *charger =
+               container_of(nb, struct da9030_charger, nb);
+       int status;
+
+       switch (event) {
+       case DA9030_EVENT_CHDET:
+               status = da903x_query_status(charger->master,
+                                            DA9030_STATUS_CHDET);
+               da9030_set_charge(charger, status);
+               break;
+       case DA9030_EVENT_VBATMON:
+               da9030_battery_vbat_event(charger);
+               break;
+       case DA9030_EVENT_CHIOVER:
+       case DA9030_EVENT_TBAT:
+               da9030_set_charge(charger, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static void da9030_battery_convert_thresholds(struct da9030_charger *charger,
+                                             struct da9030_battery_info *pdata)
+{
+       charger->thresholds.tbat_low = pdata->tbat_low;
+       charger->thresholds.tbat_high = pdata->tbat_high;
+       charger->thresholds.tbat_restart  = pdata->tbat_restart;
+
+       charger->thresholds.vbat_low =
+               da9030_millivolt_to_reg(pdata->vbat_low);
+       charger->thresholds.vbat_crit =
+               da9030_millivolt_to_reg(pdata->vbat_crit);
+       charger->thresholds.vbat_charge_start =
+               da9030_millivolt_to_reg(pdata->vbat_charge_start);
+       charger->thresholds.vbat_charge_stop =
+               da9030_millivolt_to_reg(pdata->vbat_charge_stop);
+       charger->thresholds.vbat_charge_restart =
+               da9030_millivolt_to_reg(pdata->vbat_charge_restart);
+
+       charger->thresholds.vcharge_min =
+               da9030_millivolt_to_reg(pdata->vcharge_min);
+       charger->thresholds.vcharge_max =
+               da9030_millivolt_to_reg(pdata->vcharge_max);
+}
+
+static void da9030_battery_setup_psy(struct da9030_charger *charger)
+{
+       struct power_supply *psy = &charger->psy;
+       struct power_supply_info *info = charger->battery_info;
+
+       psy->name = info->name;
+       psy->use_for_apm = info->use_for_apm;
+       psy->type = POWER_SUPPLY_TYPE_BATTERY;
+       psy->get_property = da9030_battery_get_property;
+
+       psy->properties = da9030_battery_props;
+       psy->num_properties = ARRAY_SIZE(da9030_battery_props);
+};
+
+static int da9030_battery_charger_init(struct da9030_charger *charger)
+{
+       char v[5];
+       int ret;
+
+       v[0] = v[1] = charger->thresholds.vbat_low;
+       v[2] = charger->thresholds.tbat_high;
+       v[3] = charger->thresholds.tbat_restart;
+       v[4] = charger->thresholds.tbat_low;
+
+       ret = da903x_writes(charger->master, DA9030_VBATMON, 5, v);
+       if (ret)
+               return ret;
+
+       /*
+        * Enable reference voltage supply for ADC from the LDO_INTERNAL
+        * regulator. Must be set before ADC measurements can be made.
+        */
+       ret = da903x_write(charger->master, DA9030_ADC_MAN_CONTROL,
+                          DA9030_ADC_LDO_INT_ENABLE |
+                          DA9030_ADC_TBATREF_ENABLE);
+       if (ret)
+               return ret;
+
+       /* enable auto ADC measuremnts */
+       return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL,
+                           DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON |
+                           DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE |
+                           DA9030_ADC_VBAT_ENABLE |
+                           DA9030_ADC_AUTO_SLEEP_ENABLE);
+}
+
+static int da9030_battery_probe(struct platform_device *pdev)
+{
+       struct da9030_charger *charger;
+       struct da9030_battery_info *pdata = pdev->dev.platform_data;
+       int ret;
+
+       if (pdata == NULL)
+               return -EINVAL;
+
+       if (pdata->charge_milliamp >= 1500 ||
+           pdata->charge_millivolt < 4000 ||
+           pdata->charge_millivolt > 4350)
+               return -EINVAL;
+
+       charger = kzalloc(sizeof(*charger), GFP_KERNEL);
+       if (charger == NULL)
+               return -ENOMEM;
+
+       charger->master = pdev->dev.parent;
+
+       /* 10 seconds between monotor runs unless platfrom defines other
+          interval */
+       charger->interval = msecs_to_jiffies(
+               (pdata->batmon_interval ? : 10) * 1000);
+
+       charger->charge_milliamp = pdata->charge_milliamp;
+       charger->charge_millivolt = pdata->charge_millivolt;
+       charger->battery_info = pdata->battery_info;
+       charger->battery_low = pdata->battery_low;
+       charger->battery_critical = pdata->battery_critical;
+
+       da9030_battery_convert_thresholds(charger, pdata);
+
+       ret = da9030_battery_charger_init(charger);
+       if (ret)
+               goto err_charger_init;
+
+       INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor);
+       schedule_delayed_work(&charger->work, charger->interval);
+
+       charger->nb.notifier_call = da9030_battery_event;
+       ret = da903x_register_notifier(charger->master, &charger->nb,
+                                      DA9030_EVENT_CHDET |
+                                      DA9030_EVENT_VBATMON |
+                                      DA9030_EVENT_CHIOVER |
+                                      DA9030_EVENT_TBAT);
+       if (ret)
+               goto err_notifier;
+
+       da9030_battery_setup_psy(charger);
+       ret = power_supply_register(&pdev->dev, &charger->psy);
+       if (ret)
+               goto err_ps_register;
+
+       charger->debug_file = da9030_bat_create_debugfs(charger);
+       platform_set_drvdata(pdev, charger);
+       return 0;
+
+err_ps_register:
+       da903x_unregister_notifier(charger->master, &charger->nb,
+                                  DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
+                                  DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
+err_notifier:
+       cancel_delayed_work(&charger->work);
+
+err_charger_init:
+       kfree(charger);
+
+       return ret;
+}
+
+static int da9030_battery_remove(struct platform_device *dev)
+{
+       struct da9030_charger *charger = platform_get_drvdata(dev);
+
+       da9030_bat_remove_debugfs(charger);
+
+       da903x_unregister_notifier(charger->master, &charger->nb,
+                                  DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
+                                  DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
+       cancel_delayed_work(&charger->work);
+       power_supply_unregister(&charger->psy);
+
+       kfree(charger);
+
+       return 0;
+}
+
+static struct platform_driver da903x_battery_driver = {
+       .driver = {
+               .name   = "da903x-battery",
+               .owner  = THIS_MODULE,
+       },
+       .probe = da9030_battery_probe,
+       .remove = da9030_battery_remove,
+};
+
+static int da903x_battery_init(void)
+{
+       return platform_driver_register(&da903x_battery_driver);
+}
+
+static void da903x_battery_exit(void)
+{
+       platform_driver_unregister(&da903x_battery_driver);
+}
+
+module_init(da903x_battery_init);
+module_exit(da903x_battery_exit);
+
+MODULE_DESCRIPTION("DA9030 battery charger driver");
+MODULE_AUTHOR("Mike Rapoport, CompuLab");
+MODULE_LICENSE("GPL");
index 23ae846..ac01e06 100644 (file)
@@ -45,7 +45,7 @@ static ssize_t power_supply_show_property(struct device *dev,
        };
        static char *health_text[] = {
                "Unknown", "Good", "Overheat", "Dead", "Over voltage",
-               "Unspecified failure"
+               "Unspecified failure", "Cold",
        };
        static char *technology_text[] = {
                "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c
new file mode 100644 (file)
index 0000000..1b16bf3
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Battery driver for wm8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Based on OLPC Battery Driver
+ *
+ * Copyright 2006  David Woodhouse <dwmw2@infradead.org>
+ *
+ * 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/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/comparator.h>
+
+static int wm8350_read_battery_uvolts(struct wm8350 *wm8350)
+{
+       return wm8350_read_auxadc(wm8350, WM8350_AUXADC_BATT, 0, 0)
+               * WM8350_AUX_COEFF;
+}
+
+static int wm8350_read_line_uvolts(struct wm8350 *wm8350)
+{
+       return wm8350_read_auxadc(wm8350, WM8350_AUXADC_LINE, 0, 0)
+               * WM8350_AUX_COEFF;
+}
+
+static int wm8350_read_usb_uvolts(struct wm8350 *wm8350)
+{
+       return wm8350_read_auxadc(wm8350, WM8350_AUXADC_USB, 0, 0)
+               * WM8350_AUX_COEFF;
+}
+
+#define WM8350_BATT_SUPPLY     1
+#define WM8350_USB_SUPPLY      2
+#define WM8350_LINE_SUPPLY     4
+
+static inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min)
+{
+       if (!wm8350->power.rev_g_coeff)
+               return (((min - 30) / 15) & 0xf) << 8;
+       else
+               return (((min - 30) / 30) & 0xf) << 8;
+}
+
+static int wm8350_get_supplies(struct wm8350 *wm8350)
+{
+       u16 sm, ov, co, chrg;
+       int supplies = 0;
+
+       sm = wm8350_reg_read(wm8350, WM8350_STATE_MACHINE_STATUS);
+       ov = wm8350_reg_read(wm8350, WM8350_MISC_OVERRIDES);
+       co = wm8350_reg_read(wm8350, WM8350_COMPARATOR_OVERRIDES);
+       chrg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
+
+       /* USB_SM */
+       sm = (sm & WM8350_USB_SM_MASK) >> WM8350_USB_SM_SHIFT;
+
+       /* CHG_ISEL */
+       chrg &= WM8350_CHG_ISEL_MASK;
+
+       /* If the USB state machine is active then we're using that with or
+        * without battery, otherwise check for wall supply */
+       if (((sm == WM8350_USB_SM_100_SLV) ||
+            (sm == WM8350_USB_SM_500_SLV) ||
+            (sm == WM8350_USB_SM_STDBY_SLV))
+           && !(ov & WM8350_USB_LIMIT_OVRDE))
+               supplies = WM8350_USB_SUPPLY;
+       else if (((sm == WM8350_USB_SM_100_SLV) ||
+                 (sm == WM8350_USB_SM_500_SLV) ||
+                 (sm == WM8350_USB_SM_STDBY_SLV))
+                && (ov & WM8350_USB_LIMIT_OVRDE) && (chrg == 0))
+               supplies = WM8350_USB_SUPPLY | WM8350_BATT_SUPPLY;
+       else if (co & WM8350_WALL_FB_OVRDE)
+               supplies = WM8350_LINE_SUPPLY;
+       else
+               supplies = WM8350_BATT_SUPPLY;
+
+       return supplies;
+}
+
+static int wm8350_charger_config(struct wm8350 *wm8350,
+                                struct wm8350_charger_policy *policy)
+{
+       u16 reg, eoc_mA, fast_limit_mA;
+
+       if (!policy) {
+               dev_warn(wm8350->dev,
+                        "No charger policy, charger not configured.\n");
+               return -EINVAL;
+       }
+
+       /* make sure USB fast charge current is not > 500mA */
+       if (policy->fast_limit_USB_mA > 500) {
+               dev_err(wm8350->dev, "USB fast charge > 500mA\n");
+               return -EINVAL;
+       }
+
+       eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA);
+
+       wm8350_reg_unlock(wm8350);
+
+       reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1)
+               & WM8350_CHG_ENA_R168;
+       wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
+                        reg | eoc_mA | policy->trickle_start_mV |
+                        WM8350_CHG_TRICKLE_TEMP_CHOKE |
+                        WM8350_CHG_TRICKLE_USB_CHOKE |
+                        WM8350_CHG_FAST_USB_THROTTLE);
+
+       if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) {
+               fast_limit_mA =
+                       WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA);
+               wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
+                           policy->charge_mV | policy->trickle_charge_USB_mA |
+                           fast_limit_mA | wm8350_charge_time_min(wm8350,
+                                               policy->charge_timeout));
+
+       } else {
+               fast_limit_mA =
+                       WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA);
+               wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
+                           policy->charge_mV | policy->trickle_charge_mA |
+                           fast_limit_mA | wm8350_charge_time_min(wm8350,
+                                               policy->charge_timeout));
+       }
+
+       wm8350_reg_lock(wm8350);
+       return 0;
+}
+
+static int wm8350_batt_status(struct wm8350 *wm8350)
+{
+       u16 state;
+
+       state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
+       state &= WM8350_CHG_STS_MASK;
+
+       switch (state) {
+       case WM8350_CHG_STS_OFF:
+               return POWER_SUPPLY_STATUS_DISCHARGING;
+
+       case WM8350_CHG_STS_TRICKLE:
+       case WM8350_CHG_STS_FAST:
+               return POWER_SUPPLY_STATUS_CHARGING;
+
+       default:
+               return POWER_SUPPLY_STATUS_UNKNOWN;
+       }
+}
+
+static ssize_t charger_state_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+       char *charge;
+       int state;
+
+       state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
+           WM8350_CHG_STS_MASK;
+       switch (state) {
+       case WM8350_CHG_STS_OFF:
+               charge = "Charger Off";
+               break;
+       case WM8350_CHG_STS_TRICKLE:
+               charge = "Trickle Charging";
+               break;
+       case WM8350_CHG_STS_FAST:
+               charge = "Fast Charging";
+               break;
+       default:
+               return 0;
+       }
+
+       return sprintf(buf, "%s\n", charge);
+}
+
+static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL);
+
+static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+       struct wm8350_power *power = &wm8350->power;
+       struct wm8350_charger_policy *policy = power->policy;
+
+       switch (irq) {
+       case WM8350_IRQ_CHG_BAT_FAIL:
+               dev_err(wm8350->dev, "battery failed\n");
+               break;
+       case WM8350_IRQ_CHG_TO:
+               dev_err(wm8350->dev, "charger timeout\n");
+               power_supply_changed(&power->battery);
+               break;
+
+       case WM8350_IRQ_CHG_BAT_HOT:
+       case WM8350_IRQ_CHG_BAT_COLD:
+       case WM8350_IRQ_CHG_START:
+       case WM8350_IRQ_CHG_END:
+               power_supply_changed(&power->battery);
+               break;
+
+       case WM8350_IRQ_CHG_FAST_RDY:
+               dev_dbg(wm8350->dev, "fast charger ready\n");
+               wm8350_charger_config(wm8350, policy);
+               wm8350_reg_unlock(wm8350);
+               wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
+                               WM8350_CHG_FAST);
+               wm8350_reg_lock(wm8350);
+               break;
+
+       case WM8350_IRQ_CHG_VBATT_LT_3P9:
+               dev_warn(wm8350->dev, "battery < 3.9V\n");
+               break;
+       case WM8350_IRQ_CHG_VBATT_LT_3P1:
+               dev_warn(wm8350->dev, "battery < 3.1V\n");
+               break;
+       case WM8350_IRQ_CHG_VBATT_LT_2P85:
+               dev_warn(wm8350->dev, "battery < 2.85V\n");
+               break;
+
+               /* Supply change.  We will overnotify but it should do
+                * no harm. */
+       case WM8350_IRQ_EXT_USB_FB:
+       case WM8350_IRQ_EXT_WALL_FB:
+               wm8350_charger_config(wm8350, policy);
+       case WM8350_IRQ_EXT_BAT_FB:   /* Fall through */
+               power_supply_changed(&power->battery);
+               power_supply_changed(&power->usb);
+               power_supply_changed(&power->ac);
+               break;
+
+       default:
+               dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
+       }
+}
+
+/*********************************************************************
+ *             AC Power
+ *********************************************************************/
+static int wm8350_ac_get_prop(struct power_supply *psy,
+                             enum power_supply_property psp,
+                             union power_supply_propval *val)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = !!(wm8350_get_supplies(wm8350) &
+                                WM8350_LINE_SUPPLY);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = wm8350_read_line_uvolts(wm8350);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static enum power_supply_property wm8350_ac_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+/*********************************************************************
+ *             USB Power
+ *********************************************************************/
+static int wm8350_usb_get_prop(struct power_supply *psy,
+                              enum power_supply_property psp,
+                              union power_supply_propval *val)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = !!(wm8350_get_supplies(wm8350) &
+                                WM8350_USB_SUPPLY);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = wm8350_read_usb_uvolts(wm8350);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static enum power_supply_property wm8350_usb_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+/*********************************************************************
+ *             Battery properties
+ *********************************************************************/
+
+static int wm8350_bat_check_health(struct wm8350 *wm8350)
+{
+       u16 reg;
+
+       if (wm8350_read_battery_uvolts(wm8350) < 2850000)
+               return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+
+       reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES);
+       if (reg & WM8350_CHG_BATT_HOT_OVRDE)
+               return POWER_SUPPLY_HEALTH_OVERHEAT;
+
+       if (reg & WM8350_CHG_BATT_COLD_OVRDE)
+               return POWER_SUPPLY_HEALTH_COLD;
+
+       return POWER_SUPPLY_HEALTH_GOOD;
+}
+
+static int wm8350_bat_get_property(struct power_supply *psy,
+                                  enum power_supply_property psp,
+                                  union power_supply_propval *val)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = wm8350_batt_status(wm8350);
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = !!(wm8350_get_supplies(wm8350) &
+                                WM8350_BATT_SUPPLY);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = wm8350_read_battery_uvolts(wm8350);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               val->intval = wm8350_bat_check_health(wm8350);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static enum power_supply_property wm8350_bat_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_HEALTH,
+};
+
+/*********************************************************************
+ *             Initialisation
+ *********************************************************************/
+
+static void wm8350_init_charger(struct wm8350 *wm8350)
+{
+       /* register our interest in charger events */
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_TO);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_END);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_START);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
+       wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
+
+       /* and supply change events */
+       wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
+       wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
+       wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB,
+                           wm8350_charger_handler, NULL);
+       wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+}
+
+static void free_charger_irq(struct wm8350 *wm8350)
+{
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_TO);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_END);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_START);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
+       wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
+       wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
+       wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
+       wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+       wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+}
+
+static __devinit int wm8350_power_probe(struct platform_device *pdev)
+{
+       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+       struct wm8350_power *power = &wm8350->power;
+       struct wm8350_charger_policy *policy = power->policy;
+       struct power_supply *usb = &power->usb;
+       struct power_supply *battery = &power->battery;
+       struct power_supply *ac = &power->ac;
+       int ret;
+
+       ac->name = "wm8350-ac";
+       ac->type = POWER_SUPPLY_TYPE_MAINS;
+       ac->properties = wm8350_ac_props;
+       ac->num_properties = ARRAY_SIZE(wm8350_ac_props);
+       ac->get_property = wm8350_ac_get_prop;
+       ret = power_supply_register(&pdev->dev, ac);
+       if (ret)
+               return ret;
+
+       battery->name = "wm8350-battery";
+       battery->properties = wm8350_bat_props;
+       battery->num_properties = ARRAY_SIZE(wm8350_bat_props);
+       battery->get_property = wm8350_bat_get_property;
+       battery->use_for_apm = 1;
+       ret = power_supply_register(&pdev->dev, battery);
+       if (ret)
+               goto battery_failed;
+
+       usb->name = "wm8350-usb",
+       usb->type = POWER_SUPPLY_TYPE_USB;
+       usb->properties = wm8350_usb_props;
+       usb->num_properties = ARRAY_SIZE(wm8350_usb_props);
+       usb->get_property = wm8350_usb_get_prop;
+       ret = power_supply_register(&pdev->dev, usb);
+       if (ret)
+               goto usb_failed;
+
+       ret = device_create_file(&pdev->dev, &dev_attr_charger_state);
+       if (ret < 0)
+               dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret);
+       ret = 0;
+
+       wm8350_init_charger(wm8350);
+       if (wm8350_charger_config(wm8350, policy) == 0) {
+               wm8350_reg_unlock(wm8350);
+               wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA);
+               wm8350_reg_lock(wm8350);
+       }
+
+       return ret;
+
+usb_failed:
+       power_supply_unregister(battery);
+battery_failed:
+       power_supply_unregister(ac);
+
+       return ret;
+}
+
+static __devexit int wm8350_power_remove(struct platform_device *pdev)
+{
+       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+       struct wm8350_power *power = &wm8350->power;
+
+       free_charger_irq(wm8350);
+       device_remove_file(&pdev->dev, &dev_attr_charger_state);
+       power_supply_unregister(&power->battery);
+       power_supply_unregister(&power->ac);
+       power_supply_unregister(&power->usb);
+       return 0;
+}
+
+static struct platform_driver wm8350_power_driver = {
+       .probe = wm8350_power_probe,
+       .remove = __devexit_p(wm8350_power_remove),
+       .driver = {
+               .name = "wm8350-power",
+       },
+};
+
+static int __init wm8350_power_init(void)
+{
+       return platform_driver_register(&wm8350_power_driver);
+}
+module_init(wm8350_power_init);
+
+static void __exit wm8350_power_exit(void)
+{
+       platform_driver_unregister(&wm8350_power_driver);
+}
+module_exit(wm8350_power_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Power supply driver for WM8350");
+MODULE_ALIAS("platform:wm8350-power");
index 1f44b17..c68c496 100644 (file)
@@ -1380,6 +1380,13 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
        if (wm8350->pmic.pdev[reg])
                return -EBUSY;
 
+       if (reg >= WM8350_DCDC_1 && reg <= WM8350_DCDC_6 &&
+           reg > wm8350->pmic.max_dcdc)
+               return -ENODEV;
+       if (reg >= WM8350_ISINK_A && reg <= WM8350_ISINK_B &&
+           reg > wm8350->pmic.max_isink)
+               return -ENODEV;
+
        pdev = platform_device_alloc("wm8350-regulator", reg);
        if (!pdev)
                return -ENOMEM;
diff --git a/include/linux/i2c/dm355evm_msp.h b/include/linux/i2c/dm355evm_msp.h
new file mode 100644 (file)
index 0000000..3724703
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * dm355evm_msp.h - support MSP430 microcontroller on DM355EVM board
+ */
+#ifndef __LINUX_I2C_DM355EVM_MSP
+#define __LINUX_I2C_DM355EVM_MSP
+
+/*
+ * Written against Spectrum's writeup for the A4 firmware revision,
+ * and tweaked to match source and rev D2 schematics by removing CPLD
+ * and NOR flash hooks (which were last appropriate in rev B boards).
+ *
+ * Note that the firmware supports a flavor of write posting ... to be
+ * sure a write completes, issue another read or write.
+ */
+
+/* utilities to access "registers" emulated by msp430 firmware */
+extern int dm355evm_msp_write(u8 value, u8 reg);
+extern int dm355evm_msp_read(u8 reg);
+
+
+/* command/control registers */
+#define DM355EVM_MSP_COMMAND           0x00
+#      define MSP_COMMAND_NULL         0
+#      define MSP_COMMAND_RESET_COLD   1
+#      define MSP_COMMAND_RESET_WARM   2
+#      define MSP_COMMAND_RESET_WARM_I 3
+#      define MSP_COMMAND_POWEROFF     4
+#      define MSP_COMMAND_IR_REINIT    5
+#define DM355EVM_MSP_STATUS            0x01
+#      define MSP_STATUS_BAD_OFFSET    BIT(0)
+#      define MSP_STATUS_BAD_COMMAND   BIT(1)
+#      define MSP_STATUS_POWER_ERROR   BIT(2)
+#      define MSP_STATUS_RXBUF_OVERRUN BIT(3)
+#define DM355EVM_MSP_RESET             0x02    /* 0 bits == in reset */
+#      define MSP_RESET_DC5            BIT(0)
+#      define MSP_RESET_TVP5154        BIT(2)
+#      define MSP_RESET_IMAGER         BIT(3)
+#      define MSP_RESET_ETHERNET       BIT(4)
+#      define MSP_RESET_SYS            BIT(5)
+#      define MSP_RESET_AIC33          BIT(7)
+
+/* GPIO registers ... bit patterns mostly match the source MSP ports */
+#define DM355EVM_MSP_LED               0x03    /* active low (MSP P4) */
+#define DM355EVM_MSP_SWITCH1           0x04    /* (MSP P5, masked) */
+#      define MSP_SWITCH1_SW6_1        BIT(0)
+#      define MSP_SWITCH1_SW6_2        BIT(1)
+#      define MSP_SWITCH1_SW6_3        BIT(2)
+#      define MSP_SWITCH1_SW6_4        BIT(3)
+#      define MSP_SWITCH1_J1           BIT(4)  /* NTSC/PAL */
+#      define MSP_SWITCH1_MSP_INT      BIT(5)  /* active low */
+#define DM355EVM_MSP_SWITCH2           0x05    /* (MSP P6, masked) */
+#      define MSP_SWITCH2_SW10         BIT(3)
+#      define MSP_SWITCH2_SW11         BIT(4)
+#      define MSP_SWITCH2_SW12         BIT(5)
+#      define MSP_SWITCH2_SW13         BIT(6)
+#      define MSP_SWITCH2_SW14         BIT(7)
+#define DM355EVM_MSP_SDMMC             0x06    /* (MSP P2, masked) */
+#      define MSP_SDMMC_0_WP           BIT(1)
+#      define MSP_SDMMC_0_CD           BIT(2)  /* active low */
+#      define MSP_SDMMC_1_WP           BIT(3)
+#      define MSP_SDMMC_1_CD           BIT(4)  /* active low */
+#define DM355EVM_MSP_FIRMREV           0x07    /* not a GPIO (out of order) */
+#define DM355EVM_MSP_VIDEO_IN          0x08    /* (MSP P3, masked) */
+#      define MSP_VIDEO_IMAGER         BIT(7)  /* low == tvp5146 */
+
+/* power supply registers are currently omitted */
+
+/* RTC registers */
+#define DM355EVM_MSP_RTC_0             0x12    /* LSB */
+#define DM355EVM_MSP_RTC_1             0x13
+#define DM355EVM_MSP_RTC_2             0x14
+#define DM355EVM_MSP_RTC_3             0x15    /* MSB */
+
+/* input event queue registers; code == ((HIGH << 8) | LOW) */
+#define DM355EVM_MSP_INPUT_COUNT       0x16    /* decrement by reading LOW */
+#define DM355EVM_MSP_INPUT_HIGH                0x17
+#define DM355EVM_MSP_INPUT_LOW         0x18
+
+#endif /* __LINUX_I2C_DM355EVM_MSP */
index fb604dc..a8f84c0 100644 (file)
@@ -78,8 +78,8 @@ int twl4030_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
  * IMPORTANT:  For twl4030_i2c_write(), allocate num_bytes + 1
  * for the value, and populate your data starting at offset 1.
  */
-int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
-int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
 
 /*----------------------------------------------------------------------*/
 
@@ -278,6 +278,18 @@ struct twl4030_platform_data {
        struct twl4030_keypad_data              *keypad;
        struct twl4030_usb_data                 *usb;
 
+       /* LDO regulators */
+       struct regulator_init_data              *vdac;
+       struct regulator_init_data              *vpll1;
+       struct regulator_init_data              *vpll2;
+       struct regulator_init_data              *vmmc1;
+       struct regulator_init_data              *vmmc2;
+       struct regulator_init_data              *vsim;
+       struct regulator_init_data              *vaux1;
+       struct regulator_init_data              *vaux2;
+       struct regulator_init_data              *vaux3;
+       struct regulator_init_data              *vaux4;
+
        /* REVISIT more to come ... _nothing_ should be hard-wired */
 };
 
@@ -285,33 +297,6 @@ struct twl4030_platform_data {
 
 int twl4030_sih_setup(int module);
 
-/*
- * FIXME completely stop using TWL4030_IRQ_BASE ... instead, pass the
- * IRQ data to subsidiary devices using platform device resources.
- */
-
-/* IRQ information-need base */
-#include <mach/irqs.h>
-/* TWL4030 interrupts */
-
-/* #define TWL4030_MODIRQ_GPIO         (TWL4030_IRQ_BASE + 0) */
-#define TWL4030_MODIRQ_KEYPAD          (TWL4030_IRQ_BASE + 1)
-#define TWL4030_MODIRQ_BCI             (TWL4030_IRQ_BASE + 2)
-#define TWL4030_MODIRQ_MADC            (TWL4030_IRQ_BASE + 3)
-/* #define TWL4030_MODIRQ_USB          (TWL4030_IRQ_BASE + 4) */
-/* #define TWL4030_MODIRQ_PWR          (TWL4030_IRQ_BASE + 5) */
-
-#define TWL4030_PWRIRQ_PWRBTN          (TWL4030_PWR_IRQ_BASE + 0)
-/* #define TWL4030_PWRIRQ_CHG_PRES             (TWL4030_PWR_IRQ_BASE + 1) */
-/* #define TWL4030_PWRIRQ_USB_PRES             (TWL4030_PWR_IRQ_BASE + 2) */
-/* #define TWL4030_PWRIRQ_RTC          (TWL4030_PWR_IRQ_BASE + 3) */
-/* #define TWL4030_PWRIRQ_HOT_DIE              (TWL4030_PWR_IRQ_BASE + 4) */
-/* #define TWL4030_PWRIRQ_PWROK_TIMEOUT        (TWL4030_PWR_IRQ_BASE + 5) */
-/* #define TWL4030_PWRIRQ_MBCHG                (TWL4030_PWR_IRQ_BASE + 6) */
-/* #define TWL4030_PWRIRQ_SC_DETECT    (TWL4030_PWR_IRQ_BASE + 7) */
-
-/* Rest are unsued currently*/
-
 /* Offsets to Power Registers */
 #define TWL4030_VDAC_DEV_GRP           0x3B
 #define TWL4030_VDAC_DEDICATED         0x3E
@@ -322,10 +307,6 @@ int twl4030_sih_setup(int module);
 #define TWL4030_VAUX3_DEV_GRP          0x1F
 #define TWL4030_VAUX3_DEDICATED                0x22
 
-/* TWL4030 GPIO interrupt definitions */
-
-#define TWL4030_GPIO_IRQ_NO(n)         (TWL4030_GPIO_IRQ_BASE + (n))
-
 /*
  * Exported TWL4030 GPIO APIs
  *
@@ -340,4 +321,38 @@ int twl4030_set_gpio_debounce(int gpio, int enable);
        static inline int twl4030charger_usb_en(int enable) { return 0; }
 #endif
 
+/*----------------------------------------------------------------------*/
+
+/* Linux-specific regulator identifiers ... for now, we only support
+ * the LDOs, and leave the three buck converters alone.  VDD1 and VDD2
+ * need to tie into hardware based voltage scaling (cpufreq etc), while
+ * VIO is generally fixed.
+ */
+
+/* EXTERNAL dc-to-dc buck converters */
+#define TWL4030_REG_VDD1       0
+#define TWL4030_REG_VDD2       1
+#define TWL4030_REG_VIO                2
+
+/* EXTERNAL LDOs */
+#define TWL4030_REG_VDAC       3
+#define TWL4030_REG_VPLL1      4
+#define TWL4030_REG_VPLL2      5       /* not on all chips */
+#define TWL4030_REG_VMMC1      6
+#define TWL4030_REG_VMMC2      7       /* not on all chips */
+#define TWL4030_REG_VSIM       8       /* not on all chips */
+#define TWL4030_REG_VAUX1      9       /* not on all chips */
+#define TWL4030_REG_VAUX2_4030 10      /* (twl4030-specific) */
+#define TWL4030_REG_VAUX2      11      /* (twl5030 and newer) */
+#define TWL4030_REG_VAUX3      12      /* not on all chips */
+#define TWL4030_REG_VAUX4      13      /* not on all chips */
+
+/* INTERNAL LDOs */
+#define TWL4030_REG_VINTANA1   14
+#define TWL4030_REG_VINTANA2   15
+#define TWL4030_REG_VINTDIG    16
+#define TWL4030_REG_VUSB1V5    17
+#define TWL4030_REG_VUSB1V8    18
+#define TWL4030_REG_VUSB3V1    19
+
 #endif /* End of __TWL4030_H */
index cad314c..115dbe9 100644 (file)
@@ -32,6 +32,7 @@ enum {
        DA9030_ID_LDO18,
        DA9030_ID_LDO19,
        DA9030_ID_LDO_INT,      /* LDO Internal */
+       DA9030_ID_BAT,          /* battery charger */
 
        DA9034_ID_LED_1,
        DA9034_ID_LED_2,
@@ -93,6 +94,43 @@ struct da9034_touch_pdata {
        int     y_inverted;
 };
 
+/* DA9030 battery charger data */
+struct power_supply_info;
+
+struct da9030_battery_info {
+       /* battery parameters */
+       struct power_supply_info *battery_info;
+
+       /* current and voltage to use for battery charging */
+       unsigned int charge_milliamp;
+       unsigned int charge_millivolt;
+
+       /* voltage thresholds (in millivolts) */
+       int vbat_low;
+       int vbat_crit;
+       int vbat_charge_start;
+       int vbat_charge_stop;
+       int vbat_charge_restart;
+
+       /* battery nominal minimal and maximal voltages in millivolts */
+       int vcharge_min;
+       int vcharge_max;
+
+       /* Temperature thresholds. These are DA9030 register values
+          "as is" and should be measured for each battery type */
+       int tbat_low;
+       int tbat_high;
+       int tbat_restart;
+
+
+       /* battery monitor interval (seconds) */
+       unsigned int batmon_interval;
+
+       /* platform callbacks for battery low and critical events */
+       void (*battery_low)(void);
+       void (*battery_critical)(void);
+};
+
 struct da903x_subdev_info {
        int             id;
        const char      *name;
@@ -190,11 +228,13 @@ extern int da903x_unregister_notifier(struct device *dev,
 extern int da903x_query_status(struct device *dev, unsigned int status);
 
 
-/* NOTE: the two functions below are not intended for use outside
- * of the DA9034 sub-device drivers
+/* NOTE: the functions below are not intended for use outside
+ * of the DA903x sub-device drivers
  */
 extern int da903x_write(struct device *dev, int reg, uint8_t val);
+extern int da903x_writes(struct device *dev, int reg, int len, uint8_t *val);
 extern int da903x_read(struct device *dev, int reg, uint8_t *val);
+extern int da903x_reads(struct device *dev, int reg, int len, uint8_t *val);
 extern int da903x_update(struct device *dev, int reg, uint8_t val, uint8_t mask);
 extern int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask);
 extern int da903x_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
index 0537886..54bc5d0 100644 (file)
 #define WM8350_AUXADC_BATT                     6
 #define WM8350_AUXADC_TEMP                     7
 
+struct wm8350;
+
+/*
+ * AUX ADC Readback
+ */
+int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale,
+                      int vref);
+
 #endif
index 6ebf97f..980669d 100644 (file)
@@ -29,6 +29,7 @@
  */
 #define WM8350_RESET_ID                         0x00
 #define WM8350_ID                               0x01
+#define WM8350_REVISION                                0x02
 #define WM8350_SYSTEM_CONTROL_1                 0x03
 #define WM8350_SYSTEM_CONTROL_2                 0x04
 #define WM8350_SYSTEM_HIBERNATE                 0x05
 #define WM8350_OVER_CURRENT_INT_STATUS_MASK     0x25
 #define WM8350_GPIO_INT_STATUS_MASK             0x26
 #define WM8350_COMPARATOR_INT_STATUS_MASK       0x27
+#define WM8350_CHARGER_OVERRIDES               0xE2
+#define WM8350_MISC_OVERRIDES                  0xE3
+#define WM8350_COMPARATOR_OVERRIDES            0xE7
+#define WM8350_STATE_MACHINE_STATUS            0xE9
 
 #define WM8350_MAX_REGISTER                     0xFF
 
 #define WM8350_CUST_ID_MASK                     0x00FF
 
 /*
+ * R2 (0x02) - Revision
+ */
+#define WM8350_MASK_REV_MASK                   0x00FF
+
+/*
  * R3 (0x03) - System Control 1
  */
 #define WM8350_CHIP_ON                          0x8000
 #define WM8350_DC2_STS                          0x0002
 #define WM8350_DC1_STS                          0x0001
 
+/*
+ * R226 (0xE2) - Charger status
+ */
+#define WM8350_CHG_BATT_HOT_OVRDE              0x8000
+#define WM8350_CHG_BATT_COLD_OVRDE             0x4000
+
+/*
+ * R227 (0xE3) - Misc Overrides
+ */
+#define WM8350_USB_LIMIT_OVRDE                 0x0400
+
+/*
+ * R227 (0xE7) - Comparator Overrides
+ */
+#define WM8350_USB_FB_OVRDE                    0x8000
+#define WM8350_WALL_FB_OVRDE                   0x4000
+#define WM8350_BATT_FB_OVRDE                   0x2000
+
+
+/*
+ * R233 (0xE9) - State Machinine Status
+ */
+#define WM8350_USB_SM_MASK                     0x0700
+#define WM8350_USB_SM_SHIFT                    8
+
+#define WM8350_USB_SM_100_SLV   1
+#define WM8350_USB_SM_500_SLV   5
+#define WM8350_USB_SM_STDBY_SLV 7
+
 /* WM8350 wake up conditions */
 #define WM8350_IRQ_WKUP_OFF_STATE              43
 #define WM8350_IRQ_WKUP_HIB_STATE              44
 #define WM8350_REV_E                           0x4
 #define WM8350_REV_F                           0x5
 #define WM8350_REV_G                           0x6
+#define WM8350_REV_H                           0x7
 
 #define WM8350_NUM_IRQ                         63
 
@@ -549,6 +589,14 @@ extern const u16 wm8350_mode0_defaults[];
 extern const u16 wm8350_mode1_defaults[];
 extern const u16 wm8350_mode2_defaults[];
 extern const u16 wm8350_mode3_defaults[];
+extern const u16 wm8351_mode0_defaults[];
+extern const u16 wm8351_mode1_defaults[];
+extern const u16 wm8351_mode2_defaults[];
+extern const u16 wm8351_mode3_defaults[];
+extern const u16 wm8352_mode0_defaults[];
+extern const u16 wm8352_mode1_defaults[];
+extern const u16 wm8352_mode2_defaults[];
+extern const u16 wm8352_mode3_defaults[];
 
 struct wm8350;
 
@@ -558,8 +606,6 @@ struct wm8350_irq {
 };
 
 struct wm8350 {
-       int rev;                /* chip revision */
-
        struct device *dev;
 
        /* device IO */
@@ -572,6 +618,8 @@ struct wm8350 {
                         void *src);
        u16 *reg_cache;
 
+       struct mutex auxadc_mutex;
+
        /* Interrupt handling */
        struct work_struct irq_work;
        struct mutex irq_mutex; /* IRQ table mutex */
index 69b69e0..96acbfc 100644 (file)
@@ -701,6 +701,10 @@ struct platform_device;
 struct regulator_init_data;
 
 struct wm8350_pmic {
+       /* Number of regulators of each type on this device */
+       int max_dcdc;
+       int max_isink;
+
        /* ISINK to DCDC mapping */
        int isink_A_dcdc;
        int isink_B_dcdc;
index 1c8f3cd..2b94793 100644 (file)
@@ -13,7 +13,8 @@
 #ifndef __LINUX_MFD_WM8350_SUPPLY_H_
 #define __LINUX_MFD_WM8350_SUPPLY_H_
 
-#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
 
 /*
  * Charger registers
 #define WM8350_IRQ_EXT_WALL_FB                 37
 #define WM8350_IRQ_EXT_BAT_FB                  38
 
+/*
+ * Policy to control charger state machine.
+ */
+struct wm8350_charger_policy {
+
+       /* charger state machine policy  - set in machine driver */
+       int eoc_mA;             /* end of charge current (mA)  */
+       int charge_mV;          /* charge voltage */
+       int fast_limit_mA;      /* fast charge current limit */
+       int fast_limit_USB_mA;  /* USB fast charge current limit */
+       int charge_timeout;     /* charge timeout (mins) */
+       int trickle_start_mV;   /* trickle charge starts at mV */
+       int trickle_charge_mA;  /* trickle charge current */
+       int trickle_charge_USB_mA;      /* USB trickle charge current */
+};
+
 struct wm8350_power {
        struct platform_device *pdev;
+       struct power_supply battery;
+       struct power_supply usb;
+       struct power_supply ac;
+       struct wm8350_charger_policy *policy;
+
+       int rev_g_coeff;
 };
 
 #endif
index f9348cb..8ff25e0 100644 (file)
@@ -45,6 +45,7 @@ enum {
        POWER_SUPPLY_HEALTH_DEAD,
        POWER_SUPPLY_HEALTH_OVERVOLTAGE,
        POWER_SUPPLY_HEALTH_UNSPEC_FAILURE,
+       POWER_SUPPLY_HEALTH_COLD,
 };
 
 enum {