summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-01-06 06:04:09 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-06 06:04:09 +0300
commit8e128ce3318a147903c893de1891f6c2306f8a61 (patch)
tree3b45e780570e9beb9ec8e83c677f2d9fd9b458ce /drivers
parent0bbb2753584231db364b624bf8cf82551b94da7d (diff)
parent3f874b6643e189d3d07618928ceed0013d71593e (diff)
downloadlinux-8e128ce3318a147903c893de1891f6c2306f8a61.tar.xz
Merge branch 'for-next' of git://git.o-hand.com/linux-mfd
* '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 ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/chips/Kconfig23
-rw-r--r--drivers/i2c/chips/Makefile2
-rw-r--r--drivers/mfd/Kconfig66
-rw-r--r--drivers/mfd/Makefile7
-rw-r--r--drivers/mfd/da903x.c16
-rw-r--r--drivers/mfd/dm355evm_msp.c420
-rw-r--r--drivers/mfd/menelaus.c (renamed from drivers/i2c/chips/menelaus.c)0
-rw-r--r--drivers/mfd/mfd-core.c1
-rw-r--r--drivers/mfd/tps65010.c (renamed from drivers/i2c/chips/tps65010.c)0
-rw-r--r--drivers/mfd/twl4030-core.c472
-rw-r--r--drivers/mfd/twl4030-irq.c30
-rw-r--r--drivers/mfd/wm8350-core.c266
-rw-r--r--drivers/mfd/wm8350-i2c.c4
-rw-r--r--drivers/mfd/wm8350-regmap.c2100
-rw-r--r--drivers/mfd/wm8400-core.c31
-rw-r--r--drivers/power/Kconfig14
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/da9030_battery.c600
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/power/wm8350_power.c532
-rw-r--r--drivers/regulator/wm8350-regulator.c7
21 files changed, 4290 insertions, 305 deletions
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 4c35702830ce..864ac561fdbb 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -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
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 23d2a31b0a64..8b95f41a5001 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -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
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 257277394f8c..416f9e7286ba 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -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
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9a5ad8af9116..0c9418b36c26 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -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
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
index 0b5bd85dfcec..99f8dcfe3d98 100644
--- a/drivers/mfd/da903x.c
+++ b/drivers/mfd/da903x.c
@@ -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
index 000000000000..4214b3f72426
--- /dev/null
+++ b/drivers/mfd/dm355evm_msp.c
@@ -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");
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/mfd/menelaus.c
index 4b364bae6b3e..4b364bae6b3e 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/mfd/menelaus.c
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 6c0d1bec4b76..54ddf3772e0c 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -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);
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/mfd/tps65010.c
index acf8b9d5f575..acf8b9d5f575 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/mfd/tps65010.c
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
index dd843c4fbcc7..b59c385cbc12 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -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>
@@ -71,6 +73,13 @@
#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
@@ -149,6 +158,10 @@
#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);
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index fae868a8d499..b10876036983 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -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;
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 0d47fb9e4b3b..3a273ccef3f2 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -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) {
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
index 3e0ce0e50ea2..8d8c93217572 100644
--- a/drivers/mfd/wm8350-i2c.c
+++ b/drivers/mfd/wm8350-i2c.c
@@ -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);
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c
index 974678db22cd..68887b817d17 100644
--- a/drivers/mfd/wm8350-regmap.c
+++ b/drivers/mfd/wm8350-regmap.c
@@ -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 */
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 6a0cedb5bb8a..cf30d06a0104 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -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)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8e0c2b47803c..668472405a57 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -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
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index e8f1ecec5d8f..eebb15505a40 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -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
index 000000000000..1662bb0f23a5
--- /dev/null
+++ b/drivers/power/da9030_battery.c
@@ -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");
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 23ae8460f5c1..ac01e06817fb 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -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
index 000000000000..1b16bf343f2f
--- /dev/null
+++ b/drivers/power/wm8350_power.c
@@ -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");
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 1f44b17e23b1..c68c496b2c49 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -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;