summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/glue.c112
-rw-r--r--drivers/block/ataflop.c4
-rw-r--r--drivers/char/vt.c5
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c10
-rw-r--r--drivers/input/serio/hp_sdc.c2
-rw-r--r--drivers/isdn/mISDN/dsp_cmx.c4
-rw-r--r--drivers/isdn/mISDN/timerdev.c2
-rw-r--r--drivers/md/Kconfig14
-rw-r--r--drivers/mfd/Kconfig38
-rw-r--r--drivers/mfd/Makefile5
-rw-r--r--drivers/mfd/wm8350-core.c1273
-rw-r--r--drivers/mfd/wm8350-gpio.c222
-rw-r--r--drivers/mfd/wm8350-i2c.c120
-rw-r--r--drivers/mfd/wm8350-regmap.c1347
-rw-r--r--drivers/mfd/wm8400-core.c455
-rw-r--r--drivers/net/3c501.c12
-rw-r--r--drivers/net/3c515.c2
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/cxgb3/adapter.h2
-rw-r--r--drivers/net/cxgb3/ael1002.c2
-rw-r--r--drivers/net/cxgb3/common.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_ctl_defs.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_ioctl.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c2
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c2
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.h2
-rw-r--r--drivers/net/cxgb3/firmware_exports.h2
-rw-r--r--drivers/net/cxgb3/l2t.c2
-rw-r--r--drivers/net/cxgb3/l2t.h2
-rw-r--r--drivers/net/cxgb3/mc5.c2
-rw-r--r--drivers/net/cxgb3/sge.c2
-rw-r--r--drivers/net/cxgb3/t3_cpl.h2
-rw-r--r--drivers/net/cxgb3/t3_hw.c2
-rw-r--r--drivers/net/cxgb3/t3cdev.h2
-rw-r--r--drivers/net/cxgb3/version.h4
-rw-r--r--drivers/net/cxgb3/vsc8211.c2
-rw-r--r--drivers/net/cxgb3/xgmac.c2
-rw-r--r--drivers/net/eexpress.c2
-rw-r--r--drivers/net/enic/enic_main.c1
-rw-r--r--drivers/net/ibmlana.c2
-rw-r--r--drivers/net/jme.c1
-rw-r--r--drivers/net/macmace.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/phy/mdio_bus.c1
-rw-r--r--drivers/net/phy/phy_device.c1
-rw-r--r--drivers/net/qlge/qlge.h2
-rw-r--r--drivers/net/qlge/qlge_main.c1
-rw-r--r--drivers/net/tlan.c3
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tulip/de2104x.c1
-rw-r--r--drivers/net/tulip/dmfe.c4
-rw-r--r--drivers/net/via-velocity.c2
-rw-r--r--drivers/net/wan/z85230.c3
-rw-r--r--drivers/net/wan/z85230.h2
-rw-r--r--drivers/net/wireless/wavelan.c2
-rw-r--r--drivers/net/wireless/wavelan.p.h2
-rw-r--r--drivers/regulator/Kconfig24
-rw-r--r--drivers/regulator/Makefile3
-rw-r--r--drivers/regulator/bq24022.c21
-rw-r--r--drivers/regulator/core.c508
-rw-r--r--drivers/regulator/da903x.c513
-rw-r--r--drivers/regulator/wm8350-regulator.c1431
-rw-r--r--drivers/regulator/wm8400-regulator.c368
-rw-r--r--drivers/rtc/rtc-cmos.c122
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/scsi/Kconfig9
-rw-r--r--drivers/scsi/atari_dma_emul.c468
-rw-r--r--drivers/scsi/atari_scsi.c27
-rw-r--r--drivers/serial/8250.c3
-rw-r--r--drivers/video/console/fbcon.c39
-rw-r--r--drivers/video/console/mdacon.c2
-rw-r--r--drivers/video/console/sticon.c4
-rw-r--r--drivers/video/console/vgacon.c4
76 files changed, 6293 insertions, 966 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 3c578ef78c48..24649ada08df 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -260,115 +260,3 @@ static int __init init_acpi_device_notify(void)
}
arch_initcall(init_acpi_device_notify);
-
-
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
-
-#ifdef CONFIG_PM
-static u32 rtc_handler(void *context)
-{
- acpi_clear_event(ACPI_EVENT_RTC);
- acpi_disable_event(ACPI_EVENT_RTC, 0);
- return ACPI_INTERRUPT_HANDLED;
-}
-
-static inline void rtc_wake_setup(void)
-{
- acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
- /*
- * After the RTC handler is installed, the Fixed_RTC event should
- * be disabled. Only when the RTC alarm is set will it be enabled.
- */
- acpi_clear_event(ACPI_EVENT_RTC);
- acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_on(struct device *dev)
-{
- acpi_clear_event(ACPI_EVENT_RTC);
- acpi_enable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_off(struct device *dev)
-{
- acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-#else
-#define rtc_wake_setup() do{}while(0)
-#define rtc_wake_on NULL
-#define rtc_wake_off NULL
-#endif
-
-/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
- * its device node and pass extra config data. This helps its driver use
- * capabilities that the now-obsolete mc146818 didn't have, and informs it
- * that this board's RTC is wakeup-capable (per ACPI spec).
- */
-#include <linux/mc146818rtc.h>
-
-static struct cmos_rtc_board_info rtc_info;
-
-
-/* PNP devices are registered in a subsys_initcall();
- * ACPI specifies the PNP IDs to use.
- */
-#include <linux/pnp.h>
-
-static int __init pnp_match(struct device *dev, void *data)
-{
- static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", };
- struct pnp_dev *pnp = to_pnp_dev(dev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ids); i++) {
- if (compare_pnp_id(pnp->id, ids[i]) != 0)
- return 1;
- }
- return 0;
-}
-
-static struct device *__init get_rtc_dev(void)
-{
- return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match);
-}
-
-static int __init acpi_rtc_init(void)
-{
- struct device *dev = get_rtc_dev();
-
- if (acpi_disabled)
- return 0;
-
- if (dev) {
- rtc_wake_setup();
- rtc_info.wake_on = rtc_wake_on;
- rtc_info.wake_off = rtc_wake_off;
-
- /* workaround bug in some ACPI tables */
- if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
- DBG("bogus FADT month_alarm\n");
- acpi_gbl_FADT.month_alarm = 0;
- }
-
- rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
- rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
- rtc_info.rtc_century = acpi_gbl_FADT.century;
-
- /* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */
- if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
- printk(PREFIX "RTC can wake from S4\n");
-
-
- dev->platform_data = &rtc_info;
-
- /* RTC always wakes from S1/S2/S3, and often S4/STD */
- device_init_wakeup(dev, 1);
-
- put_device(dev);
- } else
- DBG("RTC unavailable?\n");
- return 0;
-}
-module_init(acpi_rtc_init);
-
-#endif
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 49f274197b16..432cf4018291 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1882,10 +1882,6 @@ static int __init atari_floppy_init (void)
/* Amiga, Mac, ... don't have Atari-compatible floppy :-) */
return -ENODEV;
- if (MACH_IS_HADES)
- /* Hades doesn't have Atari-compatible floppy */
- return -ENODEV;
-
if (register_blkdev(FLOPPY_MAJOR,"fd"))
return -EBUSY;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 57029fefd64a..a0f7ffb68087 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char,
+ scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
vc->vc_size_row * nr);
}
@@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
step = vc->vc_cols * nr;
scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step);
+ scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
}
static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -434,7 +434,6 @@ static void update_attr(struct vc_data *vc)
vc->vc_blink, vc->vc_underline,
vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
- vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, vc->vc_decscnm, false) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index daa9d4220331..82ec6b1b6467 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -458,35 +458,35 @@ static int hp_sdc_rtc_proc_output (char *buf)
p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");
} else {
p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_fhs(&tv)) {
p += sprintf(p, "handshake\t: READ FAILED!\n");
} else {
p += sprintf(p, "handshake\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_mt(&tv)) {
p += sprintf(p, "alarm\t\t: READ FAILED!\n");
} else {
p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_dt(&tv)) {
p += sprintf(p, "delay\t\t: READ FAILED!\n");
} else {
p += sprintf(p, "delay\t\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_ct(&tv)) {
p += sprintf(p, "periodic\t: READ FAILED!\n");
} else {
p += sprintf(p, "periodic\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
p += sprintf(p,
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 0d395979b2d1..bfe49243f38b 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -323,7 +323,7 @@ static void hp_sdc_tasklet(unsigned long foo)
* it back to the application. and be less verbose.
*/
printk(KERN_WARNING PREFIX "read timeout (%ius)!\n",
- tv.tv_usec - hp_sdc.rtv.tv_usec);
+ (int)(tv.tv_usec - hp_sdc.rtv.tv_usec));
curr->idx += hp_sdc.rqty;
hp_sdc.rqty = 0;
tmp = curr->seq[curr->actidx];
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index e92b1ba4b45e..c2f51cc50760 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -452,10 +452,10 @@ one_member:
if (finddsp->features.pcm_id == dsp->features.pcm_id) {
if (finddsp->pcm_slot_rx >= 0 &&
finddsp->pcm_slot_rx < sizeof(freeslots))
- freeslots[finddsp->pcm_slot_tx] = 0;
+ freeslots[finddsp->pcm_slot_rx] = 0;
if (finddsp->pcm_slot_tx >= 0 &&
finddsp->pcm_slot_tx < sizeof(freeslots))
- freeslots[finddsp->pcm_slot_rx] = 0;
+ freeslots[finddsp->pcm_slot_tx] = 0;
}
}
i = 0;
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index e7462924b505..875fabe16e36 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -61,7 +61,7 @@ mISDN_open(struct inode *ino, struct file *filep)
init_waitqueue_head(&dev->wait);
filep->private_data = dev;
__module_get(THIS_MODULE);
- return 0;
+ return nonseekable_open(ino, filep);
}
static int
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 07d92c11b5d8..2281b5098e95 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -30,6 +30,20 @@ config BLK_DEV_MD
If unsure, say N.
+config MD_AUTODETECT
+ bool "Autodetect RAID arrays during kernel boot"
+ depends on BLK_DEV_MD=y
+ default y
+ ---help---
+ If you say Y here, then the kernel will try to autodetect raid
+ arrays as part of its boot process.
+
+ If you don't use raid and say Y, this autodetection can cause
+ a several-second delay in the boot time due to various
+ synchronisation steps that are part of this step.
+
+ If unsure, say Y.
+
config MD_LINEAR
tristate "Linear (append) mode"
depends on BLK_DEV_MD
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0dae245c6259..5eff8ad834d6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -87,6 +87,44 @@ config MFD_TC6393XB
help
Support for Toshiba Mobile IO Controller TC6393XB
+config MFD_WM8400
+ tristate "Support Wolfson Microelectronics WM8400"
+ help
+ Support for the Wolfson Microelecronics WM8400 PMIC and audio
+ CODEC. This driver adds provides common support for accessing
+ the device, additional drivers must be enabled in order to use
+ the functionality of the device.
+
+config MFD_WM8350
+ tristate
+
+config MFD_WM8350_CONFIG_MODE_0
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_1
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_2
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_3
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_I2C
+ tristate "Support Wolfson Microelectronics WM8350 with I2C"
+ select MFD_WM8350
+ depends on I2C
+ help
+ The WM8350 is an integrated audio and power management
+ subsystem with watchdog and RTC functionality for embedded
+ systems. This option enables core support for the WM8350 with
+ I2C as the control interface. Additional options must be
+ selected to enable support for the functionality of the chip.
+
endmenu
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 6abebe364419..759b1fe1c891 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -12,6 +12,11 @@ obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
+obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
+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_MFD_CORE) += mfd-core.o
obj-$(CONFIG_MCP) += mcp-core.o
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
new file mode 100644
index 000000000000..25a7a5d08bce
--- /dev/null
+++ b/drivers/mfd/wm8350-core.c
@@ -0,0 +1,1273 @@
+/*
+ * wm8350-core.c -- Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood, Mark Brown
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/comparator.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+#define WM8350_UNLOCK_KEY 0x0013
+#define WM8350_LOCK_KEY 0x0000
+
+#define WM8350_CLOCK_CONTROL_1 0x28
+#define WM8350_AIF_TEST 0x74
+
+/* debug */
+#define WM8350_BUS_DEBUG 0
+#if WM8350_BUS_DEBUG
+#define dump(regs, src) do { \
+ int i_; \
+ u16 *src_ = src; \
+ printk(KERN_DEBUG); \
+ for (i_ = 0; i_ < regs; i_++) \
+ printk(" 0x%4.4x", *src_++); \
+ printk("\n"); \
+} while (0);
+#else
+#define dump(bytes, src)
+#endif
+
+#define WM8350_LOCK_DEBUG 0
+#if WM8350_LOCK_DEBUG
+#define ldbg(format, arg...) printk(format, ## arg)
+#else
+#define ldbg(format, arg...)
+#endif
+
+/*
+ * WM8350 Device IO
+ */
+static DEFINE_MUTEX(io_mutex);
+static DEFINE_MUTEX(reg_lock_mutex);
+static DEFINE_MUTEX(auxadc_mutex);
+
+/* Perform a physical read from the device.
+ */
+static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
+ u16 *dest)
+{
+ int i, ret;
+ int bytes = num_regs * 2;
+
+ dev_dbg(wm8350->dev, "volatile read\n");
+ ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest);
+
+ for (i = reg; i < reg + num_regs; i++) {
+ /* Cache is CPU endian */
+ dest[i - reg] = be16_to_cpu(dest[i - reg]);
+
+ /* Satisfy non-volatile bits from cache */
+ dest[i - reg] &= wm8350_reg_io_map[i].vol;
+ dest[i - reg] |= wm8350->reg_cache[i];
+
+ /* Mask out non-readable bits */
+ dest[i - reg] &= wm8350_reg_io_map[i].readable;
+ }
+
+ dump(num_regs, dest);
+
+ return ret;
+}
+
+static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest)
+{
+ int i;
+ int end = reg + num_regs;
+ int ret = 0;
+ int bytes = num_regs * 2;
+
+ if (wm8350->read_dev == NULL)
+ return -ENODEV;
+
+ if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+ dev_err(wm8350->dev, "invalid reg %x\n",
+ reg + num_regs - 1);
+ return -EINVAL;
+ }
+
+ dev_dbg(wm8350->dev,
+ "%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs);
+
+#if WM8350_BUS_DEBUG
+ /* we can _safely_ read any register, but warn if read not supported */
+ for (i = reg; i < end; i++) {
+ if (!wm8350_reg_io_map[i].readable)
+ dev_warn(wm8350->dev,
+ "reg R%d is not readable\n", i);
+ }
+#endif
+
+ /* if any volatile registers are required, then read back all */
+ for (i = reg; i < end; i++)
+ if (wm8350_reg_io_map[i].vol)
+ return wm8350_phys_read(wm8350, reg, num_regs, dest);
+
+ /* no volatiles, then cache is good */
+ dev_dbg(wm8350->dev, "cache read\n");
+ memcpy(dest, &wm8350->reg_cache[reg], bytes);
+ dump(num_regs, dest);
+ return ret;
+}
+
+static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
+{
+ if (reg == WM8350_SECURITY ||
+ wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
+ return 0;
+
+ if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
+ (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
+ reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
+ (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
+ reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
+ return 1;
+ return 0;
+}
+
+static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
+{
+ int i;
+ int end = reg + num_regs;
+ int bytes = num_regs * 2;
+
+ if (wm8350->write_dev == NULL)
+ return -ENODEV;
+
+ if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+ dev_err(wm8350->dev, "invalid reg %x\n",
+ reg + num_regs - 1);
+ return -EINVAL;
+ }
+
+ /* it's generally not a good idea to write to RO or locked registers */
+ for (i = reg; i < end; i++) {
+ if (!wm8350_reg_io_map[i].writable) {
+ dev_err(wm8350->dev,
+ "attempted write to read only reg R%d\n", i);
+ return -EINVAL;
+ }
+
+ if (is_reg_locked(wm8350, i)) {
+ dev_err(wm8350->dev,
+ "attempted write to locked reg R%d\n", i);
+ return -EINVAL;
+ }
+
+ src[i - reg] &= wm8350_reg_io_map[i].writable;
+
+ wm8350->reg_cache[i] =
+ (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
+ | src[i - reg];
+
+ src[i - reg] = cpu_to_be16(src[i - reg]);
+ }
+
+ /* Actually write it out */
+ return wm8350->write_dev(wm8350, reg, bytes, (char *)src);
+}
+
+/*
+ * Safe read, modify, write methods
+ */
+int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+ u16 data;
+ int err;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, reg, 1, &data);
+ if (err) {
+ dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+ goto out;
+ }
+
+ data &= ~mask;
+ err = wm8350_write(wm8350, reg, 1, &data);
+ if (err)
+ dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+ mutex_unlock(&io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_clear_bits);
+
+int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+ u16 data;
+ int err;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, reg, 1, &data);
+ if (err) {
+ dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+ goto out;
+ }
+
+ data |= mask;
+ err = wm8350_write(wm8350, reg, 1, &data);
+ if (err)
+ dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+ mutex_unlock(&io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_set_bits);
+
+u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
+{
+ u16 data;
+ int err;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, reg, 1, &data);
+ if (err)
+ dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+
+ mutex_unlock(&io_mutex);
+ return data;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_read);
+
+int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
+{
+ int ret;
+ u16 data = val;
+
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, reg, 1, &data);
+ if (ret)
+ dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_write);
+
+int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
+ u16 *dest)
+{
+ int err = 0;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, start_reg, regs, dest);
+ if (err)
+ dev_err(wm8350->dev, "block read starting from R%d failed\n",
+ start_reg);
+ mutex_unlock(&io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_read);
+
+int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
+ u16 *src)
+{
+ int ret = 0;
+
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, start_reg, regs, src);
+ if (ret)
+ dev_err(wm8350->dev, "block write starting at R%d failed\n",
+ start_reg);
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_write);
+
+int wm8350_reg_lock(struct wm8350 *wm8350)
+{
+ u16 key = WM8350_LOCK_KEY;
+ int ret;
+
+ ldbg(__func__);
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+ if (ret)
+ dev_err(wm8350->dev, "lock failed\n");
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_lock);
+
+int wm8350_reg_unlock(struct wm8350 *wm8350)
+{
+ u16 key = WM8350_UNLOCK_KEY;
+ int ret;
+
+ ldbg(__func__);
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+ if (ret)
+ dev_err(wm8350->dev, "unlock failed\n");
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
+
+static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+{
+ mutex_lock(&wm8350->irq_mutex);
+
+ if (wm8350->irq[irq].handler)
+ wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
+ else {
+ dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
+ irq);
+ wm8350_mask_irq(wm8350, irq);
+ }
+
+ mutex_unlock(&wm8350->irq_mutex);
+}
+
+/*
+ * wm8350_irq_worker actually handles the interrupts. Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.
+ */
+static void wm8350_irq_worker(struct work_struct *work)
+{
+ struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work);
+ u16 level_one, status1, status2, comp;
+
+ /* TODO: Use block reads to improve performance? */
+ level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
+ & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
+ status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
+ & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
+ status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
+ & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
+ comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
+ & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
+
+ /* over current */
+ if (level_one & WM8350_OC_INT) {
+ u16 oc;
+
+ oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
+ oc &= ~wm8350_reg_read(wm8350,
+ WM8350_OVER_CURRENT_INT_STATUS_MASK);
+
+ if (oc & WM8350_OC_LS_EINT) /* limit switch */
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
+ }
+
+ /* under voltage */
+ if (level_one & WM8350_UV_INT) {
+ u16 uv;
+
+ uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
+ uv &= ~wm8350_reg_read(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
+
+ if (uv & WM8350_UV_DC1_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
+ if (uv & WM8350_UV_DC2_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
+ if (uv & WM8350_UV_DC3_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
+ if (uv & WM8350_UV_DC4_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
+ if (uv & WM8350_UV_DC5_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
+ if (uv & WM8350_UV_DC6_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
+ if (uv & WM8350_UV_LDO1_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
+ if (uv & WM8350_UV_LDO2_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
+ if (uv & WM8350_UV_LDO3_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
+ if (uv & WM8350_UV_LDO4_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
+ }
+
+ /* charger, RTC */
+ if (status1) {
+ if (status1 & WM8350_CHG_BAT_HOT_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_BAT_HOT);
+ if (status1 & WM8350_CHG_BAT_COLD_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_BAT_COLD);
+ if (status1 & WM8350_CHG_BAT_FAIL_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_BAT_FAIL);
+ if (status1 & WM8350_CHG_TO_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
+ if (status1 & WM8350_CHG_END_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
+ if (status1 & WM8350_CHG_START_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
+ if (status1 & WM8350_CHG_FAST_RDY_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_FAST_RDY);
+ if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_VBATT_LT_3P9);
+ if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_VBATT_LT_3P1);
+ if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_VBATT_LT_2P85);
+ if (status1 & WM8350_RTC_ALM_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
+ if (status1 & WM8350_RTC_SEC_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
+ if (status1 & WM8350_RTC_PER_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
+ }
+
+ /* current sink, system, aux adc */
+ if (status2) {
+ if (status2 & WM8350_CS1_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
+ if (status2 & WM8350_CS2_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
+
+ if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_HYST_COMP_FAIL);
+ if (status2 & WM8350_SYS_CHIP_GT115_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_CHIP_GT115);
+ if (status2 & WM8350_SYS_CHIP_GT140_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_CHIP_GT140);
+ if (status2 & WM8350_SYS_WDOG_TO_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_WDOG_TO);
+
+ if (status2 & WM8350_AUXADC_DATARDY_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DATARDY);
+ if (status2 & WM8350_AUXADC_DCOMP4_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP4);
+ if (status2 & WM8350_AUXADC_DCOMP3_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP3);
+ if (status2 & WM8350_AUXADC_DCOMP2_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP2);
+ if (status2 & WM8350_AUXADC_DCOMP1_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP1);
+
+ if (status2 & WM8350_USB_LIMIT_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
+ }
+
+ /* wake, codec, ext */
+ if (comp) {
+ if (comp & WM8350_WKUP_OFF_STATE_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_OFF_STATE);
+ if (comp & WM8350_WKUP_HIB_STATE_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_HIB_STATE);
+ if (comp & WM8350_WKUP_CONV_FAULT_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_CONV_FAULT);
+ if (comp & WM8350_WKUP_WDOG_RST_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_WDOG_RST);
+ if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_GP_PWR_ON);
+ if (comp & WM8350_WKUP_ONKEY_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
+ if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_GP_WAKEUP);
+
+ if (comp & WM8350_CODEC_JCK_DET_L_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CODEC_JCK_DET_L);
+ if (comp & WM8350_CODEC_JCK_DET_R_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CODEC_JCK_DET_R);
+ if (comp & WM8350_CODEC_MICSCD_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CODEC_MICSCD);
+ if (comp & WM8350_CODEC_MICD_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
+
+ if (comp & WM8350_EXT_USB_FB_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
+ if (comp & WM8350_EXT_WALL_FB_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_EXT_WALL_FB);
+ if (comp & WM8350_EXT_BAT_FB_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
+ }
+
+ if (level_one & WM8350_GP_INT) {
+ int i;
+ u16 gpio;
+
+ gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
+ gpio &= ~wm8350_reg_read(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK);
+
+ for (i = 0; i < 12; i++) {
+ if (gpio & (1 << i))
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_GPIO(i));
+ }
+ }
+
+ enable_irq(wm8350->chip_irq);
+}
+
+static irqreturn_t wm8350_irq(int irq, void *data)
+{
+ struct wm8350 *wm8350 = data;
+
+ disable_irq_nosync(irq);
+ schedule_work(&wm8350->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+ void (*handler) (struct wm8350 *, int, void *),
+ void *data)
+{
+ if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+ return -EINVAL;
+
+ if (wm8350->irq[irq].handler)
+ return -EBUSY;
+
+ mutex_lock(&wm8350->irq_mutex);
+ wm8350->irq[irq].handler = handler;
+ wm8350->irq[irq].data = data;
+ mutex_unlock(&wm8350->irq_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_irq);
+
+int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+{
+ if (irq < 0 || irq > WM8350_NUM_IRQ)
+ return -EINVAL;
+
+ mutex_lock(&wm8350->irq_mutex);
+ wm8350->irq[irq].handler = NULL;
+ mutex_unlock(&wm8350->irq_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_free_irq);
+
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+{
+ switch (irq) {
+ case WM8350_IRQ_CHG_BAT_HOT:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_HOT_EINT);
+ case WM8350_IRQ_CHG_BAT_COLD:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_COLD_EINT);
+ case WM8350_IRQ_CHG_BAT_FAIL:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_FAIL_EINT);
+ case WM8350_IRQ_CHG_TO:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_TO_EINT);
+ case WM8350_IRQ_CHG_END:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_END_EINT);
+ case WM8350_IRQ_CHG_START:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_START_EINT);
+ case WM8350_IRQ_CHG_FAST_RDY:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_FAST_RDY_EINT);
+ case WM8350_IRQ_RTC_PER:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_PER_EINT);
+ case WM8350_IRQ_RTC_SEC:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_SEC_EINT);
+ case WM8350_IRQ_RTC_ALM:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_ALM_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P9:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P1:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_2P85:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+ case WM8350_IRQ_CS1:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS1_EINT);
+ case WM8350_IRQ_CS2:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS2_EINT);
+ case WM8350_IRQ_USB_LIMIT:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_USB_LIMIT_EINT);
+ case WM8350_IRQ_AUXADC_DATARDY:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DATARDY_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP4:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP4_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP3:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP3_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP2:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP2_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP1:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP1_EINT);
+ case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT115:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT115_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT140:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT140_EINT);
+ case WM8350_IRQ_SYS_WDOG_TO:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_WDOG_TO_EINT);
+ case WM8350_IRQ_UV_LDO4:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO4_EINT);
+ case WM8350_IRQ_UV_LDO3:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO3_EINT);
+ case WM8350_IRQ_UV_LDO2:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO2_EINT);
+ case WM8350_IRQ_UV_LDO1:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO1_EINT);
+ case WM8350_IRQ_UV_DC6:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC6_EINT);
+ case WM8350_IRQ_UV_DC5:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC5_EINT);
+ case WM8350_IRQ_UV_DC4:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC4_EINT);
+ case WM8350_IRQ_UV_DC3:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC3_EINT);
+ case WM8350_IRQ_UV_DC2:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC2_EINT);
+ case WM8350_IRQ_UV_DC1:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC1_EINT);
+ case WM8350_IRQ_OC_LS:
+ return wm8350_set_bits(wm8350,
+ WM8350_OVER_CURRENT_INT_STATUS_MASK,
+ WM8350_IM_OC_LS_EINT);
+ case WM8350_IRQ_EXT_USB_FB:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_USB_FB_EINT);
+ case WM8350_IRQ_EXT_WALL_FB:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_WALL_FB_EINT);
+ case WM8350_IRQ_EXT_BAT_FB:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_BAT_FB_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_L:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_L_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_R:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_R_EINT);
+ case WM8350_IRQ_CODEC_MICSCD:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICSCD_EINT);
+ case WM8350_IRQ_CODEC_MICD:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICD_EINT);
+ case WM8350_IRQ_WKUP_OFF_STATE:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_HIB_STATE:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_HIB_STATE_EINT);
+ case WM8350_IRQ_WKUP_CONV_FAULT:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_CONV_FAULT_EINT);
+ case WM8350_IRQ_WKUP_WDOG_RST:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_GP_PWR_ON:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_PWR_ON_EINT);
+ case WM8350_IRQ_WKUP_ONKEY:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_ONKEY_EINT);
+ case WM8350_IRQ_WKUP_GP_WAKEUP:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_WAKEUP_EINT);
+ case WM8350_IRQ_GPIO(0):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP0_EINT);
+ case WM8350_IRQ_GPIO(1):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP1_EINT);
+ case WM8350_IRQ_GPIO(2):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP2_EINT);
+ case WM8350_IRQ_GPIO(3):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP3_EINT);
+ case WM8350_IRQ_GPIO(4):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP4_EINT);
+ case WM8350_IRQ_GPIO(5):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP5_EINT);
+ case WM8350_IRQ_GPIO(6):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP6_EINT);
+ case WM8350_IRQ_GPIO(7):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP7_EINT);
+ case WM8350_IRQ_GPIO(8):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP8_EINT);
+ case WM8350_IRQ_GPIO(9):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP9_EINT);
+ case WM8350_IRQ_GPIO(10):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP10_EINT);
+ case WM8350_IRQ_GPIO(11):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP11_EINT);
+ case WM8350_IRQ_GPIO(12):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP12_EINT);
+ default:
+ dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
+ irq);
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_mask_irq);
+
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+{
+ switch (irq) {
+ case WM8350_IRQ_CHG_BAT_HOT:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_HOT_EINT);
+ case WM8350_IRQ_CHG_BAT_COLD:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_COLD_EINT);
+ case WM8350_IRQ_CHG_BAT_FAIL:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_FAIL_EINT);
+ case WM8350_IRQ_CHG_TO:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_TO_EINT);
+ case WM8350_IRQ_CHG_END:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_END_EINT);
+ case WM8350_IRQ_CHG_START:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_START_EINT);
+ case WM8350_IRQ_CHG_FAST_RDY:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_FAST_RDY_EINT);
+ case WM8350_IRQ_RTC_PER:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_PER_EINT);
+ case WM8350_IRQ_RTC_SEC:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_SEC_EINT);
+ case WM8350_IRQ_RTC_ALM:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_ALM_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P9:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P1:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_2P85:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+ case WM8350_IRQ_CS1:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS1_EINT);
+ case WM8350_IRQ_CS2:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS2_EINT);
+ case WM8350_IRQ_USB_LIMIT:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_USB_LIMIT_EINT);
+ case WM8350_IRQ_AUXADC_DATARDY:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DATARDY_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP4:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP4_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP3:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP3_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP2:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP2_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP1:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP1_EINT);
+ case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT115:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT115_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT140:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT140_EINT);
+ case WM8350_IRQ_SYS_WDOG_TO:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_WDOG_TO_EINT);
+ case WM8350_IRQ_UV_LDO4:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO4_EINT);
+ case WM8350_IRQ_UV_LDO3:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO3_EINT);
+ case WM8350_IRQ_UV_LDO2:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO2_EINT);
+ case WM8350_IRQ_UV_LDO1:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO1_EINT);
+ case WM8350_IRQ_UV_DC6:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC6_EINT);
+ case WM8350_IRQ_UV_DC5:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC5_EINT);
+ case WM8350_IRQ_UV_DC4:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC4_EINT);
+ case WM8350_IRQ_UV_DC3:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC3_EINT);
+ case WM8350_IRQ_UV_DC2:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC2_EINT);
+ case WM8350_IRQ_UV_DC1:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC1_EINT);
+ case WM8350_IRQ_OC_LS:
+ return wm8350_clear_bits(wm8350,
+ WM8350_OVER_CURRENT_INT_STATUS_MASK,
+ WM8350_IM_OC_LS_EINT);
+ case WM8350_IRQ_EXT_USB_FB:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_USB_FB_EINT);
+ case WM8350_IRQ_EXT_WALL_FB:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_WALL_FB_EINT);
+ case WM8350_IRQ_EXT_BAT_FB:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_BAT_FB_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_L:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_L_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_R:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_R_EINT);
+ case WM8350_IRQ_CODEC_MICSCD:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICSCD_EINT);
+ case WM8350_IRQ_CODEC_MICD:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICD_EINT);
+ case WM8350_IRQ_WKUP_OFF_STATE:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_HIB_STATE:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_HIB_STATE_EINT);
+ case WM8350_IRQ_WKUP_CONV_FAULT:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_CONV_FAULT_EINT);
+ case WM8350_IRQ_WKUP_WDOG_RST:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_GP_PWR_ON:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_PWR_ON_EINT);
+ case WM8350_IRQ_WKUP_ONKEY:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_ONKEY_EINT);
+ case WM8350_IRQ_WKUP_GP_WAKEUP:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_WAKEUP_EINT);
+ case WM8350_IRQ_GPIO(0):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP0_EINT);
+ case WM8350_IRQ_GPIO(1):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP1_EINT);
+ case WM8350_IRQ_GPIO(2):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP2_EINT);
+ case WM8350_IRQ_GPIO(3):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP3_EINT);
+ case WM8350_IRQ_GPIO(4):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP4_EINT);
+ case WM8350_IRQ_GPIO(5):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP5_EINT);
+ case WM8350_IRQ_GPIO(6):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP6_EINT);
+ case WM8350_IRQ_GPIO(7):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP7_EINT);
+ case WM8350_IRQ_GPIO(8):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP8_EINT);
+ case WM8350_IRQ_GPIO(9):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP9_EINT);
+ case WM8350_IRQ_GPIO(10):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP10_EINT);
+ case WM8350_IRQ_GPIO(11):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP11_EINT);
+ case WM8350_IRQ_GPIO(12):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP12_EINT);
+ default:
+ dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
+ irq);
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+/*
+ * Cache is always host endian.
+ */
+static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
+{
+ int i, ret = 0;
+ u16 value;
+ const u16 *reg_map;
+
+ 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;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+ case 2:
+ reg_map = wm8350_mode2_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+ case 3:
+ reg_map = wm8350_mode3_defaults;
+ break;
+#endif
+ default:
+ dev_err(wm8350->dev, "Configuration mode %d not supported\n",
+ mode);
+ return -EINVAL;
+ }
+
+ wm8350->reg_cache =
+ kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
+ if (wm8350->reg_cache == NULL)
+ return -ENOMEM;
+
+ /* Read the initial cache state back from the device - this is
+ * a PMIC so the device many not be in a virgin state and we
+ * can't rely on the silicon values.
+ */
+ for (i = 0; i < WM8350_MAX_REGISTER; i++) {
+ /* audio register range */
+ if (wm8350_reg_io_map[i].readable &&
+ (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
+ ret = wm8350->read_dev(wm8350, i, 2, (char *)&value);
+ if (ret < 0) {
+ dev_err(wm8350->dev,
+ "failed to read initial cache value\n");
+ goto out;
+ }
+ value = be16_to_cpu(value);
+ value &= wm8350_reg_io_map[i].readable;
+ wm8350->reg_cache[i] = value;
+ } else
+ wm8350->reg_cache[i] = reg_map[i];
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_create_cache);
+
+/*
+ * Register a client device. This is non-fatal since there is no need to
+ * fail the entire device init due to a single platform device failing.
+ */
+static void wm8350_client_dev_register(struct wm8350 *wm8350,
+ const char *name,
+ struct platform_device **pdev)
+{
+ int ret;
+
+ *pdev = platform_device_alloc(name, -1);
+ if (pdev == NULL) {
+ dev_err(wm8350->dev, "Failed to allocate %s\n", name);
+ return;
+ }
+
+ (*pdev)->dev.parent = wm8350->dev;
+ platform_set_drvdata(*pdev, wm8350);
+ ret = platform_device_add(*pdev);
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret);
+ platform_device_put(*pdev);
+ *pdev = NULL;
+ }
+}
+
+int wm8350_device_init(struct wm8350 *wm8350, int irq,
+ struct wm8350_platform_data *pdata)
+{
+ int ret = -EINVAL;
+ u16 id1, id2, mask, mode;
+
+ /* 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);
+
+ id1 = be16_to_cpu(id1);
+ id2 = be16_to_cpu(id2);
+
+ if (id1 == 0x6143) {
+ switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
+ case WM8350_REV_E:
+ dev_info(wm8350->dev, "Found Rev E device\n");
+ wm8350->rev = WM8350_REV_E;
+ break;
+ case WM8350_REV_F:
+ dev_info(wm8350->dev, "Found Rev F device\n");
+ wm8350->rev = WM8350_REV_F;
+ break;
+ case WM8350_REV_G:
+ dev_info(wm8350->dev, "Found Rev G device\n");
+ wm8350->rev = WM8350_REV_G;
+ break;
+ default:
+ /* For safety we refuse to run on unknown hardware */
+ dev_info(wm8350->dev, "Found unknown rev\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ } else {
+ dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
+ id1);
+ 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);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8350: failed to create register cache\n");
+ return ret;
+ }
+
+ if (pdata->init) {
+ ret = pdata->init(wm8350);
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Platform init() failed: %d\n",
+ ret);
+ goto err;
+ }
+ }
+
+ mutex_init(&wm8350->irq_mutex);
+ INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
+ if (irq != NO_IRQ) {
+ ret = request_irq(irq, wm8350_irq, 0,
+ "wm8350", wm8350);
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
+ ret);
+ goto err;
+ }
+ } else {
+ dev_err(wm8350->dev, "No IRQ configured\n");
+ goto err;
+ }
+ wm8350->chip_irq = irq;
+
+ wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
+
+ wm8350_client_dev_register(wm8350, "wm8350-codec",
+ &(wm8350->codec.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-gpio",
+ &(wm8350->gpio.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-power",
+ &(wm8350->power.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev));
+
+ return 0;
+
+err:
+ kfree(wm8350->reg_cache);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_device_init);
+
+void wm8350_device_exit(struct wm8350 *wm8350)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
+ platform_device_unregister(wm8350->pmic.pdev[i]);
+
+ platform_device_unregister(wm8350->wdt.pdev);
+ platform_device_unregister(wm8350->rtc.pdev);
+ platform_device_unregister(wm8350->power.pdev);
+ platform_device_unregister(wm8350->gpio.pdev);
+ platform_device_unregister(wm8350->codec.pdev);
+
+ free_irq(wm8350->chip_irq, wm8350);
+ flush_work(&wm8350->irq_work);
+ kfree(wm8350->reg_cache);
+}
+EXPORT_SYMBOL_GPL(wm8350_device_exit);
+
+MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c
new file mode 100644
index 000000000000..ebf99bef392f
--- /dev/null
+++ b/drivers/mfd/wm8350-gpio.c
@@ -0,0 +1,222 @@
+/*
+ * wm8350-core.c -- Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+
+static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
+{
+ int ret;
+
+ wm8350_reg_unlock(wm8350);
+ if (dir == WM8350_GPIO_DIR_OUT)
+ ret = wm8350_clear_bits(wm8350,
+ WM8350_GPIO_CONFIGURATION_I_O,
+ 1 << gpio);
+ else
+ ret = wm8350_set_bits(wm8350,
+ WM8350_GPIO_CONFIGURATION_I_O,
+ 1 << gpio);
+ wm8350_reg_lock(wm8350);
+ return ret;
+}
+
+static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
+{
+ if (db == WM8350_GPIO_DEBOUNCE_ON)
+ return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_DEBOUNCE, 1 << gpio);
+}
+
+static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
+{
+ u16 reg;
+
+ wm8350_reg_unlock(wm8350);
+ switch (gpio) {
+ case 0:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP0_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 0));
+ break;
+ case 1:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP1_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 4));
+ break;
+ case 2:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP2_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 8));
+ break;
+ case 3:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP3_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 12));
+ break;
+ case 4:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP4_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 0));
+ break;
+ case 5:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP5_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 4));
+ break;
+ case 6:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP6_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 8));
+ break;
+ case 7:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP7_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 12));
+ break;
+ case 8:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP8_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 0));
+ break;
+ case 9:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP9_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 4));
+ break;
+ case 10:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP10_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 8));
+ break;
+ case 11:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP11_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 12));
+ break;
+ case 12:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
+ & ~WM8350_GP12_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
+ reg | ((func & 0xf) << 0));
+ break;
+ default:
+ wm8350_reg_lock(wm8350);
+ return -EINVAL;
+ }
+
+ wm8350_reg_lock(wm8350);
+ return 0;
+}
+
+static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
+{
+ if (up)
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_PIN_PULL_UP_CONTROL,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_PIN_PULL_UP_CONTROL,
+ 1 << gpio);
+}
+
+static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
+{
+ if (down)
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_PULL_DOWN_CONTROL,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_PULL_DOWN_CONTROL,
+ 1 << gpio);
+}
+
+static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
+{
+ if (pol == WM8350_GPIO_ACTIVE_HIGH)
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_PIN_POLARITY_TYPE,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_PIN_POLARITY_TYPE,
+ 1 << gpio);
+}
+
+static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
+{
+ if (invert == WM8350_GPIO_INVERT_ON)
+ return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_MODE, 1 << gpio);
+}
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+ int pol, int pull, int invert, int debounce)
+{
+ /* make sure we never pull up and down at the same time */
+ if (pull == WM8350_GPIO_PULL_NONE) {
+ if (gpio_set_pull_up(wm8350, gpio, 0))
+ goto err;
+ if (gpio_set_pull_down(wm8350, gpio, 0))
+ goto err;
+ } else if (pull == WM8350_GPIO_PULL_UP) {
+ if (gpio_set_pull_down(wm8350, gpio, 0))
+ goto err;
+ if (gpio_set_pull_up(wm8350, gpio, 1))
+ goto err;
+ } else if (pull == WM8350_GPIO_PULL_DOWN) {
+ if (gpio_set_pull_up(wm8350, gpio, 0))
+ goto err;
+ if (gpio_set_pull_down(wm8350, gpio, 1))
+ goto err;
+ }
+
+ if (gpio_set_invert(wm8350, gpio, invert))
+ goto err;
+ if (gpio_set_polarity(wm8350, gpio, pol))
+ goto err;
+ if (gpio_set_debounce(wm8350, gpio, debounce))
+ goto err;
+ if (gpio_set_dir(wm8350, gpio, dir))
+ goto err;
+ return gpio_set_func(wm8350, gpio, func);
+
+err:
+ return -EIO;
+}
+EXPORT_SYMBOL_GPL(wm8350_gpio_config);
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
new file mode 100644
index 000000000000..8dfe21bb3bd1
--- /dev/null
+++ b/drivers/mfd/wm8350-i2c.c
@@ -0,0 +1,120 @@
+/*
+ * 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
+ * linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wm8350/core.h>
+
+static int wm8350_i2c_read_device(struct wm8350 *wm8350, char reg,
+ int bytes, void *dest)
+{
+ int ret;
+
+ ret = i2c_master_send(wm8350->i2c_client, &reg, 1);
+ if (ret < 0)
+ return ret;
+ return i2c_master_recv(wm8350->i2c_client, dest, bytes);
+}
+
+static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg,
+ int bytes, void *src)
+{
+ /* we add 1 byte for device register */
+ u8 msg[(WM8350_MAX_REGISTER << 1) + 1];
+
+ if (bytes > ((WM8350_MAX_REGISTER << 1) + 1))
+ return -EINVAL;
+
+ msg[0] = reg;
+ memcpy(&msg[1], src, bytes);
+ return i2c_master_send(wm8350->i2c_client, msg, bytes + 1);
+}
+
+static int wm8350_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8350 *wm8350;
+ int ret = 0;
+
+ wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
+ if (wm8350 == NULL) {
+ kfree(i2c);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c, wm8350);
+ wm8350->dev = &i2c->dev;
+ wm8350->i2c_client = i2c;
+ wm8350->read_dev = wm8350_i2c_read_device;
+ wm8350->write_dev = wm8350_i2c_write_device;
+
+ ret = wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data);
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ kfree(wm8350);
+ return ret;
+}
+
+static int wm8350_i2c_remove(struct i2c_client *i2c)
+{
+ struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
+
+ wm8350_device_exit(wm8350);
+ kfree(wm8350);
+
+ return 0;
+}
+
+static const struct i2c_device_id wm8350_i2c_id[] = {
+ { "wm8350", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id);
+
+
+static struct i2c_driver wm8350_i2c_driver = {
+ .driver = {
+ .name = "wm8350",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8350_i2c_probe,
+ .remove = wm8350_i2c_remove,
+ .id_table = wm8350_i2c_id,
+};
+
+static int __init wm8350_i2c_init(void)
+{
+ return i2c_add_driver(&wm8350_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(wm8350_i2c_init);
+
+static void __exit wm8350_i2c_exit(void)
+{
+ i2c_del_driver(&wm8350_i2c_driver);
+}
+module_exit(wm8350_i2c_exit);
+
+MODULE_DESCRIPTION("I2C support for the WM8350 AudioPlus PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c
new file mode 100644
index 000000000000..974678db22cd
--- /dev/null
+++ b/drivers/mfd/wm8350-regmap.c
@@ -0,0 +1,1347 @@
+/*
+ * wm8350-regmap.c -- Wolfson Microelectronics WM8350 register map
+ *
+ * This file splits out the tables describing the defaults and access
+ * status of the WM8350 registers since they are rather large.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * 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/mfd/wm8350/core.h>
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode0_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1002, /* 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 - Power Up Interrupt Status */
+ 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 - Power Up Interrupt Status Mask */
+ 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 */
+ 0x3B00, /* 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 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 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 - AIF Test */
+ 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 */
+ 0x03FC, /* 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 */
+ 0x002D, /* 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 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode1_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1002, /* R3 - System Control 1 */
+ 0x0014, /* 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 - Power Up Interrupt Status */
+ 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 - Power Up Interrupt Status Mask */
+ 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 */
+ 0x3B00, /* 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 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 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 - AIF Test */
+ 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 */
+ 0x03FC, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x00FB, /* R134 - GPIO Configuration (i/o) */
+ 0x04FE, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0312, /* R140 - GPIO Function Select 1 */
+ 0x1003, /* R141 - GPIO Function Select 2 */
+ 0x1331, /* 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 */
+ 0x002D, /* 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 */
+ 0x0026, /* R186 - DCDC3 Control */
+ 0x0400, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0062, /* R189 - DCDC4 Control */
+ 0x0400, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 - DCDC6 Control */
+ 0x0800, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x0006, /* R200 - LDO1 Control */
+ 0x0400, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0006, /* R203 - LDO2 Control */
+ 0x0400, /* 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 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode2_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1002, /* R3 - System Control 1 */
+ 0x0014, /* 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 - Power Up Interrupt Status */
+ 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 - Power Up Interrupt Status Mask */
+ 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 */
+ 0x3B00, /* 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 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 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 - AIF Test */
+ 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 */
+ 0x03FC, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x08FB, /* R134 - GPIO Configuration (i/o) */
+ 0x0CFE, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0312, /* R140 - GPIO Function Select 1 */
+ 0x0003, /* R141 - GPIO Function Select 2 */
+ 0x2331, /* 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 */
+ 0x002D, /* 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 */
+ 0x002E, /* R186 - DCDC3 Control */
+ 0x0800, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x000E, /* R189 - DCDC4 Control */
+ 0x0800, /* 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 */
+ 0x001A, /* R200 - LDO1 Control */
+ 0x0800, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0010, /* R203 - LDO2 Control */
+ 0x0800, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x000A, /* R206 - LDO3 Control */
+ 0x0C00, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001A, /* 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 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode3_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1000, /* 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 - Power Up Interrupt Status */
+ 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 - Power Up Interrupt Status Mask */
+ 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 */
+ 0x3B00, /* 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 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 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 - AIF Test */
+ 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 */
+ 0x03FC, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0A7B, /* R134 - GPIO Configuration (i/o) */
+ 0x06FE, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x1312, /* R140 - GPIO Function Select 1 */
+ 0x1030, /* R141 - GPIO Function Select 2 */
+ 0x2231, /* 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 */
+ 0x002D, /* 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 */
+ 0x000E, /* R186 - DCDC3 Control */
+ 0x0400, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0026, /* R189 - DCDC4 Control */
+ 0x0400, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 - DCDC6 Control */
+ 0x0400, /* 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 */
+ 0x001C, /* R203 - LDO2 Control */
+ 0x0400, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001C, /* R206 - LDO3 Control */
+ 0x0400, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001F, /* R209 - LDO4 Control */
+ 0x0400, /* 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 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#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
+ */
+#ifndef WM8350_HAVE_CONFIG_MODE
+#warning No WM8350 config modes supported - select at least one of the
+#warning MFD_WM8350_CONFIG_MODE_n options from the board driver.
+#endif
+
+/*
+ * Access masks.
+ */
+
+const struct wm8350_reg_access wm8350_reg_io_map[] = {
+ /* read write volatile */
+ { 0xFFFF, 0xFFFF, 0xFFFF }, /* R0 - Reset/ID */
+ { 0x7CFF, 0x0C00, 0x7FFF }, /* R1 - ID */
+ { 0x0000, 0x0000, 0x0000 }, /* R2 */
+ { 0xBE3B, 0xBE3B, 0x8000 }, /* R3 - System Control 1 */
+ { 0xFCF7, 0xFCF7, 0xF800 }, /* R4 - System Control 2 */
+ { 0x80FF, 0x80FF, 0x8000 }, /* R5 - System Hibernate */
+ { 0xFB0E, 0xFB0E, 0x0000 }, /* R6 - Interface Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R7 */
+ { 0xE537, 0xE537, 0xFFFF }, /* R8 - Power mgmt (1) */
+ { 0x0FF3, 0x0FF3, 0xFFFF }, /* R9 - Power mgmt (2) */
+ { 0x008F, 0x008F, 0xFFFF }, /* R10 - Power mgmt (3) */
+ { 0x6D3C, 0x6D3C, 0xFFFF }, /* R11 - Power mgmt (4) */
+ { 0x1F8F, 0x1F8F, 0xFFFF }, /* R12 - Power mgmt (5) */
+ { 0x8F3F, 0x8F3F, 0xFFFF }, /* R13 - Power mgmt (6) */
+ { 0x0003, 0x0003, 0xFFFF }, /* R14 - Power mgmt (7) */
+ { 0x0000, 0x0000, 0x0000 }, /* R15 */
+ { 0x7F7F, 0x7F7F, 0xFFFF }, /* R16 - RTC Seconds/Minutes */
+ { 0x073F, 0x073F, 0xFFFF }, /* R17 - RTC Hours/Day */
+ { 0x1F3F, 0x1F3F, 0xFFFF }, /* R18 - RTC Date/Month */
+ { 0x3FFF, 0x00FF, 0xFFFF }, /* R19 - RTC Year */
+ { 0x7F7F, 0x7F7F, 0x0000 }, /* R20 - Alarm Seconds/Minutes */
+ { 0x0F3F, 0x0F3F, 0x0000 }, /* R21 - Alarm Hours/Day */
+ { 0x1F3F, 0x1F3F, 0x0000 }, /* R22 - Alarm Date/Month */
+ { 0xEF7F, 0xEA7F, 0xFFFF }, /* R23 - RTC Time Control */
+ { 0x3BFF, 0x0000, 0xFFFF }, /* R24 - System Interrupts */
+ { 0xFEE7, 0x0000, 0xFFFF }, /* R25 - Interrupt Status 1 */
+ { 0x35FF, 0x0000, 0xFFFF }, /* R26 - Interrupt Status 2 */
+ { 0x0F3F, 0x0000, 0xFFFF }, /* R27 - Power Up Interrupt Status */
+ { 0x0F3F, 0x0000, 0xFFFF }, /* R28 - Under Voltage Interrupt status */
+ { 0x8000, 0x0000, 0xFFFF }, /* R29 - Over Current Interrupt status */
+ { 0x1FFF, 0x0000, 0xFFFF }, /* R30 - GPIO Interrupt Status */
+ { 0xEF7F, 0x0000, 0xFFFF }, /* R31 - Comparator Interrupt Status */
+ { 0x3FFF, 0x3FFF, 0x0000 }, /* R32 - System Interrupts Mask */
+ { 0xFEE7, 0xFEE7, 0x0000 }, /* R33 - Interrupt Status 1 Mask */
+ { 0xF5FF, 0xF5FF, 0x0000 }, /* R34 - Interrupt Status 2 Mask */
+ { 0x0F3F, 0x0F3F, 0x0000 }, /* R35 - Power Up Interrupt Status Mask */
+ { 0x0F3F, 0x0F3F, 0x0000 }, /* R36 - Under Voltage Int status Mask */
+ { 0x8000, 0x8000, 0x0000 }, /* R37 - Over Current Int status Mask */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R38 - GPIO Interrupt Status Mask */
+ { 0xEF7F, 0xEF7F, 0x0000 }, /* R39 - Comparator IntStatus Mask */
+ { 0xC9F7, 0xC9F7, 0xFFFF }, /* R40 - Clock Control 1 */
+ { 0x8001, 0x8001, 0x0000 }, /* R41 - Clock Control 2 */
+ { 0xFFF7, 0xFFF7, 0xFFFF }, /* R42 - FLL Control 1 */
+ { 0xFBFF, 0xFBFF, 0x0000 }, /* R43 - FLL Control 2 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R44 - FLL Control 3 */
+ { 0x0033, 0x0033, 0x0000 }, /* R45 - FLL Control 4 */
+ { 0x0000, 0x0000, 0x0000 }, /* R46 */
+ { 0x0000, 0x0000, 0x0000 }, /* R47 */
+ { 0x3033, 0x3033, 0x0000 }, /* R48 - DAC Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R49 */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R50 - DAC Digital Volume L */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R51 - DAC Digital Volume R */
+ { 0x0000, 0x0000, 0x0000 }, /* R52 */
+ { 0x0FFF, 0x0FFF, 0xFFFF }, /* R53 - DAC LR Rate */
+ { 0x0017, 0x0017, 0x0000 }, /* R54 - DAC Clock Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R55 */
+ { 0x0000, 0x0000, 0x0000 }, /* R56 */
+ { 0x0000, 0x0000, 0x0000 }, /* R57 */
+ { 0x4000, 0x4000, 0x0000 }, /* R58 - DAC Mute */
+ { 0x7000, 0x7000, 0x0000 }, /* R59 - DAC Mute Volume */
+ { 0x3C00, 0x3C00, 0x0000 }, /* R60 - DAC Side */
+ { 0x0000, 0x0000, 0x0000 }, /* R61 */
+ { 0x0000, 0x0000, 0x0000 }, /* R62 */
+ { 0x0000, 0x0000, 0x0000 }, /* R63 */
+ { 0x8303, 0x8303, 0xFFFF }, /* R64 - ADC Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R65 */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R66 - ADC Digital Volume L */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R67 - ADC Digital Volume R */
+ { 0x0FFF, 0x0FFF, 0x0000 }, /* R68 - ADC Divider */
+ { 0x0000, 0x0000, 0x0000 }, /* R69 */
+ { 0x0FFF, 0x0FFF, 0xFFFF }, /* R70 - ADC LR Rate */
+ { 0x0000, 0x0000, 0x0000 }, /* R71 */
+ { 0x0707, 0x0707, 0xFFFF }, /* R72 - Input Control */
+ { 0xC0C0, 0xC0C0, 0xFFFF }, /* R73 - IN3 Input Control */
+ { 0xC09F, 0xC09F, 0xFFFF }, /* R74 - Mic Bias Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R75 */
+ { 0x0F15, 0x0F15, 0xFFFF }, /* R76 - Output Control */
+ { 0xC000, 0xC000, 0xFFFF }, /* R77 - Jack Detect */
+ { 0x03FF, 0x03FF, 0x0000 }, /* R78 - Anti Pop Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R79 */
+ { 0xE1FC, 0xE1FC, 0x8000 }, /* R80 - Left Input Volume */
+ { 0xE1FC, 0xE1FC, 0x8000 }, /* R81 - Right Input Volume */
+ { 0x0000, 0x0000, 0x0000 }, /* R82 */
+ { 0x0000, 0x0000, 0x0000 }, /* R83 */
+ { 0x0000, 0x0000, 0x0000 }, /* R84 */
+ { 0x0000, 0x0000, 0x0000 }, /* R85 */
+ { 0x0000, 0x0000, 0x0000 }, /* R86 */
+ { 0x0000, 0x0000, 0x0000 }, /* R87 */
+ { 0x9807, 0x9807, 0xFFFF }, /* R88 - Left Mixer Control */
+ { 0x980B, 0x980B, 0xFFFF }, /* R89 - Right Mixer Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R90 */
+ { 0x0000, 0x0000, 0x0000 }, /* R91 */
+ { 0x8909, 0x8909, 0xFFFF }, /* R92 - OUT3 Mixer Control */
+ { 0x9E07, 0x9E07, 0xFFFF }, /* R93 - OUT4 Mixer Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R94 */
+ { 0x0000, 0x0000, 0x0000 }, /* R95 */
+ { 0x0EEE, 0x0EEE, 0x0000 }, /* R96 - Output Left Mixer Volume */
+ { 0xE0EE, 0xE0EE, 0x0000 }, /* R97 - Output Right Mixer Volume */
+ { 0x0E0F, 0x0E0F, 0x0000 }, /* R98 - Input Mixer Volume L */
+ { 0xE0E1, 0xE0E1, 0x0000 }, /* R99 - Input Mixer Volume R */
+ { 0x800E, 0x800E, 0x0000 }, /* R100 - Input Mixer Volume */
+ { 0x0000, 0x0000, 0x0000 }, /* R101 */
+ { 0x0000, 0x0000, 0x0000 }, /* R102 */
+ { 0x0000, 0x0000, 0x0000 }, /* R103 */
+ { 0xE1FC, 0xE1FC, 0xFFFF }, /* R104 - LOUT1 Volume */
+ { 0xE1FC, 0xE1FC, 0xFFFF }, /* R105 - ROUT1 Volume */
+ { 0xE1FC, 0xE1FC, 0xFFFF }, /* R106 - LOUT2 Volume */
+ { 0xE7FC, 0xE7FC, 0xFFFF }, /* R107 - ROUT2 Volume */
+ { 0x0000, 0x0000, 0x0000 }, /* R108 */
+ { 0x0000, 0x0000, 0x0000 }, /* R109 */
+ { 0x0000, 0x0000, 0x0000 }, /* R110 */
+ { 0x80E0, 0x80E0, 0xFFFF }, /* R111 - BEEP Volume */
+ { 0xBF00, 0xBF00, 0x0000 }, /* R112 - AI Formating */
+ { 0x00F1, 0x00F1, 0x0000 }, /* R113 - ADC DAC COMP */
+ { 0x00F8, 0x00F8, 0x0000 }, /* R114 - AI ADC Control */
+ { 0x40FB, 0x40FB, 0x0000 }, /* R115 - AI DAC Control */
+ { 0x7C30, 0x7C30, 0x0000 }, /* R116 - AIF Test */
+ { 0x0000, 0x0000, 0x0000 }, /* R117 */
+ { 0x0000, 0x0000, 0x0000 }, /* R118 */
+ { 0x0000, 0x0000, 0x0000 }, /* R119 */
+ { 0x0000, 0x0000, 0x0000 }, /* R120 */
+ { 0x0000, 0x0000, 0x0000 }, /* R121 */
+ { 0x0000, 0x0000, 0x0000 }, /* R122 */
+ { 0x0000, 0x0000, 0x0000 }, /* R123 */
+ { 0x0000, 0x0000, 0x0000 }, /* R124 */
+ { 0x0000, 0x0000, 0x0000 }, /* R125 */
+ { 0x0000, 0x0000, 0x0000 }, /* R126 */
+ { 0x0000, 0x0000, 0x0000 }, /* R127 */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R128 - GPIO Debounce */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R129 - GPIO Pin pull up Control */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R130 - GPIO Pull down Control */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R131 - GPIO Interrupt Mode */
+ { 0x0000, 0x0000, 0x0000 }, /* R132 */
+ { 0x00C0, 0x00C0, 0x0000 }, /* R133 - GPIO Control */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R134 - GPIO Configuration (i/o) */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R135 - GPIO Pin Polarity / Type */
+ { 0x0000, 0x0000, 0x0000 }, /* R136 */
+ { 0x0000, 0x0000, 0x0000 }, /* R137 */
+ { 0x0000, 0x0000, 0x0000 }, /* R138 */
+ { 0x0000, 0x0000, 0x0000 }, /* R139 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R140 - GPIO Function Select 1 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R141 - GPIO Function Select 2 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R142 - GPIO Function Select 3 */
+ { 0x000F, 0x000F, 0x0000 }, /* R143 - GPIO Function Select 4 */
+ { 0xF0FF, 0xF0FF, 0xA000 }, /* R144 - Digitiser Control (1) */
+ { 0x3707, 0x3707, 0x0000 }, /* R145 - Digitiser Control (2) */
+ { 0x0000, 0x0000, 0x0000 }, /* R146 */
+ { 0x0000, 0x0000, 0x0000 }, /* R147 */
+ { 0x0000, 0x0000, 0x0000 }, /* R148 */
+ { 0x0000, 0x0000, 0x0000 }, /* R149 */
+ { 0x0000, 0x0000, 0x0000 }, /* R150 */
+ { 0x0000, 0x0000, 0x0000 }, /* R151 */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R152 - AUX1 Readback */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R153 - AUX2 Readback */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R154 - AUX3 Readback */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R155 - AUX4 Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R156 - USB Voltage Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R157 - LINE Voltage Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R158 - BATT Voltage Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R159 - Chip Temp Readback */
+ { 0x0000, 0x0000, 0x0000 }, /* R160 */
+ { 0x0000, 0x0000, 0x0000 }, /* R161 */
+ { 0x0000, 0x0000, 0x0000 }, /* R162 */
+ { 0x000F, 0x000F, 0x0000 }, /* R163 - Generic Comparator Control */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R164 - Generic comparator 1 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R165 - Generic comparator 2 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R166 - Generic comparator 3 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R167 - Generic comparator 4 */
+ { 0xBFFF, 0xBFFF, 0x8000 }, /* R168 - Battery Charger Control 1 */
+ { 0xFFFF, 0x4FFF, 0xB000 }, /* R169 - Battery Charger Control 2 */
+ { 0x007F, 0x007F, 0x0000 }, /* R170 - Battery Charger Control 3 */
+ { 0x0000, 0x0000, 0x0000 }, /* R171 */
+ { 0x903F, 0x903F, 0xFFFF }, /* R172 - Current Sink Driver A */
+ { 0xE333, 0xE333, 0xFFFF }, /* R173 - CSA Flash control */
+ { 0x903F, 0x903F, 0xFFFF }, /* R174 - Current Sink Driver B */
+ { 0xE333, 0xE333, 0xFFFF }, /* R175 - CSB Flash control */
+ { 0x8F3F, 0x8F3F, 0xFFFF }, /* R176 - DCDC/LDO requested */
+ { 0x332D, 0x332D, 0x0000 }, /* R177 - DCDC Active options */
+ { 0x002D, 0x002D, 0x0000 }, /* R178 - DCDC Sleep options */
+ { 0x5177, 0x5177, 0x8000 }, /* R179 - Power-check comparator */
+ { 0x047F, 0x047F, 0x0000 }, /* R180 - DCDC1 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R181 - DCDC1 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R182 - DCDC1 Low Power */
+ { 0x535B, 0x535B, 0x0000 }, /* R183 - DCDC2 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R184 - DCDC2 Timeouts */
+ { 0x0000, 0x0000, 0x0000 }, /* R185 */
+ { 0x047F, 0x047F, 0x0000 }, /* R186 - DCDC3 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R187 - DCDC3 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R188 - DCDC3 Low Power */
+ { 0x047F, 0x047F, 0x0000 }, /* R189 - DCDC4 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R190 - DCDC4 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R191 - DCDC4 Low Power */
+ { 0x535B, 0x535B, 0x0000 }, /* R192 - DCDC5 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R193 - DCDC5 Timeouts */
+ { 0x0000, 0x0000, 0x0000 }, /* R194 */
+ { 0x047F, 0x047F, 0x0000 }, /* R195 - DCDC6 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R196 - DCDC6 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R197 - DCDC6 Low Power */
+ { 0x0000, 0x0000, 0x0000 }, /* R198 */
+ { 0xFFD3, 0xFFD3, 0x0000 }, /* R199 - Limit Switch Control */
+ { 0x441F, 0x441F, 0x0000 }, /* R200 - LDO1 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R201 - LDO1 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R202 - LDO1 Low Power */
+ { 0x441F, 0x441F, 0x0000 }, /* R203 - LDO2 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R204 - LDO2 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R205 - LDO2 Low Power */
+ { 0x441F, 0x441F, 0x0000 }, /* R206 - LDO3 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R207 - LDO3 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R208 - LDO3 Low Power */
+ { 0x441F, 0x441F, 0x0000 }, /* R209 - LDO4 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R210 - LDO4 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R211 - LDO4 Low Power */
+ { 0x0000, 0x0000, 0x0000 }, /* R212 */
+ { 0x0000, 0x0000, 0x0000 }, /* R213 */
+ { 0x0000, 0x0000, 0x0000 }, /* R214 */
+ { 0x8F3F, 0x8F3F, 0x0000 }, /* R215 - VCC_FAULT Masks */
+ { 0xFF3F, 0xE03F, 0x0000 }, /* R216 - Main Bandgap Control */
+ { 0xEF2F, 0xE02F, 0x0000 }, /* R217 - OSC Control */
+ { 0xF3FF, 0xB3FF, 0xc000 }, /* R218 - RTC Tick Control */
+ { 0xFFFF, 0xFFFF, 0xFFFF }, /* R219 */
+ { 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 }, /* R227 */
+ { 0x0000, 0x0000, 0x0000 }, /* R228 */
+ { 0x0000, 0x0000, 0x0000 }, /* R229 */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R230 - GPIO Pin Status */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R231 */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R232 */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R233 */
+ { 0x0000, 0x0000, 0x0000 }, /* R234 */
+ { 0x0000, 0x0000, 0x0000 }, /* R235 */
+ { 0x0000, 0x0000, 0x0000 }, /* R236 */
+ { 0x0000, 0x0000, 0x0000 }, /* R237 */
+ { 0x0000, 0x0000, 0x0000 }, /* R238 */
+ { 0x0000, 0x0000, 0x0000 }, /* R239 */
+ { 0x0000, 0x0000, 0x0000 }, /* R240 */
+ { 0x0000, 0x0000, 0x0000 }, /* R241 */
+ { 0x0000, 0x0000, 0x0000 }, /* R242 */
+ { 0x0000, 0x0000, 0x0000 }, /* R243 */
+ { 0x0000, 0x0000, 0x0000 }, /* R244 */
+ { 0x0000, 0x0000, 0x0000 }, /* R245 */
+ { 0x0000, 0x0000, 0x0000 }, /* R246 */
+ { 0x0000, 0x0000, 0x0000 }, /* R247 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R248 */
+ { 0x0000, 0x0000, 0x0000 }, /* R249 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R250 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R251 */
+ { 0x0000, 0x0000, 0x0000 }, /* R252 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R253 */
+ { 0x0000, 0x0000, 0x0000 }, /* R254 */
+ { 0x0000, 0x0000, 0x0000 }, /* R255 */
+};
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
new file mode 100644
index 000000000000..6a0cedb5bb8a
--- /dev/null
+++ b/drivers/mfd/wm8400-core.c
@@ -0,0 +1,455 @@
+/*
+ * Core driver for WM8400.
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/wm8400-private.h>
+#include <linux/mfd/wm8400-audio.h>
+
+static struct {
+ u16 readable; /* Mask of readable bits */
+ u16 writable; /* Mask of writable bits */
+ u16 vol; /* Mask of volatile bits */
+ int is_codec; /* Register controlled by codec reset */
+ u16 default_val; /* Value on reset */
+} reg_data[] = {
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */
+ { 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */
+ { 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */
+ { 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */
+ { 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4 */
+ { 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5 */
+ { 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6 */
+ { 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7 */
+ { 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8 */
+ { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9 */
+ { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */
+ { 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */
+ { 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */
+ { 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */
+ { 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */
+ { 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */
+ { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */
+ { 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */
+ { 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */
+ { 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */
+ { 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */
+ { 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */
+ { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */
+ { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */
+ { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */
+ { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */
+ { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */
+ { 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */
+ { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */
+ { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */
+ { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */
+ { 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */
+ { 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */
+ { 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */
+ { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */
+ { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */
+ { 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */
+ { 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */
+ { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */
+ { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */
+ { 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */
+ { 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */
+ { 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */
+ { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */
+ { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */
+ { 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */
+ { 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */
+};
+
+static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest)
+{
+ int i, ret = 0;
+
+ BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+ /* If there are any volatile reads then read back the entire block */
+ for (i = reg; i < reg + num_regs; i++)
+ if (reg_data[i].vol) {
+ ret = wm8400->read_dev(wm8400->io_data, reg,
+ num_regs, dest);
+ if (ret != 0)
+ return ret;
+ for (i = 0; i < num_regs; i++)
+ dest[i] = be16_to_cpu(dest[i]);
+
+ return 0;
+ }
+
+ /* Otherwise use the cache */
+ memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16));
+
+ return 0;
+}
+
+static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs,
+ u16 *src)
+{
+ int ret, i;
+
+ BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+ for (i = 0; i < num_regs; i++) {
+ BUG_ON(!reg_data[reg + i].writable);
+ wm8400->reg_cache[reg + i] = src[i];
+ src[i] = cpu_to_be16(src[i]);
+ }
+
+ /* Do the actual I/O */
+ ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src);
+ if (ret != 0)
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * wm8400_reg_read - Single register read
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg: Register to read
+ *
+ * @return Read value
+ */
+u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg)
+{
+ u16 val;
+
+ mutex_lock(&wm8400->io_lock);
+
+ wm8400_read(wm8400, reg, 1, &val);
+
+ mutex_unlock(&wm8400->io_lock);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(wm8400_reg_read);
+
+int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data)
+{
+ int ret;
+
+ mutex_lock(&wm8400->io_lock);
+
+ ret = wm8400_read(wm8400, reg, count, data);
+
+ mutex_unlock(&wm8400->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_block_read);
+
+/**
+ * wm8400_set_bits - Bitmask write
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg: Register to access
+ * @mask: Mask of bits to change
+ * @val: Value to set for masked bits
+ */
+int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val)
+{
+ u16 tmp;
+ int ret;
+
+ mutex_lock(&wm8400->io_lock);
+
+ ret = wm8400_read(wm8400, reg, 1, &tmp);
+ tmp = (tmp & ~mask) | val;
+ if (ret == 0)
+ ret = wm8400_write(wm8400, reg, 1, &tmp);
+
+ mutex_unlock(&wm8400->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_set_bits);
+
+/**
+ * wm8400_reset_codec_reg_cache - Reset cached codec registers to
+ * their default values.
+ */
+void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
+{
+ int i;
+
+ mutex_lock(&wm8400->io_lock);
+
+ /* Reset all codec registers to their initial value */
+ for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+ if (reg_data[i].is_codec)
+ wm8400->reg_cache[i] = reg_data[i].default_val;
+
+ mutex_unlock(&wm8400->io_lock);
+}
+EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
+
+/*
+ * wm8400_init - Generic initialisation
+ *
+ * The WM8400 can be configured as either an I2C or SPI device. Probe
+ * functions for each bus set up the accessors then call into this to
+ * set up the device itself.
+ */
+static int wm8400_init(struct wm8400 *wm8400,
+ struct wm8400_platform_data *pdata)
+{
+ u16 reg;
+ int ret, i;
+
+ mutex_init(&wm8400->io_lock);
+
+ wm8400->dev->driver_data = wm8400;
+
+ /* Check that this is actually a WM8400 */
+ ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
+ if (ret != 0) {
+ dev_err(wm8400->dev, "Chip ID register read failed\n");
+ return -EIO;
+ }
+ if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) {
+ dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
+ be16_to_cpu(reg));
+ return -ENODEV;
+ }
+
+ /* We don't know what state the hardware is in and since this
+ * is a PMIC we can't reset it safely so initialise the register
+ * cache from the hardware.
+ */
+ ret = wm8400->read_dev(wm8400->io_data, 0,
+ ARRAY_SIZE(wm8400->reg_cache),
+ wm8400->reg_cache);
+ if (ret != 0) {
+ dev_err(wm8400->dev, "Register cache read failed\n");
+ return -EIO;
+ }
+ for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+ wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]);
+
+ /* If the codec is in reset use hard coded values */
+ if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA))
+ for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+ if (reg_data[i].is_codec)
+ wm8400->reg_cache[i] = reg_data[i].default_val;
+
+ ret = wm8400_read(wm8400, WM8400_ID, 1, &reg);
+ if (ret != 0) {
+ dev_err(wm8400->dev, "ID register read failed: %d\n", ret);
+ return ret;
+ }
+ reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
+ dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
+
+ if (pdata && pdata->platform_init) {
+ ret = pdata->platform_init(wm8400->dev);
+ if (ret != 0)
+ dev_err(wm8400->dev, "Platform init failed: %d\n",
+ ret);
+ } else
+ dev_warn(wm8400->dev, "No platform initialisation supplied\n");
+
+ 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]);
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest)
+{
+ struct i2c_client *i2c = io_data;
+ struct i2c_msg xfer[2];
+ int ret;
+
+ /* Write register */
+ xfer[0].addr = i2c->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 1;
+ xfer[0].buf = &reg;
+
+ /* Read data */
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = count * sizeof(u16);
+ xfer[1].buf = (u8 *)dest;
+
+ ret = i2c_transfer(i2c->adapter, xfer, 2);
+ if (ret == 2)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ return ret;
+}
+
+static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src)
+{
+ struct i2c_client *i2c = io_data;
+ u8 *msg;
+ int ret;
+
+ /* We add 1 byte for device register - ideally I2C would gather. */
+ msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL);
+ if (msg == NULL)
+ return -ENOMEM;
+
+ msg[0] = reg;
+ memcpy(&msg[1], src, count * sizeof(u16));
+
+ ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1);
+
+ if (ret == (count * 2) + 1)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ kfree(msg);
+
+ return ret;
+}
+
+static int wm8400_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8400 *wm8400;
+ int ret;
+
+ wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
+ if (wm8400 == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ wm8400->io_data = i2c;
+ wm8400->read_dev = wm8400_i2c_read;
+ wm8400->write_dev = wm8400_i2c_write;
+ wm8400->dev = &i2c->dev;
+ i2c_set_clientdata(i2c, wm8400);
+
+ ret = wm8400_init(wm8400, i2c->dev.platform_data);
+ if (ret != 0)
+ goto struct_err;
+
+ return 0;
+
+struct_err:
+ i2c_set_clientdata(i2c, NULL);
+ kfree(wm8400);
+err:
+ return ret;
+}
+
+static int wm8400_i2c_remove(struct i2c_client *i2c)
+{
+ struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
+
+ wm8400_release(wm8400);
+ i2c_set_clientdata(i2c, NULL);
+ kfree(wm8400);
+
+ return 0;
+}
+
+static const struct i2c_device_id wm8400_i2c_id[] = {
+ { "wm8400", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id);
+
+static struct i2c_driver wm8400_i2c_driver = {
+ .driver = {
+ .name = "WM8400",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8400_i2c_probe,
+ .remove = wm8400_i2c_remove,
+ .id_table = wm8400_i2c_id,
+};
+#endif
+
+static int __init wm8400_module_init(void)
+{
+ int ret = -ENODEV;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8400_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register I2C driver: %d\n", ret);
+#endif
+
+ return ret;
+}
+module_init(wm8400_module_init);
+
+static void __exit wm8400_module_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8400_i2c_driver);
+#endif
+}
+module_exit(wm8400_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 5ba4bab6d43e..7d15e7c6bcad 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -17,7 +17,7 @@
Annapolis MD 21403
Fixed (again!) the missing interrupt locking on TX/RX shifting.
- Alan Cox <Alan.Cox@linux.org>
+ Alan Cox <alan@lxorguk.ukuu.org.uk>
Removed calls to init_etherdev since they are no longer needed, and
cleaned up modularization just a bit. The driver still allows only
@@ -29,16 +29,16 @@
the board. Now getting 150K/second FTP with a 3c501 card. Still playing
with a TX-TX optimisation to see if we can touch 180-200K/second as seems
theoretically maximum.
- 19950402 Alan Cox <Alan.Cox@linux.org>
+ 19950402 Alan Cox <alan@lxorguk.ukuu.org.uk>
Cleaned up for 2.3.x because we broke SMP now.
- 20000208 Alan Cox <alan@redhat.com>
+ 20000208 Alan Cox <alan@lxorguk.ukuu.org.uk>
Check up pass for 2.5. Nothing significant changed
- 20021009 Alan Cox <alan@redhat.com>
+ 20021009 Alan Cox <alan@lxorguk.ukuu.org.uk>
Fixed zero fill corner case
- 20030104 Alan Cox <alan@redhat.com>
+ 20030104 Alan Cox <alan@lxorguk.ukuu.org.uk>
For the avoidance of doubt the "preferred form" of this code is one which
@@ -104,7 +104,7 @@
static const char version[] =
- DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@redhat.com).\n";
+ DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n";
/*
* Braindamage remaining:
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index e4e3241628d6..a0f8b6e2d0af 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -18,7 +18,7 @@
2001/11/17 - Added ethtool support (jgarzik)
- 2002/10/28 - Locking updates for 2.5 (alan@redhat.com)
+ 2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk)
*/
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index e9d529442b06..1d8af3348331 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2400,7 +2400,7 @@ config EHEA
will be called ehea.
config ENIC
- tristate "E, the Cisco 10G Ethernet NIC"
+ tristate "Cisco 10G Ethernet NIC support"
depends on PCI && INET
select INET_LRO
help
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index a0b4c8516073..735fc9476403 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -4,7 +4,7 @@
* - Jay Schulist <jschlst@samba.org>
*
* With more than a little help from;
- * - Alan Cox <Alan.Cox@linux.org>
+ * - Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Derived from:
* - skeleton.c: A network driver outline for linux.
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 455ef529cd62..bc8e2413abd2 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index 744fac0b1617..5c3c05da4d96 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 593fb643a615..e312d315a42d 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
index 6ad92405d9a0..1d8d46eb3c96 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
index 45e92164c260..47e53769af5b 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
index 3e8d5faec3a4..b19e4376ba76 100644
--- a/drivers/net/cxgb3/cxgb3_ioctl.h
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index f31985df0bb9..1ace41a13ac3 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 0f6fd63b2847..265aa8a15afa 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
index 7a379138b5a6..d514e5019dfc 100644
--- a/drivers/net/cxgb3/cxgb3_offload.h
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
index b75ddd8777fe..0d9b0e6dccff 100644
--- a/drivers/net/cxgb3/firmware_exports.h
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
index b2c5314582aa..4407ac9bb555 100644
--- a/drivers/net/cxgb3/l2t.c
+++ b/drivers/net/cxgb3/l2t.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
index 42ce65f76a87..fd3eb07e3f40 100644
--- a/drivers/net/cxgb3/l2t.h
+++ b/drivers/net/cxgb3/l2t.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
index 4c4d6e877ea6..3b5517b8fbde 100644
--- a/drivers/net/cxgb3/mc5.c
+++ b/drivers/net/cxgb3/mc5.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 87919419b707..c6480be0bc1f 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
index 917970ed24a1..852c399a8b0a 100644
--- a/drivers/net/cxgb3/t3_cpl.h
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 4da5b09b9bc2..968f64be3743 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
index 0a21cfbd2b21..be55e9ae74d1 100644
--- a/drivers/net/cxgb3/t3cdev.h
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved.
+ * Copyright (C) 2006-2008 Chelsio Communications. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 29db711303b9..bb8698a86754 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -35,7 +35,7 @@
#define DRV_DESC "Chelsio T3 Network Driver"
#define DRV_NAME "cxgb3"
/* Driver version */
-#define DRV_VERSION "1.0-ko"
+#define DRV_VERSION "1.1.0-ko"
/* Firmware version */
#define FW_VERSION_MAJOR 7
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
index 306c2dc4ab34..33f956bd6b59 100644
--- a/drivers/net/cxgb3/vsc8211.c
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index ffdc0a1892bd..9d7786937aad 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 795c594a4b7c..b751c1b96cfa 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -8,7 +8,7 @@
*
* Many modifications, and currently maintained, by
* Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE Alan Cox <alan@redhat.com>
+ * Added the Compaq LTE Alan Cox <alan@lxorguk.ukuu.org.uk>
* Added MCA support Adam Fritzler
*
* Note - this driver is experimental still - it has problems on faster
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index f3a47a87dbbe..180e968dc54d 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -34,6 +34,7 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
+#include <net/ip6_checksum.h>
#include "cq_enet_desc.h"
#include "vnic_dev.h"
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 95e3464068db..f02764725a22 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -71,7 +71,7 @@ History:
June 1st, 2000
corrected version codes, added support for the latest 2.3 changes
Oct 28th, 2002
- cleaned up for the 2.5 tree <alan@redhat.com>
+ cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk>
*************************************************************************/
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 156f159aafbb..81c6cdc3851f 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -37,6 +37,7 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>
+#include <net/ip6_checksum.h>
#include "jme.h"
static int force_pseudohp = -1;
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 51ad3765e075..85587a6667b9 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -9,7 +9,7 @@
* 2 of the License, or (at your option) any later version.
*
* Copyright (C) 1996 Paul Mackerras.
- * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
*
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 0b28d0d8ffa8..c235cdba69c6 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -15,7 +15,7 @@
incorporated herein by reference.
Donald Becker may be reached at becker@scyld.com
- Updated for 2.5.x by Alan Cox <alan@redhat.com>
+ Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
======================================================================*/
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 54df34f21c5f..448cd40aeba5 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -69,7 +69,7 @@ Driver Notes and Issues
History
-------------------------------------------------------------------------------
Log: nmclan_cs.c,v
- * 2.5.75-ac1 2003/07/11 Alan Cox <alan@redhat.com>
+ * 2.5.75-ac1 2003/07/11 Alan Cox <alan@lxorguk.ukuu.org.uk>
* Fixed hang on card eject as we probe it
* Cleaned up to use new style locking.
*
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 6671e2da0d57..d0ed1ef284a8 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -55,6 +55,7 @@ EXPORT_SYMBOL(mdiobus_alloc);
/**
* mdiobus_release - mii_bus device release callback
+ * @d: the target struct device that contains the mii_bus
*
* Description: called when the last reference to an mii_bus is
* dropped, to free the underlying memory.
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 171627480058..f11e900b437b 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -557,6 +557,7 @@ int genphy_restart_aneg(struct phy_device *phydev)
return ctl;
}
+EXPORT_SYMBOL(genphy_restart_aneg);
/**
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index c37ea436c918..38116f9d4163 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -58,7 +58,7 @@
*/
#if (PAGE_SHIFT == 12) || (PAGE_SHIFT == 13) /* 4k & 8k pages */
#define TX_DESC_PER_OAL ((MAX_SKB_FRAGS - TX_DESC_PER_IOCB) + 2)
-#elif (PAGE_SHIFT == 16) /* 64k pages */
+#else /* all other page sizes */
#define TX_DESC_PER_OAL 0
#endif
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 297877b68c46..4b2caa6b7ac5 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -39,6 +39,7 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
+#include <net/ip6_checksum.h>
#include "qlge.h"
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index ec871f646766..c41d68761364 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -29,7 +29,8 @@
*
* Tigran Aivazian <tigran@sco.com>: TLan_PciProbe() now uses
* new PCI BIOS interface.
- * Alan Cox <alan@redhat.com>: Fixed the out of memory
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ * Fixed the out of memory
* handling.
*
* Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index fa73e6eed6be..ed50d288e494 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -25,7 +25,7 @@
* To do:
* 1. Multicast support.
*
- * Initial 2.5 cleanup Alan Cox <alan@redhat.com> 2002/10/28
+ * Initial 2.5 cleanup Alan Cox <alan@lxorguk.ukuu.org.uk> 2002/10/28
*/
#include <linux/module.h>
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index f54c45049d50..124d5d690dde 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1688,6 +1688,7 @@ static void __devinit de21040_get_mac_address (struct de_private *de)
unsigned i;
dw32 (ROMCmd, 0); /* Reset the pointer with a dummy write. */
+ udelay(5);
for (i = 0; i < 6; i++) {
int value, boguscnt = 100000;
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 656200472fa1..8e46a513a252 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -23,7 +23,7 @@
Marcelo Tosatti <marcelo@conectiva.com.br> :
Made it compile in 2.3 (device to net_device)
- Alan Cox <alan@redhat.com> :
+ Alan Cox <alan@lxorguk.ukuu.org.uk> :
Cleaned up for kernel merge.
Removed the back compatibility support
Reformatted, fixing spelling etc as I went
@@ -49,7 +49,7 @@
support. Updated PCI resource allocation. Do not
forget to unmap PCI mapped skbs.
- Alan Cox <alan@redhat.com>
+ Alan Cox <alan@lxorguk.ukuu.org.uk>
Added new PCI identifiers provided by Clear Zhang at ALi
for their 1563 ethernet device.
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index ad20f96edfa1..2dced383bcfb 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -12,7 +12,7 @@
* Scatter gather
* More testing
*
- * The changes are (c) Copyright 2004, Red Hat Inc. <alan@redhat.com>
+ * The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk>
* Additional fixes and clean up: Francois Romieu
*
* This source has not been verified for use in safety critical systems.
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 243bd8d918fe..ccd9cd35ecbe 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -18,7 +18,8 @@
* DMA now uses get_free_page as kmalloc buffers may span a 64K
* boundary.
*
- * Modified for SMP safety and SMP locking by Alan Cox <alan@redhat.com>
+ * Modified for SMP safety and SMP locking by Alan Cox
+ * <alan@lxorguk.ukuu.org.uk>
*
* Performance
*
diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
index 4f372396c512..85b3e785d484 100644
--- a/drivers/net/wan/z85230.h
+++ b/drivers/net/wan/z85230.h
@@ -2,7 +2,7 @@
* Description of Z8530 Z85C30 and Z85230 communications chips
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
*/
#ifndef _Z8530_H
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 136220b5ca81..e939a73ff794 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -4387,7 +4387,7 @@ MODULE_LICENSE("GPL");
*
* Thanks go also to:
* James Ashton (jaa101@syseng.anu.edu.au),
- * Alan Cox (alan@redhat.com),
+ * Alan Cox (alan@lxorguk.ukuu.org.uk),
* Allan Creighton (allanc@cs.usyd.edu.au),
* Matthew Geier (matthew@cs.usyd.edu.au),
* Remo di Giovanni (remo@cs.usyd.edu.au),
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index b33ac47dd8df..44d31bbf39e4 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -186,7 +186,7 @@
*
* Thanks go also to:
* James Ashton <jaa101@syseng.anu.edu.au>,
- * Alan Cox <alan@redhat.com>,
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>,
* Allan Creighton <allanc@cs.usyd.edu.au>,
* Matthew Geier <matthew@cs.usyd.edu.au>,
* Remo di Giovanni <remo@cs.usyd.edu.au>,
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a656128f1fdd..4dada6ee1119 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -56,4 +56,28 @@ config REGULATOR_BQ24022
charging select between 100 mA and 500 mA charging current
limit.
+config REGULATOR_WM8350
+ tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
+ depends on MFD_WM8350
+ select REGULATOR
+ help
+ This driver provides support for the voltage and current regulators
+ of the WM8350 AudioPlus PMIC.
+
+config REGULATOR_WM8400
+ tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC"
+ depends on MFD_WM8400
+ select REGULATOR
+ help
+ This driver provides support for the voltage regulators of the
+ WM8400 AudioPlus PMIC.
+
+config REGULATOR_DA903X
+ tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
+ depends on PMIC_DA903X
+ select REGULATOR
+ help
+ Say y here to support the BUCKs and LDOs regulators found on
+ Dialog Semiconductor DA9030/DA9034 PMIC.
+
endmenu
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ac2c64efe65c..254d40c02ee8 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -8,5 +8,8 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
+obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
+obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
index 263699d6152d..366565aba865 100644
--- a/drivers/regulator/bq24022.c
+++ b/drivers/regulator/bq24022.c
@@ -18,13 +18,13 @@
#include <linux/regulator/bq24022.h>
#include <linux/regulator/driver.h>
+
static int bq24022_set_current_limit(struct regulator_dev *rdev,
int min_uA, int max_uA)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
- dev_dbg(&pdev->dev, "setting current limit to %s mA\n",
+ dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
max_uA >= 500000 ? "500" : "100");
/* REVISIT: maybe return error if min_uA != 0 ? */
@@ -34,18 +34,16 @@ static int bq24022_set_current_limit(struct regulator_dev *rdev,
static int bq24022_get_current_limit(struct regulator_dev *rdev)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
}
static int bq24022_enable(struct regulator_dev *rdev)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
- dev_dbg(&pdev->dev, "enabling charger\n");
+ dev_dbg(rdev_get_dev(rdev), "enabling charger\n");
gpio_set_value(pdata->gpio_nce, 0);
return 0;
@@ -53,10 +51,9 @@ static int bq24022_enable(struct regulator_dev *rdev)
static int bq24022_disable(struct regulator_dev *rdev)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
- dev_dbg(&pdev->dev, "disabling charger\n");
+ dev_dbg(rdev_get_dev(rdev), "disabling charger\n");
gpio_set_value(pdata->gpio_nce, 1);
return 0;
@@ -108,7 +105,7 @@ static int __init bq24022_probe(struct platform_device *pdev)
ret = gpio_direction_output(pdata->gpio_iset2, 0);
ret = gpio_direction_output(pdata->gpio_nce, 1);
- bq24022 = regulator_register(&bq24022_desc, pdev);
+ bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
if (IS_ERR(bq24022)) {
dev_dbg(&pdev->dev, "couldn't register regulator\n");
ret = PTR_ERR(bq24022);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9c7986261568..02a774424e8d 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2,8 +2,9 @@
* core.c -- Voltage/Current Regulator framework.
*
* Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008 SlimLogic Ltd.
*
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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
@@ -64,14 +65,9 @@ struct regulator_map {
struct list_head list;
struct device *dev;
const char *supply;
- const char *regulator;
+ struct regulator_dev *regulator;
};
-static inline struct regulator_dev *to_rdev(struct device *d)
-{
- return container_of(d, struct regulator_dev, dev);
-}
-
/*
* struct regulator
*
@@ -227,7 +223,7 @@ static ssize_t device_requested_uA_show(struct device *dev,
static ssize_t regulator_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
ssize_t ret;
mutex_lock(&rdev->mutex);
@@ -240,15 +236,31 @@ static ssize_t regulator_uV_show(struct device *dev,
static ssize_t regulator_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
}
+static ssize_t regulator_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ const char *name;
+
+ if (rdev->constraints->name)
+ name = rdev->constraints->name;
+ else if (rdev->desc->name)
+ name = rdev->desc->name;
+ else
+ name = "";
+
+ return sprintf(buf, "%s\n", name);
+}
+
static ssize_t regulator_opmode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
int mode = _regulator_get_mode(rdev);
switch (mode) {
@@ -267,7 +279,7 @@ static ssize_t regulator_opmode_show(struct device *dev,
static ssize_t regulator_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
int state = _regulator_is_enabled(rdev);
if (state > 0)
@@ -281,7 +293,7 @@ static ssize_t regulator_state_show(struct device *dev,
static ssize_t regulator_min_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -292,7 +304,7 @@ static ssize_t regulator_min_uA_show(struct device *dev,
static ssize_t regulator_max_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -303,7 +315,7 @@ static ssize_t regulator_max_uA_show(struct device *dev,
static ssize_t regulator_min_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -314,7 +326,7 @@ static ssize_t regulator_min_uV_show(struct device *dev,
static ssize_t regulator_max_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -325,7 +337,7 @@ static ssize_t regulator_max_uV_show(struct device *dev,
static ssize_t regulator_total_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
struct regulator *regulator;
int uA = 0;
@@ -339,14 +351,14 @@ static ssize_t regulator_total_uA_show(struct device *dev,
static ssize_t regulator_num_users_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", rdev->use_count);
}
static ssize_t regulator_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
@@ -360,7 +372,7 @@ static ssize_t regulator_type_show(struct device *dev,
static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -370,7 +382,7 @@ static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -380,7 +392,7 @@ static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -406,7 +418,7 @@ static ssize_t suspend_opmode_show(struct regulator_dev *rdev,
static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -417,7 +429,7 @@ static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -428,7 +440,7 @@ static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -439,7 +451,7 @@ static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
static ssize_t regulator_suspend_mem_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -453,7 +465,7 @@ static ssize_t regulator_suspend_mem_state_show(struct device *dev,
static ssize_t regulator_suspend_disk_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -467,7 +479,7 @@ static ssize_t regulator_suspend_disk_state_show(struct device *dev,
static ssize_t regulator_suspend_standby_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -477,7 +489,9 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
else
return sprintf(buf, "disabled\n");
}
+
static struct device_attribute regulator_dev_attrs[] = {
+ __ATTR(name, 0444, regulator_name_show, NULL),
__ATTR(microvolts, 0444, regulator_uV_show, NULL),
__ATTR(microamps, 0444, regulator_uA_show, NULL),
__ATTR(opmode, 0444, regulator_opmode_show, NULL),
@@ -512,7 +526,7 @@ static struct device_attribute regulator_dev_attrs[] = {
static void regulator_dev_release(struct device *dev)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
kfree(rdev);
}
@@ -569,8 +583,11 @@ static int suspend_set_state(struct regulator_dev *rdev,
/* enable & disable are mandatory for suspend control */
if (!rdev->desc->ops->set_suspend_enable ||
- !rdev->desc->ops->set_suspend_disable)
+ !rdev->desc->ops->set_suspend_disable) {
+ printk(KERN_ERR "%s: no way to set suspend state\n",
+ __func__);
return -EINVAL;
+ }
if (rstate->enabled)
ret = rdev->desc->ops->set_suspend_enable(rdev);
@@ -656,6 +673,155 @@ static void print_constraints(struct regulator_dev *rdev)
printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
}
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @regulator: regulator source
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+ struct regulation_constraints *constraints)
+{
+ int ret = 0;
+ const char *name;
+ struct regulator_ops *ops = rdev->desc->ops;
+
+ if (constraints->name)
+ name = constraints->name;
+ else if (rdev->desc->name)
+ name = rdev->desc->name;
+ else
+ name = "regulator";
+
+ rdev->constraints = constraints;
+
+ /* do we need to apply the constraint voltage */
+ if (rdev->constraints->apply_uV &&
+ rdev->constraints->min_uV == rdev->constraints->max_uV &&
+ ops->set_voltage) {
+ ret = ops->set_voltage(rdev,
+ rdev->constraints->min_uV, rdev->constraints->max_uV);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
+ __func__,
+ rdev->constraints->min_uV, name);
+ rdev->constraints = NULL;
+ goto out;
+ }
+ }
+
+ /* are we enabled at boot time by firmware / bootloader */
+ if (rdev->constraints->boot_on)
+ rdev->use_count = 1;
+
+ /* do we need to setup our suspend state */
+ if (constraints->initial_state) {
+ ret = suspend_prepare(rdev, constraints->initial_state);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to set suspend state for %s\n",
+ __func__, name);
+ rdev->constraints = NULL;
+ goto out;
+ }
+ }
+
+ /* if always_on is set then turn the regulator on if it's not
+ * already on. */
+ if (constraints->always_on && ops->enable &&
+ ((ops->is_enabled && !ops->is_enabled(rdev)) ||
+ (!ops->is_enabled && !constraints->boot_on))) {
+ ret = ops->enable(rdev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to enable %s\n",
+ __func__, name);
+ rdev->constraints = NULL;
+ goto out;
+ }
+ }
+
+ print_constraints(rdev);
+out:
+ return ret;
+}
+
+/**
+ * set_supply - set regulator supply regulator
+ * @regulator: regulator name
+ * @supply: supply regulator name
+ *
+ * Called by platform initialisation code to set the supply regulator for this
+ * regulator. This ensures that a regulators supply will also be enabled by the
+ * core if it's child is enabled.
+ */
+static int set_supply(struct regulator_dev *rdev,
+ struct regulator_dev *supply_rdev)
+{
+ int err;
+
+ err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
+ "supply");
+ if (err) {
+ printk(KERN_ERR
+ "%s: could not add device link %s err %d\n",
+ __func__, supply_rdev->dev.kobj.name, err);
+ goto out;
+ }
+ rdev->supply = supply_rdev;
+ list_add(&rdev->slist, &supply_rdev->supply_list);
+out:
+ return err;
+}
+
+/**
+ * set_consumer_device_supply: Bind a regulator to a symbolic supply
+ * @regulator: regulator source
+ * @dev: device the supply applies to
+ * @supply: symbolic name for supply
+ *
+ * Allows platform initialisation code to map physical regulator
+ * sources to symbolic names for supplies for use by devices. Devices
+ * should use these symbolic names to request regulators, avoiding the
+ * need to provide board-specific regulator names as platform data.
+ */
+static int set_consumer_device_supply(struct regulator_dev *rdev,
+ struct device *consumer_dev, const char *supply)
+{
+ struct regulator_map *node;
+
+ if (supply == NULL)
+ return -EINVAL;
+
+ node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
+ if (node == NULL)
+ return -ENOMEM;
+
+ node->regulator = rdev;
+ node->dev = consumer_dev;
+ node->supply = supply;
+
+ list_add(&node->list, &regulator_map_list);
+ return 0;
+}
+
+static void unset_consumer_device_supply(struct regulator_dev *rdev,
+ struct device *consumer_dev)
+{
+ struct regulator_map *node, *n;
+
+ list_for_each_entry_safe(node, n, &regulator_map_list, list) {
+ if (rdev == node->regulator &&
+ consumer_dev == node->dev) {
+ list_del(&node->list);
+ kfree(node);
+ return;
+ }
+ }
+}
+
#define REG_STR_SIZE 32
static struct regulator *create_regulator(struct regulator_dev *rdev,
@@ -746,7 +912,6 @@ struct regulator *regulator_get(struct device *dev, const char *id)
struct regulator_dev *rdev;
struct regulator_map *map;
struct regulator *regulator = ERR_PTR(-ENODEV);
- const char *supply = id;
if (id == NULL) {
printk(KERN_ERR "regulator: get() with no identifier\n");
@@ -758,15 +923,9 @@ struct regulator *regulator_get(struct device *dev, const char *id)
list_for_each_entry(map, &regulator_map_list, list) {
if (dev == map->dev &&
strcmp(map->supply, id) == 0) {
- supply = map->regulator;
- break;
- }
- }
-
- list_for_each_entry(rdev, &regulator_list, list) {
- if (strcmp(supply, rdev->desc->name) == 0 &&
- try_module_get(rdev->owner))
+ rdev = map->regulator;
goto found;
+ }
}
printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",
id);
@@ -774,12 +933,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
return regulator;
found:
+ if (!try_module_get(rdev->owner))
+ goto out;
+
regulator = create_regulator(rdev, dev, id);
if (regulator == NULL) {
regulator = ERR_PTR(-ENOMEM);
module_put(rdev->owner);
}
+out:
mutex_unlock(&regulator_list_mutex);
return regulator;
}
@@ -1559,11 +1722,12 @@ EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
* Returns 0 on success.
*/
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
- void *reg_data)
+ struct device *dev, void *driver_data)
{
static atomic_t regulator_no = ATOMIC_INIT(0);
struct regulator_dev *rdev;
- int ret;
+ struct regulator_init_data *init_data = dev->platform_data;
+ int ret, i;
if (regulator_desc == NULL)
return ERR_PTR(-EINVAL);
@@ -1575,6 +1739,9 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
!regulator_desc->type == REGULATOR_CURRENT)
return ERR_PTR(-EINVAL);
+ if (!init_data)
+ return ERR_PTR(-EINVAL);
+
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev == NULL)
return ERR_PTR(-ENOMEM);
@@ -1582,7 +1749,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
mutex_lock(&regulator_list_mutex);
mutex_init(&rdev->mutex);
- rdev->reg_data = reg_data;
+ rdev->reg_data = driver_data;
rdev->owner = regulator_desc->owner;
rdev->desc = regulator_desc;
INIT_LIST_HEAD(&rdev->consumer_list);
@@ -1591,20 +1758,68 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
INIT_LIST_HEAD(&rdev->slist);
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
+ /* preform any regulator specific init */
+ if (init_data->regulator_init) {
+ ret = init_data->regulator_init(rdev->reg_data);
+ if (ret < 0) {
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
+ }
+
+ /* set regulator constraints */
+ ret = set_machine_constraints(rdev, &init_data->constraints);
+ if (ret < 0) {
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
+
+ /* register with sysfs */
rdev->dev.class = &regulator_class;
- device_initialize(&rdev->dev);
+ rdev->dev.parent = dev;
snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id),
- "regulator_%ld_%s",
- (unsigned long)atomic_inc_return(&regulator_no) - 1,
- regulator_desc->name);
-
- ret = device_add(&rdev->dev);
- if (ret == 0)
- list_add(&rdev->list, &regulator_list);
- else {
+ "regulator.%d", atomic_inc_return(&regulator_no) - 1);
+ ret = device_register(&rdev->dev);
+ if (ret != 0) {
kfree(rdev);
rdev = ERR_PTR(ret);
+ goto out;
+ }
+
+ dev_set_drvdata(&rdev->dev, rdev);
+
+ /* set supply regulator if it exists */
+ if (init_data->supply_regulator_dev) {
+ ret = set_supply(rdev,
+ dev_get_drvdata(init_data->supply_regulator_dev));
+ if (ret < 0) {
+ device_unregister(&rdev->dev);
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
}
+
+ /* add consumers devices */
+ for (i = 0; i < init_data->num_consumer_supplies; i++) {
+ ret = set_consumer_device_supply(rdev,
+ init_data->consumer_supplies[i].dev,
+ init_data->consumer_supplies[i].supply);
+ if (ret < 0) {
+ for (--i; i >= 0; i--)
+ unset_consumer_device_supply(rdev,
+ init_data->consumer_supplies[i].dev);
+ device_unregister(&rdev->dev);
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
+ }
+
+ list_add(&rdev->list, &regulator_list);
+out:
mutex_unlock(&regulator_list_mutex);
return rdev;
}
@@ -1631,187 +1846,6 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
/**
- * regulator_set_supply - set regulator supply regulator
- * @regulator: regulator name
- * @supply: supply regulator name
- *
- * Called by platform initialisation code to set the supply regulator for this
- * regulator. This ensures that a regulators supply will also be enabled by the
- * core if it's child is enabled.
- */
-int regulator_set_supply(const char *regulator, const char *supply)
-{
- struct regulator_dev *rdev, *supply_rdev;
- int err;
-
- if (regulator == NULL || supply == NULL)
- return -EINVAL;
-
- mutex_lock(&regulator_list_mutex);
-
- list_for_each_entry(rdev, &regulator_list, list) {
- if (!strcmp(rdev->desc->name, regulator))
- goto found_regulator;
- }
- mutex_unlock(&regulator_list_mutex);
- return -ENODEV;
-
-found_regulator:
- list_for_each_entry(supply_rdev, &regulator_list, list) {
- if (!strcmp(supply_rdev->desc->name, supply))
- goto found_supply;
- }
- mutex_unlock(&regulator_list_mutex);
- return -ENODEV;
-
-found_supply:
- err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
- "supply");
- if (err) {
- printk(KERN_ERR
- "%s: could not add device link %s err %d\n",
- __func__, supply_rdev->dev.kobj.name, err);
- goto out;
- }
- rdev->supply = supply_rdev;
- list_add(&rdev->slist, &supply_rdev->supply_list);
-out:
- mutex_unlock(&regulator_list_mutex);
- return err;
-}
-EXPORT_SYMBOL_GPL(regulator_set_supply);
-
-/**
- * regulator_get_supply - get regulator supply regulator
- * @regulator: regulator name
- *
- * Returns the supply supply regulator name or NULL if no supply regulator
- * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc)
- */
-const char *regulator_get_supply(const char *regulator)
-{
- struct regulator_dev *rdev;
-
- if (regulator == NULL)
- return NULL;
-
- mutex_lock(&regulator_list_mutex);
- list_for_each_entry(rdev, &regulator_list, list) {
- if (!strcmp(rdev->desc->name, regulator))
- goto found;
- }
- mutex_unlock(&regulator_list_mutex);
- return NULL;
-
-found:
- mutex_unlock(&regulator_list_mutex);
- if (rdev->supply)
- return rdev->supply->desc->name;
- else
- return NULL;
-}
-EXPORT_SYMBOL_GPL(regulator_get_supply);
-
-/**
- * regulator_set_machine_constraints - sets regulator constraints
- * @regulator: regulator source
- *
- * Allows platform initialisation code to define and constrain
- * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
- * Constraints *must* be set by platform code in order for some
- * regulator operations to proceed i.e. set_voltage, set_current_limit,
- * set_mode.
- */
-int regulator_set_machine_constraints(const char *regulator_name,
- struct regulation_constraints *constraints)
-{
- struct regulator_dev *rdev;
- int ret = 0;
-
- if (regulator_name == NULL)
- return -EINVAL;
-
- mutex_lock(&regulator_list_mutex);
-
- list_for_each_entry(rdev, &regulator_list, list) {
- if (!strcmp(regulator_name, rdev->desc->name))
- goto found;
- }
- ret = -ENODEV;
- goto out;
-
-found:
- mutex_lock(&rdev->mutex);
- rdev->constraints = constraints;
-
- /* do we need to apply the constraint voltage */
- if (rdev->constraints->apply_uV &&
- rdev->constraints->min_uV == rdev->constraints->max_uV &&
- rdev->desc->ops->set_voltage) {
- ret = rdev->desc->ops->set_voltage(rdev,
- rdev->constraints->min_uV, rdev->constraints->max_uV);
- if (ret < 0) {
- printk(KERN_ERR "%s: failed to apply %duV"
- " constraint\n", __func__,
- rdev->constraints->min_uV);
- rdev->constraints = NULL;
- goto out;
- }
- }
-
- /* are we enabled at boot time by firmware / bootloader */
- if (rdev->constraints->boot_on)
- rdev->use_count = 1;
-
- /* do we need to setup our suspend state */
- if (constraints->initial_state)
- ret = suspend_prepare(rdev, constraints->initial_state);
-
- print_constraints(rdev);
- mutex_unlock(&rdev->mutex);
-
-out:
- mutex_unlock(&regulator_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_set_machine_constraints);
-
-
-/**
- * regulator_set_device_supply: Bind a regulator to a symbolic supply
- * @regulator: regulator source
- * @dev: device the supply applies to
- * @supply: symbolic name for supply
- *
- * Allows platform initialisation code to map physical regulator
- * sources to symbolic names for supplies for use by devices. Devices
- * should use these symbolic names to request regulators, avoiding the
- * need to provide board-specific regulator names as platform data.
- */
-int regulator_set_device_supply(const char *regulator, struct device *dev,
- const char *supply)
-{
- struct regulator_map *node;
-
- if (regulator == NULL || supply == NULL)
- return -EINVAL;
-
- node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
- if (node == NULL)
- return -ENOMEM;
-
- node->regulator = regulator;
- node->dev = dev;
- node->supply = supply;
-
- mutex_lock(&regulator_list_mutex);
- list_add(&node->list, &regulator_map_list);
- mutex_unlock(&regulator_list_mutex);
- return 0;
-}
-EXPORT_SYMBOL_GPL(regulator_set_device_supply);
-
-/**
* regulator_suspend_prepare: prepare regulators for system wide suspend
* @state: system suspend state
*
@@ -1893,6 +1927,18 @@ int rdev_get_id(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL(rdev_get_id);
+struct device *rdev_get_dev(struct regulator_dev *rdev)
+{
+ return &rdev->dev;
+}
+EXPORT_SYMBOL_GPL(rdev_get_dev);
+
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
+{
+ return reg_init_data->driver_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
+
static int __init regulator_init(void)
{
printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
new file mode 100644
index 000000000000..3688e339db87
--- /dev/null
+++ b/drivers/regulator/da903x.c
@@ -0,0 +1,513 @@
+/*
+ * Regulators driver for Dialog Semiconductor DA903x
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 Compulab Ltd.
+ *
+ * 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/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/da903x.h>
+
+/* DA9030 Registers */
+#define DA9030_INVAL (-1)
+#define DA9030_LDO1011 (0x10)
+#define DA9030_LDO15 (0x11)
+#define DA9030_LDO1416 (0x12)
+#define DA9030_LDO1819 (0x13)
+#define DA9030_LDO17 (0x14)
+#define DA9030_BUCK2DVM1 (0x15)
+#define DA9030_BUCK2DVM2 (0x16)
+#define DA9030_RCTL11 (0x17)
+#define DA9030_RCTL21 (0x18)
+#define DA9030_LDO1 (0x90)
+#define DA9030_LDO23 (0x91)
+#define DA9030_LDO45 (0x92)
+#define DA9030_LDO6 (0x93)
+#define DA9030_LDO78 (0x94)
+#define DA9030_LDO912 (0x95)
+#define DA9030_BUCK (0x96)
+#define DA9030_RCTL12 (0x97)
+#define DA9030_RCTL22 (0x98)
+#define DA9030_LDO_UNLOCK (0xa0)
+#define DA9030_LDO_UNLOCK_MASK (0xe0)
+#define DA9034_OVER1 (0x10)
+
+/* DA9034 Registers */
+#define DA9034_INVAL (-1)
+#define DA9034_OVER2 (0x11)
+#define DA9034_OVER3 (0x12)
+#define DA9034_LDO643 (0x13)
+#define DA9034_LDO987 (0x14)
+#define DA9034_LDO1110 (0x15)
+#define DA9034_LDO1312 (0x16)
+#define DA9034_LDO1514 (0x17)
+#define DA9034_VCC1 (0x20)
+#define DA9034_ADTV1 (0x23)
+#define DA9034_ADTV2 (0x24)
+#define DA9034_AVRC (0x25)
+#define DA9034_CDTV1 (0x26)
+#define DA9034_CDTV2 (0x27)
+#define DA9034_CVRC (0x28)
+#define DA9034_SDTV1 (0x29)
+#define DA9034_SDTV2 (0x2a)
+#define DA9034_SVRC (0x2b)
+#define DA9034_MDTV1 (0x32)
+#define DA9034_MDTV2 (0x33)
+#define DA9034_MVRC (0x34)
+
+struct da903x_regulator_info {
+ struct regulator_desc desc;
+
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ int vol_reg;
+ int vol_shift;
+ int vol_nbits;
+ int update_reg;
+ int update_bit;
+ int enable_reg;
+ int enable_bit;
+};
+
+static inline int check_range(struct da903x_regulator_info *info,
+ int min_uV, int max_uV)
+{
+ if (min_uV < info->min_uV || min_uV > info->max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* DA9030/DA9034 common operations */
+static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da903x_get_voltage(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ ret = da903x_read(da9034_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+
+ return info->min_uV + info->step_uV * val;
+}
+
+static int da903x_enable(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+ return da903x_set_bits(da9034_dev, info->enable_reg,
+ 1 << info->enable_bit);
+}
+
+static int da903x_disable(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+ return da903x_clr_bits(da9034_dev, info->enable_reg,
+ 1 << info->enable_bit);
+}
+
+static int da903x_is_enabled(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t reg_val;
+ int ret;
+
+ ret = da903x_read(da9034_dev, info->enable_reg, &reg_val);
+ if (ret)
+ return ret;
+
+ return reg_val & (1 << info->enable_bit);
+}
+
+/* DA9030 specific operations */
+static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */
+ mask |= DA9030_LDO_UNLOCK_MASK;
+
+ /* write twice */
+ ret = da903x_update(da903x_dev, info->vol_reg, val, mask);
+ if (ret)
+ return ret;
+
+ return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int thresh;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ thresh = (info->max_uV + info->min_uV) / 2;
+ if (min_uV < thresh) {
+ val = (thresh - min_uV + info->step_uV - 1) / info->step_uV;
+ val |= 0x4;
+ } else {
+ val = (min_uV - thresh + info->step_uV - 1) / info->step_uV;
+ }
+
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_get_ldo14_voltage(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ ret = da903x_read(da903x_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+
+ if (val & 0x4)
+ return info->min_uV + info->step_uV * (3 - (val & ~0x4));
+ else
+ return (info->max_uV + info->min_uV) / 2 +
+ info->step_uV * (val & ~0x4);
+}
+
+/* DA9034 specific operations */
+static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ ret = da903x_update(da9034_dev, info->vol_reg, val, mask);
+ if (ret)
+ return ret;
+
+ ret = da903x_set_bits(da9034_dev, info->update_reg,
+ 1 << info->update_bit);
+ return ret;
+}
+
+static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val = (val > 7 || val < 20) ? 8 : val - 12;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ ret = da903x_read(da9034_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+
+ if (val >= 8)
+ return 2700000 + info->step_uV * (val - 8);
+
+ return info->min_uV + info->step_uV * val;
+}
+
+static struct regulator_ops da903x_regulator_ldo_ops = {
+ .set_voltage = da903x_set_ldo_voltage,
+ .get_voltage = da903x_get_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane DA9030 LDO14 */
+static struct regulator_ops da9030_regulator_ldo14_ops = {
+ .set_voltage = da9030_set_ldo14_voltage,
+ .get_voltage = da9030_get_ldo14_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks */
+static struct regulator_ops da9030_regulator_ldo1_15_ops = {
+ .set_voltage = da9030_set_ldo1_15_voltage,
+ .get_voltage = da903x_get_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+static struct regulator_ops da9034_regulator_dvc_ops = {
+ .set_voltage = da9034_set_dvc_voltage,
+ .get_voltage = da903x_get_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane LDO12 */
+static struct regulator_ops da9034_regulator_ldo12_ops = {
+ .set_voltage = da9034_set_ldo12_voltage,
+ .get_voltage = da9034_get_ldo12_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+#define DA903x_LDO(_pmic, _id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = "LDO" #_id, \
+ .ops = &da903x_regulator_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _pmic##_ID_LDO##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = _pmic##_##vreg, \
+ .vol_shift = (shift), \
+ .vol_nbits = (nbits), \
+ .enable_reg = _pmic##_##ereg, \
+ .enable_bit = (ebit), \
+}
+
+#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = #_id, \
+ .ops = &da9034_regulator_dvc_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = DA9034_ID_##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = DA9034_##vreg, \
+ .vol_shift = (0), \
+ .vol_nbits = (nbits), \
+ .update_reg = DA9034_##ureg, \
+ .update_bit = (ubit), \
+ .enable_reg = DA9034_##ereg, \
+ .enable_bit = (ebit), \
+}
+
+#define DA9034_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+ DA903x_LDO(DA9034, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+ DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+static struct da903x_regulator_info da903x_regulator_info[] = {
+ /* DA9030 */
+ DA9030_LDO( 1, 1200, 3200, 100, LDO1, 0, 5, RCTL12, 1),
+ DA9030_LDO( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2),
+ DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3),
+ DA9030_LDO( 4, 1800, 3200, 100, LDO45, 0, 4, RCTL12, 4),
+ DA9030_LDO( 5, 1800, 3200, 100, LDO45, 4, 4, RCTL12, 5),
+ DA9030_LDO( 6, 1800, 3200, 100, LDO6, 0, 4, RCTL12, 6),
+ DA9030_LDO( 7, 1800, 3200, 100, LDO78, 0, 4, RCTL12, 7),
+ DA9030_LDO( 8, 1800, 3200, 100, LDO78, 4, 4, RCTL22, 0),
+ DA9030_LDO( 9, 1800, 3200, 100, LDO912, 0, 4, RCTL22, 1),
+ DA9030_LDO(10, 1800, 3200, 100, LDO1011, 0, 4, RCTL22, 2),
+ DA9030_LDO(11, 1800, 3200, 100, LDO1011, 4, 4, RCTL22, 3),
+ DA9030_LDO(12, 1800, 3200, 100, LDO912, 4, 4, RCTL22, 4),
+ DA9030_LDO(14, 2760, 2940, 30, LDO1416, 0, 3, RCTL11, 4),
+ DA9030_LDO(15, 1100, 2650, 50, LDO15, 0, 5, RCTL11, 5),
+ DA9030_LDO(16, 1100, 2650, 50, LDO1416, 3, 5, RCTL11, 6),
+ DA9030_LDO(17, 1800, 3200, 100, LDO17, 0, 4, RCTL11, 7),
+ DA9030_LDO(18, 1800, 3200, 100, LDO1819, 0, 4, RCTL21, 2),
+ DA9030_LDO(19, 1800, 3200, 100, LDO1819, 4, 4, RCTL21, 1),
+ DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */
+
+ /* DA9034 */
+ DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0),
+ DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1),
+ DA9034_DVC(LDO2, 725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2),
+ DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4),
+
+ DA9034_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5),
+ DA9034_LDO( 4, 1800, 2900,1100, LDO643, 4, 1, OVER3, 6),
+ DA9034_LDO( 6, 2500, 2850, 50, LDO643, 5, 3, OVER2, 0),
+ DA9034_LDO( 7, 2700, 3050, 50, LDO987, 0, 3, OVER2, 1),
+ DA9034_LDO( 8, 2700, 2850, 50, LDO987, 3, 2, OVER2, 2),
+ DA9034_LDO( 9, 2700, 3050, 50, LDO987, 5, 3, OVER2, 3),
+ DA9034_LDO(10, 2700, 3050, 50, LDO1110, 0, 3, OVER2, 4),
+ DA9034_LDO(11, 1800, 3300, 100, LDO1110, 4, 4, OVER2, 5),
+ DA9034_LDO(12, 1700, 3050, 50, LDO1312, 0, 4, OVER3, 6),
+ DA9034_LDO(13, 1800, 3300, 100, LDO1312, 4, 4, OVER2, 7),
+ DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0),
+ DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
+ DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */
+};
+
+static inline struct da903x_regulator_info *find_regulator_info(int id)
+{
+ struct da903x_regulator_info *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(da903x_regulator_info); i++) {
+ ri = &da903x_regulator_info[i];
+ if (ri->desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+static int __devinit da903x_regulator_probe(struct platform_device *pdev)
+{
+ struct da903x_regulator_info *ri = NULL;
+ struct regulator_dev *rdev;
+
+ ri = find_regulator_info(pdev->id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+
+ /* Workaround for the weird LDO12 voltage setting */
+ if (ri->desc.id == DA9034_ID_LDO12)
+ ri->desc.ops = &da9034_regulator_ldo12_ops;
+
+ if (ri->desc.id == DA9030_ID_LDO14)
+ ri->desc.ops = &da9030_regulator_ldo14_ops;
+
+ if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
+ ri->desc.ops = &da9030_regulator_ldo1_15_ops;
+
+ rdev = regulator_register(&ri->desc, pdev->dev.parent, ri);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ platform_set_drvdata(pdev, rdev);
+ return 0;
+}
+
+static int __devexit da903x_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+ return 0;
+}
+
+static struct platform_driver da903x_regulator_driver = {
+ .driver = {
+ .name = "da903x-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = da903x_regulator_probe,
+ .remove = da903x_regulator_remove,
+};
+
+static int __init da903x_regulator_init(void)
+{
+ return platform_driver_register(&da903x_regulator_driver);
+}
+module_init(da903x_regulator_init);
+
+static void __exit da903x_regulator_exit(void)
+{
+ platform_driver_unregister(&da903x_regulator_driver);
+}
+module_exit(da903x_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
+ "Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Regulator Driver for Dialog Semiconductor DA903X PMIC");
+MODULE_ALIAS("platform:da903x-regulator");
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
new file mode 100644
index 000000000000..1f44b17e23b1
--- /dev/null
+++ b/drivers/regulator/wm8350-regulator.c
@@ -0,0 +1,1431 @@
+/*
+ * wm8350.c -- Voltage and current regulation for the Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ * linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* Microamps */
+static const int isink_cur[] = {
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 10,
+ 11,
+ 14,
+ 16,
+ 19,
+ 23,
+ 27,
+ 32,
+ 39,
+ 46,
+ 54,
+ 65,
+ 77,
+ 92,
+ 109,
+ 130,
+ 154,
+ 183,
+ 218,
+ 259,
+ 308,
+ 367,
+ 436,
+ 518,
+ 616,
+ 733,
+ 872,
+ 1037,
+ 1233,
+ 1466,
+ 1744,
+ 2073,
+ 2466,
+ 2933,
+ 3487,
+ 4147,
+ 4932,
+ 5865,
+ 6975,
+ 8294,
+ 9864,
+ 11730,
+ 13949,
+ 16589,
+ 19728,
+ 23460,
+ 27899,
+ 33178,
+ 39455,
+ 46920,
+ 55798,
+ 66355,
+ 78910,
+ 93840,
+ 111596,
+ 132710,
+ 157820,
+ 187681,
+ 223191
+};
+
+static int get_isink_val(int min_uA, int max_uA, u16 *setting)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(isink_cur) - 1; i >= 0; i--) {
+ if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) {
+ *setting = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
+{
+ if (val < 16)
+ return (val * 50) + 900;
+ else
+ return ((val - 16) * 100) + 1800;
+
+}
+
+static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
+{
+ if (mV < 1800)
+ return (mV - 900) / 50;
+ else
+ return ((mV - 1800) / 100) + 16;
+}
+
+static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
+{
+ return (val * 25) + 850;
+}
+
+static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
+{
+ return (mV - 850) / 25;
+}
+
+static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
+ int max_uA)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+ u16 val, setting;
+ int ret;
+
+ ret = get_isink_val(min_uA, max_uA, &setting);
+ if (ret != 0)
+ return ret;
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+ ~WM8350_CS1_ISEL_MASK;
+ wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_A,
+ val | setting);
+ break;
+ case WM8350_ISINK_B:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+ ~WM8350_CS1_ISEL_MASK;
+ wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_B,
+ val | setting);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_isink_get_current(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+ u16 val;
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+ WM8350_CS1_ISEL_MASK;
+ break;
+ case WM8350_ISINK_B:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+ WM8350_CS1_ISEL_MASK;
+ break;
+ default:
+ return 0;
+ }
+
+ return (isink_cur[val] + 50) / 100;
+}
+
+/* turn on ISINK followed by DCDC */
+static int wm8350_isink_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ switch (wm8350->pmic.isink_A_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS1_ENA);
+ wm8350_set_bits(wm8350, WM8350_CSA_FLASH_CONTROL,
+ WM8350_CS1_DRIVE);
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_A_dcdc -
+ WM8350_DCDC_1));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case WM8350_ISINK_B:
+ switch (wm8350->pmic.isink_B_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS2_ENA);
+ wm8350_set_bits(wm8350, WM8350_CSB_FLASH_CONTROL,
+ WM8350_CS2_DRIVE);
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_B_dcdc -
+ WM8350_DCDC_1));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_isink_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ switch (wm8350->pmic.isink_A_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_A_dcdc -
+ WM8350_DCDC_1));
+ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS1_ENA);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case WM8350_ISINK_B:
+ switch (wm8350->pmic.isink_B_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_B_dcdc -
+ WM8350_DCDC_1));
+ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS2_ENA);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+ 0x8000;
+ case WM8350_ISINK_B:
+ return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+ 0x8000;
+ }
+ return -EINVAL;
+}
+
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+ u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
+ u16 drive)
+{
+ switch (isink) {
+ case WM8350_ISINK_A:
+ wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
+ (mode ? WM8350_CS1_FLASH_MODE : 0) |
+ (trigger ? WM8350_CS1_TRIGSRC : 0) |
+ duration | on_ramp | off_ramp | drive);
+ break;
+ case WM8350_ISINK_B:
+ wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
+ (mode ? WM8350_CS2_FLASH_MODE : 0) |
+ (trigger ? WM8350_CS2_TRIGSRC : 0) |
+ duration | on_ramp | off_ramp | drive);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
+
+static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, dcdc = rdev_get_id(rdev), mV,
+ min_mV = min_uV / 1000, max_mV = max_uV / 1000;
+ u16 val;
+
+ if (min_mV < 850 || min_mV > 4025)
+ return -EINVAL;
+ if (max_mV < 850 || max_mV > 4025)
+ return -EINVAL;
+
+ /* step size is 25mV */
+ mV = (min_mV - 826) / 25;
+ if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
+ return -EINVAL;
+ BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ volt_reg = WM8350_DCDC1_CONTROL;
+ break;
+ case WM8350_DCDC_3:
+ volt_reg = WM8350_DCDC3_CONTROL;
+ break;
+ case WM8350_DCDC_4:
+ volt_reg = WM8350_DCDC4_CONTROL;
+ break;
+ case WM8350_DCDC_6:
+ volt_reg = WM8350_DCDC6_CONTROL;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ /* all DCDCs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg, val | mV);
+ return 0;
+}
+
+static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ volt_reg = WM8350_DCDC1_CONTROL;
+ break;
+ case WM8350_DCDC_3:
+ volt_reg = WM8350_DCDC3_CONTROL;
+ break;
+ case WM8350_DCDC_4:
+ volt_reg = WM8350_DCDC4_CONTROL;
+ break;
+ case WM8350_DCDC_6:
+ volt_reg = WM8350_DCDC6_CONTROL;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ /* all DCDCs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
+ return wm8350_dcdc_val_to_mvolts(val) * 1000;
+}
+
+static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
+
+ if (mV && (mV < 850 || mV > 4025)) {
+ dev_err(wm8350->dev,
+ "DCDC%d suspend voltage %d mV out of range\n",
+ dcdc, mV);
+ return -EINVAL;
+ }
+ if (mV == 0)
+ mV = 850;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ volt_reg = WM8350_DCDC1_LOW_POWER;
+ break;
+ case WM8350_DCDC_3:
+ volt_reg = WM8350_DCDC3_LOW_POWER;
+ break;
+ case WM8350_DCDC_4:
+ volt_reg = WM8350_DCDC4_LOW_POWER;
+ break;
+ case WM8350_DCDC_6:
+ volt_reg = WM8350_DCDC6_LOW_POWER;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ /* all DCDCs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg,
+ val | wm8350_dcdc_mvolts_to_val(mV));
+ return 0;
+}
+
+static int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+ wm8350->pmic.dcdc1_hib_mode);
+ break;
+ case WM8350_DCDC_3:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+ wm8350->pmic.dcdc3_hib_mode);
+ break;
+ case WM8350_DCDC_4:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+ wm8350->pmic.dcdc4_hib_mode);
+ break;
+ case WM8350_DCDC_6:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+ wm8350->pmic.dcdc6_hib_mode);
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+ wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_3:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+ wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_4:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+ wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_6:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+ wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_2:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+ WM8350_DC2_HIB_MODE_ACTIVE);
+ break;
+ case WM8350_DCDC_5:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+ WM8350_DC5_HIB_MODE_ACTIVE);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_2:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+ WM8350_DC2_HIB_MODE_DISABLE);
+ break;
+ case WM8350_DCDC_5:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+ WM8350_DC2_HIB_MODE_DISABLE);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 *hib_mode;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ hib_mode = &wm8350->pmic.dcdc1_hib_mode;
+ break;
+ case WM8350_DCDC_3:
+ hib_mode = &wm8350->pmic.dcdc3_hib_mode;
+ break;
+ case WM8350_DCDC_4:
+ hib_mode = &wm8350->pmic.dcdc4_hib_mode;
+ break;
+ case WM8350_DCDC_6:
+ hib_mode = &wm8350->pmic.dcdc6_hib_mode;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ *hib_mode = WM8350_DCDC_HIB_MODE_IMAGE;
+ break;
+ case REGULATOR_MODE_IDLE:
+ *hib_mode = WM8350_DCDC_HIB_MODE_STANDBY;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ *hib_mode = WM8350_DCDC_HIB_MODE_LDO_IM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
+
+ if (mV < 900 || mV > 3300) {
+ dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
+ ldo, mV);
+ return -EINVAL;
+ }
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_LOW_POWER;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_LOW_POWER;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_LOW_POWER;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg,
+ val | wm8350_ldo_mvolts_to_val(mV));
+ return 0;
+}
+
+static int wm8350_ldo_set_suspend_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_LOW_POWER;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_LOW_POWER;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_LOW_POWER;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, volt_reg, val);
+ return 0;
+}
+
+static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_LOW_POWER;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_LOW_POWER;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_LOW_POWER;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, volt_reg, WM8350_LDO1_HIB_MODE_DIS);
+ return 0;
+}
+
+static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
+ max_mV = max_uV / 1000;
+ u16 val;
+
+ if (min_mV < 900 || min_mV > 3300)
+ return -EINVAL;
+ if (max_mV < 900 || max_mV > 3300)
+ return -EINVAL;
+
+ if (min_mV < 1800) {
+ /* step size is 50mV < 1800mV */
+ mV = (min_mV - 851) / 50;
+ if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+ return -EINVAL;
+ BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+ } else {
+ /* step size is 100mV > 1800mV */
+ mV = ((min_mV - 1701) / 100) + 16;
+ if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+ return -EINVAL;
+ BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+ }
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_CONTROL;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_CONTROL;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_CONTROL;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_CONTROL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg, val | mV);
+ return 0;
+}
+
+static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_CONTROL;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_CONTROL;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_CONTROL;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_CONTROL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
+ return wm8350_ldo_val_to_mvolts(val) * 1000;
+}
+
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+ u16 stop, u16 fault)
+{
+ int slot_reg;
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+ __func__, dcdc, start, stop);
+
+ /* slot valid ? */
+ if (start > 15 || stop > 15)
+ return -EINVAL;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ slot_reg = WM8350_DCDC1_TIMEOUTS;
+ break;
+ case WM8350_DCDC_2:
+ slot_reg = WM8350_DCDC2_TIMEOUTS;
+ break;
+ case WM8350_DCDC_3:
+ slot_reg = WM8350_DCDC3_TIMEOUTS;
+ break;
+ case WM8350_DCDC_4:
+ slot_reg = WM8350_DCDC4_TIMEOUTS;
+ break;
+ case WM8350_DCDC_5:
+ slot_reg = WM8350_DCDC5_TIMEOUTS;
+ break;
+ case WM8350_DCDC_6:
+ slot_reg = WM8350_DCDC6_TIMEOUTS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = wm8350_reg_read(wm8350, slot_reg) &
+ ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
+ WM8350_DC1_ERRACT_MASK);
+ wm8350_reg_write(wm8350, slot_reg,
+ val | (start << WM8350_DC1_ENSLOT_SHIFT) |
+ (stop << WM8350_DC1_SDSLOT_SHIFT) |
+ (fault << WM8350_DC1_ERRACT_SHIFT));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc_set_slot);
+
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop)
+{
+ int slot_reg;
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+ __func__, ldo, start, stop);
+
+ /* slot valid ? */
+ if (start > 15 || stop > 15)
+ return -EINVAL;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ slot_reg = WM8350_LDO1_TIMEOUTS;
+ break;
+ case WM8350_LDO_2:
+ slot_reg = WM8350_LDO2_TIMEOUTS;
+ break;
+ case WM8350_LDO_3:
+ slot_reg = WM8350_LDO3_TIMEOUTS;
+ break;
+ case WM8350_LDO_4:
+ slot_reg = WM8350_LDO4_TIMEOUTS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = wm8350_reg_read(wm8350, slot_reg) & ~WM8350_LDO1_SDSLOT_MASK;
+ wm8350_reg_write(wm8350, slot_reg, val | ((start << 10) | (stop << 6)));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_ldo_set_slot);
+
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+ u16 ilim, u16 ramp, u16 feedback)
+{
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d mode: %s %s\n", __func__, dcdc,
+ mode ? "normal" : "boost", ilim ? "low" : "normal");
+
+ switch (dcdc) {
+ case WM8350_DCDC_2:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+ & ~(WM8350_DC2_MODE_MASK | WM8350_DC2_ILIM_MASK |
+ WM8350_DC2_RMP_MASK | WM8350_DC2_FBSRC_MASK);
+ wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+ (mode << WM8350_DC2_MODE_SHIFT) |
+ (ilim << WM8350_DC2_ILIM_SHIFT) |
+ (ramp << WM8350_DC2_RMP_SHIFT) |
+ (feedback << WM8350_DC2_FBSRC_SHIFT));
+ break;
+ case WM8350_DCDC_5:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+ & ~(WM8350_DC5_MODE_MASK | WM8350_DC5_ILIM_MASK |
+ WM8350_DC5_RMP_MASK | WM8350_DC5_FBSRC_MASK);
+ wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+ (mode << WM8350_DC5_MODE_SHIFT) |
+ (ilim << WM8350_DC5_ILIM_SHIFT) |
+ (ramp << WM8350_DC5_RMP_SHIFT) |
+ (feedback << WM8350_DC5_FBSRC_SHIFT));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
+
+static int wm8350_dcdc_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 shift;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ shift = dcdc - WM8350_DCDC_1;
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+ return 0;
+}
+
+static int wm8350_dcdc_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 shift;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ shift = dcdc - WM8350_DCDC_1;
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+
+ return 0;
+}
+
+static int wm8350_ldo_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int ldo = rdev_get_id(rdev);
+ u16 shift;
+
+ if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+ return -EINVAL;
+
+ shift = (ldo - WM8350_LDO_1) + 8;
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+ return 0;
+}
+
+static int wm8350_ldo_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int ldo = rdev_get_id(rdev);
+ u16 shift;
+
+ if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+ return -EINVAL;
+
+ shift = (ldo - WM8350_LDO_1) + 8;
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+ return 0;
+}
+
+static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
+{
+ int reg = 0, ret;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ reg = WM8350_DCDC1_FORCE_PWM;
+ break;
+ case WM8350_DCDC_3:
+ reg = WM8350_DCDC3_FORCE_PWM;
+ break;
+ case WM8350_DCDC_4:
+ reg = WM8350_DCDC4_FORCE_PWM;
+ break;
+ case WM8350_DCDC_6:
+ reg = WM8350_DCDC6_FORCE_PWM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (enable)
+ ret = wm8350_set_bits(wm8350, reg,
+ WM8350_DCDC1_FORCE_PWM_ENA);
+ else
+ ret = wm8350_clear_bits(wm8350, reg,
+ WM8350_DCDC1_FORCE_PWM_ENA);
+ return ret;
+}
+
+static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+ return -EINVAL;
+
+ val = 1 << (dcdc - WM8350_DCDC_1);
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ /* force continuous mode */
+ wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ force_continuous_enable(wm8350, dcdc, 1);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ /* active / pulse skipping */
+ wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ force_continuous_enable(wm8350, dcdc, 0);
+ break;
+ case REGULATOR_MODE_IDLE:
+ /* standby mode */
+ force_continuous_enable(wm8350, dcdc, 0);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+ break;
+ case REGULATOR_MODE_STANDBY:
+ /* LDO mode */
+ force_continuous_enable(wm8350, dcdc, 0);
+ wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ break;
+ }
+
+ return 0;
+}
+
+static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 mask, sleep, active, force;
+ int mode = REGULATOR_MODE_NORMAL;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+ return -EINVAL;
+
+ mask = 1 << (dcdc - WM8350_DCDC_1);
+ active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
+ sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
+ force = wm8350_reg_read(wm8350, WM8350_DCDC1_FORCE_PWM)
+ & WM8350_DCDC1_FORCE_PWM_ENA;
+ dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
+ mask, active, sleep, force);
+
+ if (active && !sleep) {
+ if (force)
+ mode = REGULATOR_MODE_FAST;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+ } else if (!active && !sleep)
+ mode = REGULATOR_MODE_IDLE;
+ else if (!sleep)
+ mode = REGULATOR_MODE_STANDBY;
+
+ return mode;
+}
+
+static unsigned int wm8350_ldo_get_mode(struct regulator_dev *rdev)
+{
+ return REGULATOR_MODE_NORMAL;
+}
+
+struct wm8350_dcdc_efficiency {
+ int uA_load_min;
+ int uA_load_max;
+ unsigned int mode;
+};
+
+static const struct wm8350_dcdc_efficiency dcdc1_6_efficiency[] = {
+ {0, 10000, REGULATOR_MODE_STANDBY}, /* 0 - 10mA - LDO */
+ {10000, 100000, REGULATOR_MODE_IDLE}, /* 10mA - 100mA - Standby */
+ {100000, 1000000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+ {-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static const struct wm8350_dcdc_efficiency dcdc3_4_efficiency[] = {
+ {0, 10000, REGULATOR_MODE_STANDBY}, /* 0 - 10mA - LDO */
+ {10000, 100000, REGULATOR_MODE_IDLE}, /* 10mA - 100mA - Standby */
+ {100000, 800000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+ {-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff)
+{
+ int i = 0;
+
+ while (eff[i].uA_load_min != -1) {
+ if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max)
+ return eff[i].mode;
+ }
+ return REGULATOR_MODE_NORMAL;
+}
+
+/* Query the regulator for it's most efficient mode @ uV,uA
+ * WM8350 regulator efficiency is pretty similar over
+ * different input and output uV.
+ */
+static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV,
+ int output_uA)
+{
+ int dcdc = rdev_get_id(rdev), mode;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ case WM8350_DCDC_6:
+ mode = get_mode(output_uA, dcdc1_6_efficiency);
+ break;
+ case WM8350_DCDC_3:
+ case WM8350_DCDC_4:
+ mode = get_mode(output_uA, dcdc3_4_efficiency);
+ break;
+ default:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ }
+ return mode;
+}
+
+static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev), shift;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ shift = dcdc - WM8350_DCDC_1;
+ return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+ & (1 << shift);
+}
+
+static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int ldo = rdev_get_id(rdev), shift;
+
+ if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+ return -EINVAL;
+
+ shift = (ldo - WM8350_LDO_1) + 8;
+ return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+ & (1 << shift);
+}
+
+static struct regulator_ops wm8350_dcdc_ops = {
+ .set_voltage = wm8350_dcdc_set_voltage,
+ .get_voltage = wm8350_dcdc_get_voltage,
+ .enable = wm8350_dcdc_enable,
+ .disable = wm8350_dcdc_disable,
+ .get_mode = wm8350_dcdc_get_mode,
+ .set_mode = wm8350_dcdc_set_mode,
+ .get_optimum_mode = wm8350_dcdc_get_optimum_mode,
+ .is_enabled = wm8350_dcdc_is_enabled,
+ .set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
+ .set_suspend_enable = wm8350_dcdc_set_suspend_enable,
+ .set_suspend_disable = wm8350_dcdc_set_suspend_disable,
+ .set_suspend_mode = wm8350_dcdc_set_suspend_mode,
+};
+
+static struct regulator_ops wm8350_dcdc2_5_ops = {
+ .enable = wm8350_dcdc_enable,
+ .disable = wm8350_dcdc_disable,
+ .is_enabled = wm8350_dcdc_is_enabled,
+ .set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
+ .set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_ldo_ops = {
+ .set_voltage = wm8350_ldo_set_voltage,
+ .get_voltage = wm8350_ldo_get_voltage,
+ .enable = wm8350_ldo_enable,
+ .disable = wm8350_ldo_disable,
+ .is_enabled = wm8350_ldo_is_enabled,
+ .get_mode = wm8350_ldo_get_mode,
+ .set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
+ .set_suspend_enable = wm8350_ldo_set_suspend_enable,
+ .set_suspend_disable = wm8350_ldo_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_isink_ops = {
+ .set_current_limit = wm8350_isink_set_current,
+ .get_current_limit = wm8350_isink_get_current,
+ .enable = wm8350_isink_enable,
+ .disable = wm8350_isink_disable,
+ .is_enabled = wm8350_isink_is_enabled,
+};
+
+static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
+ {
+ .name = "DCDC1",
+ .id = WM8350_DCDC_1,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC1,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC2",
+ .id = WM8350_DCDC_2,
+ .ops = &wm8350_dcdc2_5_ops,
+ .irq = WM8350_IRQ_UV_DC2,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC3",
+ .id = WM8350_DCDC_3,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC3,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC4",
+ .id = WM8350_DCDC_4,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC4,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC5",
+ .id = WM8350_DCDC_5,
+ .ops = &wm8350_dcdc2_5_ops,
+ .irq = WM8350_IRQ_UV_DC5,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC6",
+ .id = WM8350_DCDC_6,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC6,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO1",
+ .id = WM8350_LDO_1,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO1,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO2",
+ .id = WM8350_LDO_2,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO2,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO3",
+ .id = WM8350_LDO_3,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO3,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO4",
+ .id = WM8350_LDO_4,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO4,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ISINKA",
+ .id = WM8350_ISINK_A,
+ .ops = &wm8350_isink_ops,
+ .irq = WM8350_IRQ_CS1,
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ISINKB",
+ .id = WM8350_ISINK_B,
+ .ops = &wm8350_isink_ops,
+ .irq = WM8350_IRQ_CS2,
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+ },
+};
+
+static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+ struct regulator_dev *rdev = (struct regulator_dev *)data;
+
+ if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_REGULATION_OUT,
+ wm8350);
+ else
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_UNDER_VOLTAGE,
+ wm8350);
+}
+
+static int wm8350_regulator_probe(struct platform_device *pdev)
+{
+ struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+ struct regulator_dev *rdev;
+ int ret;
+ u16 val;
+
+ if (pdev->id < WM8350_DCDC_1 || pdev->id > WM8350_ISINK_B)
+ return -ENODEV;
+
+ /* do any regulatior specific init */
+ switch (pdev->id) {
+ case WM8350_DCDC_1:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+ wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ case WM8350_DCDC_3:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+ wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ case WM8350_DCDC_4:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+ wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ case WM8350_DCDC_6:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+ wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ }
+
+
+ /* register regulator */
+ rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
+ dev_get_drvdata(&pdev->dev));
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s\n",
+ wm8350_reg[pdev->id].name);
+ return PTR_ERR(rdev);
+ }
+
+ /* register regulator IRQ */
+ ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
+ pmic_uv_handler, rdev);
+ if (ret < 0) {
+ regulator_unregister(rdev);
+ dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
+ wm8350_reg[pdev->id].name);
+ return ret;
+ }
+
+ wm8350_unmask_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+ return 0;
+}
+
+static int wm8350_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+
+ wm8350_mask_irq(wm8350, wm8350_reg[pdev->id].irq);
+ wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+ struct regulator_init_data *initdata)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ if (wm8350->pmic.pdev[reg])
+ return -EBUSY;
+
+ pdev = platform_device_alloc("wm8350-regulator", reg);
+ if (!pdev)
+ return -ENOMEM;
+
+ wm8350->pmic.pdev[reg] = pdev;
+
+ initdata->driver_data = wm8350;
+
+ pdev->dev.platform_data = initdata;
+ pdev->dev.parent = wm8350->dev;
+ platform_set_drvdata(pdev, wm8350);
+
+ ret = platform_device_add(pdev);
+
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Failed to register regulator %d: %d\n",
+ reg, ret);
+ platform_device_del(pdev);
+ wm8350->pmic.pdev[reg] = NULL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_regulator);
+
+static struct platform_driver wm8350_regulator_driver = {
+ .probe = wm8350_regulator_probe,
+ .remove = wm8350_regulator_remove,
+ .driver = {
+ .name = "wm8350-regulator",
+ },
+};
+
+static int __init wm8350_regulator_init(void)
+{
+ return platform_driver_register(&wm8350_regulator_driver);
+}
+subsys_initcall(wm8350_regulator_init);
+
+static void __exit wm8350_regulator_exit(void)
+{
+ platform_driver_unregister(&wm8350_regulator_driver);
+}
+module_exit(wm8350_regulator_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
new file mode 100644
index 000000000000..48b372e038a8
--- /dev/null
+++ b/drivers/regulator/wm8400-regulator.c
@@ -0,0 +1,368 @@
+/*
+ * Regulator support for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/wm8400-private.h>
+
+static int wm8400_ldo_is_enabled(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+
+ val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+ return (val & WM8400_LDO1_ENA) != 0;
+}
+
+static int wm8400_ldo_enable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+ return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+ WM8400_LDO1_ENA, WM8400_LDO1_ENA);
+}
+
+static int wm8400_ldo_disable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+ return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+ WM8400_LDO1_ENA, 0);
+}
+
+static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+
+ val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+ val &= WM8400_LDO1_VSEL_MASK;
+
+ if (val < 15)
+ return 900000 + (val * 50000);
+ else
+ return 1600000 + ((val - 14) * 100000);
+}
+
+static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+
+ if (min_uV < 900000 || min_uV > 3300000)
+ return -EINVAL;
+
+ if (min_uV < 1700000) {
+ /* Steps of 50mV from 900mV; */
+ val = (min_uV - 850001) / 50000;
+
+ if ((val * 50000) + 900000 > max_uV)
+ return -EINVAL;
+ BUG_ON((val * 50000) + 900000 < min_uV);
+ } else {
+ /* Steps of 100mV from 1700mV */
+ val = ((min_uV - 1600001) / 100000);
+
+ if ((val * 100000) + 1700000 > max_uV)
+ return -EINVAL;
+ BUG_ON((val * 100000) + 1700000 < min_uV);
+
+ val += 0xf;
+ }
+
+ return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+ WM8400_LDO1_VSEL_MASK, val);
+}
+
+static struct regulator_ops wm8400_ldo_ops = {
+ .is_enabled = wm8400_ldo_is_enabled,
+ .enable = wm8400_ldo_enable,
+ .disable = wm8400_ldo_disable,
+ .get_voltage = wm8400_ldo_get_voltage,
+ .set_voltage = wm8400_ldo_set_voltage,
+};
+
+static int wm8400_dcdc_is_enabled(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+ u16 val;
+
+ val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+ return (val & WM8400_DC1_ENA) != 0;
+}
+
+static int wm8400_dcdc_enable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ENA, WM8400_DC1_ENA);
+}
+
+static int wm8400_dcdc_disable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ENA, 0);
+}
+
+static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+ val &= WM8400_DC1_VSEL_MASK;
+
+ return 850000 + (25000 * val);
+}
+
+static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ if (min_uV < 850000)
+ return -EINVAL;
+
+ val = (min_uV - 825001) / 25000;
+
+ if (850000 + (25000 * val) > max_uV)
+ return -EINVAL;
+ BUG_ON(850000 + (25000 * val) < min_uV);
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_VSEL_MASK, val);
+}
+
+static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+ u16 data[2];
+ int ret;
+
+ ret = wm8400_block_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset, 2,
+ data);
+ if (ret != 0)
+ return 0;
+
+ /* Datasheet: hibernate */
+ if (data[0] & WM8400_DC1_SLEEP)
+ return REGULATOR_MODE_STANDBY;
+
+ /* Datasheet: standby */
+ if (!(data[0] & WM8400_DC1_ACTIVE))
+ return REGULATOR_MODE_IDLE;
+
+ /* Datasheet: active with or without force PWM */
+ if (data[1] & WM8400_DC1_FRC_PWM)
+ return REGULATOR_MODE_FAST;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+ int ret;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ /* Datasheet: active with force PWM */
+ ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+ WM8400_DC1_FRC_PWM, WM8400_DC1_FRC_PWM);
+ if (ret != 0)
+ return ret;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+ WM8400_DC1_ACTIVE);
+
+ case REGULATOR_MODE_NORMAL:
+ /* Datasheet: active */
+ ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+ WM8400_DC1_FRC_PWM, 0);
+ if (ret != 0)
+ return ret;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+ WM8400_DC1_ACTIVE);
+
+ case REGULATOR_MODE_IDLE:
+ /* Datasheet: standby */
+ ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ACTIVE, 0);
+ if (ret != 0)
+ return ret;
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_SLEEP, 0);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
+ int input_uV, int output_uV,
+ int load_uA)
+{
+ return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops wm8400_dcdc_ops = {
+ .is_enabled = wm8400_dcdc_is_enabled,
+ .enable = wm8400_dcdc_enable,
+ .disable = wm8400_dcdc_disable,
+ .get_voltage = wm8400_dcdc_get_voltage,
+ .set_voltage = wm8400_dcdc_set_voltage,
+ .get_mode = wm8400_dcdc_get_mode,
+ .set_mode = wm8400_dcdc_set_mode,
+ .get_optimum_mode = wm8400_dcdc_get_optimum_mode,
+};
+
+static struct regulator_desc regulators[] = {
+ {
+ .name = "LDO1",
+ .id = WM8400_LDO1,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO2",
+ .id = WM8400_LDO2,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO3",
+ .id = WM8400_LDO3,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO4",
+ .id = WM8400_LDO4,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC1",
+ .id = WM8400_DCDC1,
+ .ops = &wm8400_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC2",
+ .id = WM8400_DCDC2,
+ .ops = &wm8400_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wm8400_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+
+ rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+ pdev->dev.driver_data);
+
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ return 0;
+}
+
+static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+static struct platform_driver wm8400_regulator_driver = {
+ .driver = {
+ .name = "wm8400-regulator",
+ },
+ .probe = wm8400_regulator_probe,
+ .remove = __devexit_p(wm8400_regulator_remove),
+};
+
+/**
+ * wm8400_register_regulator - enable software control of a WM8400 regulator
+ *
+ * This function enables software control of a WM8400 regulator via
+ * the regulator API. It is intended to be called from the
+ * platform_init() callback of the WM8400 MFD driver.
+ *
+ * @param dev The WM8400 device to operate on.
+ * @param reg The regulator to control.
+ * @param initdata Regulator initdata for the regulator.
+ */
+int wm8400_register_regulator(struct device *dev, int reg,
+ struct regulator_init_data *initdata)
+{
+ struct wm8400 *wm8400 = dev->driver_data;
+
+ if (wm8400->regulators[reg].name)
+ return -EBUSY;
+
+ initdata->driver_data = wm8400;
+
+ wm8400->regulators[reg].name = "wm8400-regulator";
+ wm8400->regulators[reg].id = reg;
+ wm8400->regulators[reg].dev.parent = dev;
+ wm8400->regulators[reg].dev.driver_data = wm8400;
+ wm8400->regulators[reg].dev.platform_data = initdata;
+
+ return platform_device_register(&wm8400->regulators[reg]);
+}
+EXPORT_SYMBOL_GPL(wm8400_register_regulator);
+
+static int __init wm8400_regulator_init(void)
+{
+ return platform_driver_register(&wm8400_regulator_driver);
+}
+module_init(wm8400_regulator_init);
+
+static void __exit wm8400_regulator_exit(void)
+{
+ platform_driver_unregister(&wm8400_regulator_driver);
+}
+module_exit(wm8400_regulator_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8400 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-regulator");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index b23af0c2a869..963ad0b6a4e9 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -913,6 +913,92 @@ static inline int cmos_poweroff(struct device *dev)
* predate even PNPBIOS should set up platform_bus devices.
*/
+#ifdef CONFIG_ACPI
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_PM
+static u32 rtc_handler(void *context)
+{
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+ return ACPI_INTERRUPT_HANDLED;
+}
+
+static inline void rtc_wake_setup(void)
+{
+ acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+ /*
+ * After the RTC handler is installed, the Fixed_RTC event should
+ * be disabled. Only when the RTC alarm is set will it be enabled.
+ */
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_on(struct device *dev)
+{
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_enable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_off(struct device *dev)
+{
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+#else
+#define rtc_wake_setup() do{}while(0)
+#define rtc_wake_on NULL
+#define rtc_wake_off NULL
+#endif
+
+/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
+ * its device node and pass extra config data. This helps its driver use
+ * capabilities that the now-obsolete mc146818 didn't have, and informs it
+ * that this board's RTC is wakeup-capable (per ACPI spec).
+ */
+static struct cmos_rtc_board_info acpi_rtc_info;
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+ if (acpi_disabled)
+ return;
+
+ rtc_wake_setup();
+ acpi_rtc_info.wake_on = rtc_wake_on;
+ acpi_rtc_info.wake_off = rtc_wake_off;
+
+ /* workaround bug in some ACPI tables */
+ if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
+ dev_dbg(dev, "bogus FADT month_alarm (%d)\n",
+ acpi_gbl_FADT.month_alarm);
+ acpi_gbl_FADT.month_alarm = 0;
+ }
+
+ acpi_rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
+ acpi_rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
+ acpi_rtc_info.rtc_century = acpi_gbl_FADT.century;
+
+ /* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */
+ if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
+ dev_info(dev, "RTC can wake from S4\n");
+
+ dev->platform_data = &acpi_rtc_info;
+
+ /* RTC always wakes from S1/S2/S3, and often S4/STD */
+ device_init_wakeup(dev, 1);
+}
+
+#else
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+}
+
+#endif
+
#ifdef CONFIG_PNP
#include <linux/pnp.h>
@@ -920,6 +1006,8 @@ static inline int cmos_poweroff(struct device *dev)
static int __devinit
cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{
+ cmos_wake_setup(&pnp->dev);
+
if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
/* Some machines contain a PNP entry for the RTC, but
* don't define the IRQ. It should always be safe to
@@ -997,6 +1085,7 @@ static struct pnp_driver cmos_pnp_driver = {
static int __init cmos_platform_probe(struct platform_device *pdev)
{
+ cmos_wake_setup(&pdev->dev);
return cmos_do_probe(&pdev->dev,
platform_get_resource(pdev, IORESOURCE_IO, 0),
platform_get_irq(pdev, 0));
@@ -1031,29 +1120,32 @@ static struct platform_driver cmos_platform_driver = {
static int __init cmos_init(void)
{
+ int retval = 0;
+
#ifdef CONFIG_PNP
- if (pnp_platform_devices)
- return pnp_register_driver(&cmos_pnp_driver);
- else
- return platform_driver_probe(&cmos_platform_driver,
- cmos_platform_probe);
-#else
- return platform_driver_probe(&cmos_platform_driver,
- cmos_platform_probe);
-#endif /* CONFIG_PNP */
+ pnp_register_driver(&cmos_pnp_driver);
+#endif
+
+ if (!cmos_rtc.dev)
+ retval = platform_driver_probe(&cmos_platform_driver,
+ cmos_platform_probe);
+
+ if (retval == 0)
+ return 0;
+
+#ifdef CONFIG_PNP
+ pnp_unregister_driver(&cmos_pnp_driver);
+#endif
+ return retval;
}
module_init(cmos_init);
static void __exit cmos_exit(void)
{
#ifdef CONFIG_PNP
- if (pnp_platform_devices)
- pnp_unregister_driver(&cmos_pnp_driver);
- else
- platform_driver_unregister(&cmos_platform_driver);
-#else
+ pnp_unregister_driver(&cmos_pnp_driver);
+#endif
platform_driver_unregister(&cmos_platform_driver);
-#endif /* CONFIG_PNP */
}
module_exit(cmos_exit);
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 8f83fc994f50..f5e618562c5f 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -2913,7 +2913,7 @@ claw_new_device(struct ccwgroup_device *cgdev)
if (ret != 0) {
printk(KERN_WARNING
"claw: ccw_device_set_online %s WRITE failed "
- "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev)
+ "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev),
ret);
goto out;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d3b211af4e1c..403ecad48d4b 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1640,6 +1640,7 @@ config ATARI_SCSI
tristate "Atari native SCSI support"
depends on ATARI && SCSI
select SCSI_SPI_ATTRS
+ select NVRAM
---help---
If you have an Atari with built-in NCR5380 SCSI controller (TT,
Falcon, ...) say Y to get it supported. Of course also, if you have
@@ -1670,14 +1671,6 @@ config ATARI_SCSI_RESET_BOOT
boot process fractionally longer but may assist recovery from errors
that leave the devices with SCSI operations partway completed.
-config TT_DMA_EMUL
- bool "Hades SCSI DMA emulator"
- depends on ATARI_SCSI && HADES
- help
- This option enables code which emulates the TT SCSI DMA chip on the
- Hades. This increases the SCSI transfer rates at least ten times
- compared to PIO transfers.
-
config MAC_SCSI
bool "Macintosh NCR5380 SCSI"
depends on MAC && SCSI=y
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
deleted file mode 100644
index cdc710ea00fa..000000000000
--- a/drivers/scsi/atari_dma_emul.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * atari_dma_emul.c -- TT SCSI DMA emulator for the Hades.
- *
- * Copyright 1997 Wout Klaren <W.Klaren@inter.nl.net>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- * This code was written using the Hades TOS source code as a
- * reference. This source code can be found on the home page
- * of Medusa Computer Systems.
- *
- * Version 0.1, 1997-09-24.
- *
- * This code should be considered experimental. It has only been
- * tested on a Hades with a 68060. It might not work on a Hades
- * with a 68040. Make backups of your hard drives before using
- * this code.
- */
-
-#include <linux/compiler.h>
-#include <asm/thread_info.h>
-#include <asm/uaccess.h>
-
-#define hades_dma_ctrl (*(unsigned char *) 0xffff8717)
-#define hades_psdm_reg (*(unsigned char *) 0xffff8741)
-
-#define TRANSFER_SIZE 16
-
-struct m68040_frame {
- unsigned long effaddr; /* effective address */
- unsigned short ssw; /* special status word */
- unsigned short wb3s; /* write back 3 status */
- unsigned short wb2s; /* write back 2 status */
- unsigned short wb1s; /* write back 1 status */
- unsigned long faddr; /* fault address */
- unsigned long wb3a; /* write back 3 address */
- unsigned long wb3d; /* write back 3 data */
- unsigned long wb2a; /* write back 2 address */
- unsigned long wb2d; /* write back 2 data */
- unsigned long wb1a; /* write back 1 address */
- unsigned long wb1dpd0; /* write back 1 data/push data 0*/
- unsigned long pd1; /* push data 1*/
- unsigned long pd2; /* push data 2*/
- unsigned long pd3; /* push data 3*/
-};
-
-static void writeback (unsigned short wbs, unsigned long wba,
- unsigned long wbd, void *old_buserr)
-{
- mm_segment_t fs = get_fs();
- static void *save_buserr;
-
- __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
- "move.l %0,8(%%a0)\n\t"
- :
- : "r" (&&bus_error)
- : "a0" );
-
- save_buserr = old_buserr;
-
- set_fs (MAKE_MM_SEG(wbs & WBTM_040));
-
- switch (wbs & WBSIZ_040) {
- case BA_SIZE_BYTE:
- put_user (wbd & 0xff, (char *)wba);
- break;
- case BA_SIZE_WORD:
- put_user (wbd & 0xffff, (short *)wba);
- break;
- case BA_SIZE_LONG:
- put_user (wbd, (int *)wba);
- break;
- }
-
- set_fs (fs);
- return;
-
-bus_error:
- __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
- "bcs.s .jump_old\n\t"
- "cmp.l %1,2(%%sp)\n\t"
- "bls.s .restore_old\n"
- ".jump_old:\n\t"
- "move.l %2,-(%%sp)\n\t"
- "rts\n"
- ".restore_old:\n\t"
- "move.l %%a0,-(%%sp)\n\t"
- "movec.l %%vbr,%%a0\n\t"
- "move.l %2,8(%%a0)\n\t"
- "move.l (%%sp)+,%%a0\n\t"
- "rte\n\t"
- :
- : "i" (writeback), "i" (&&bus_error),
- "m" (save_buserr) );
-}
-
-/*
- * static inline void set_restdata_reg(unsigned char *cur_addr)
- *
- * Set the rest data register if necessary.
- */
-
-static inline void set_restdata_reg(unsigned char *cur_addr)
-{
- if (((long) cur_addr & ~3) != 0)
- tt_scsi_dma.dma_restdata =
- *((unsigned long *) ((long) cur_addr & ~3));
-}
-
-/*
- * void hades_dma_emulator(int irq, void *dummy)
- *
- * This code emulates TT SCSI DMA on the Hades.
- *
- * Note the following:
- *
- * 1. When there is no byte available to read from the SCSI bus, or
- * when a byte cannot yet bet written to the SCSI bus, a bus
- * error occurs when reading or writing the pseudo DMA data
- * register (hades_psdm_reg). We have to catch this bus error
- * and try again to read or write the byte. If after several tries
- * we still get a bus error, the interrupt handler is left. When
- * the byte can be read or written, the interrupt handler is
- * called again.
- *
- * 2. The SCSI interrupt must be disabled in this interrupt handler.
- *
- * 3. If we set the EOP signal, the SCSI controller still expects one
- * byte to be read or written. Therefore the last byte is transferred
- * separately, after setting the EOP signal.
- *
- * 4. When this function is left, the address pointer (start_addr) is
- * converted to a physical address. Because it points one byte
- * further than the last transferred byte, it can point outside the
- * current page. If virt_to_phys() is called with this address we
- * might get an access error. Therefore virt_to_phys() is called with
- * start_addr - 1 if the count has reached zero. The result is
- * increased with one.
- */
-
-static irqreturn_t hades_dma_emulator(int irq, void *dummy)
-{
- unsigned long dma_base;
- register unsigned long dma_cnt asm ("d3");
- static long save_buserr;
- register unsigned long save_sp asm ("d4");
- register int tries asm ("d5");
- register unsigned char *start_addr asm ("a3"), *end_addr asm ("a4");
- register unsigned char *eff_addr;
- register unsigned char *psdm_reg;
- unsigned long rem;
-
- atari_disable_irq(IRQ_TT_MFP_SCSI);
-
- /*
- * Read the dma address and count registers.
- */
-
- dma_base = SCSI_DMA_READ_P(dma_addr);
- dma_cnt = SCSI_DMA_READ_P(dma_cnt);
-
- /*
- * Check if DMA is still enabled.
- */
-
- if ((tt_scsi_dma.dma_ctrl & 2) == 0)
- {
- atari_enable_irq(IRQ_TT_MFP_SCSI);
- return IRQ_HANDLED;
- }
-
- if (dma_cnt == 0)
- {
- printk(KERN_NOTICE "DMA emulation: count is zero.\n");
- tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
- atari_enable_irq(IRQ_TT_MFP_SCSI);
- return IRQ_HANDLED;
- }
-
- /*
- * Install new bus error routine.
- */
-
- __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
- "move.l 8(%%a0),%0\n\t"
- "move.l %1,8(%%a0)\n\t"
- : "=&r" (save_buserr)
- : "r" (&&scsi_bus_error)
- : "a0" );
-
- hades_dma_ctrl &= 0xfc; /* Bus error and EOP off. */
-
- /*
- * Save the stack pointer.
- */
-
- __asm__ __volatile__ ("move.l %%sp,%0\n\t"
- : "=&r" (save_sp) );
-
- tries = 100; /* Maximum number of bus errors. */
- start_addr = phys_to_virt(dma_base);
- end_addr = start_addr + dma_cnt;
-
-scsi_loop:
- dma_cnt--;
- rem = dma_cnt & (TRANSFER_SIZE - 1);
- dma_cnt &= ~(TRANSFER_SIZE - 1);
- psdm_reg = &hades_psdm_reg;
-
- if (tt_scsi_dma.dma_ctrl & 1) /* Read or write? */
- {
- /*
- * SCSI write. Abort when count is zero.
- */
-
- switch (rem)
- {
- case 0:
- while (dma_cnt > 0)
- {
- dma_cnt -= TRANSFER_SIZE;
-
- *psdm_reg = *start_addr++;
- case 15:
- *psdm_reg = *start_addr++;
- case 14:
- *psdm_reg = *start_addr++;
- case 13:
- *psdm_reg = *start_addr++;
- case 12:
- *psdm_reg = *start_addr++;
- case 11:
- *psdm_reg = *start_addr++;
- case 10:
- *psdm_reg = *start_addr++;
- case 9:
- *psdm_reg = *start_addr++;
- case 8:
- *psdm_reg = *start_addr++;
- case 7:
- *psdm_reg = *start_addr++;
- case 6:
- *psdm_reg = *start_addr++;
- case 5:
- *psdm_reg = *start_addr++;
- case 4:
- *psdm_reg = *start_addr++;
- case 3:
- *psdm_reg = *start_addr++;
- case 2:
- *psdm_reg = *start_addr++;
- case 1:
- *psdm_reg = *start_addr++;
- }
- }
-
- hades_dma_ctrl |= 1; /* Set EOP. */
- udelay(10);
- *psdm_reg = *start_addr++; /* Dummy byte. */
- tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
- }
- else
- {
- /*
- * SCSI read. Abort when count is zero.
- */
-
- switch (rem)
- {
- case 0:
- while (dma_cnt > 0)
- {
- dma_cnt -= TRANSFER_SIZE;
-
- *start_addr++ = *psdm_reg;
- case 15:
- *start_addr++ = *psdm_reg;
- case 14:
- *start_addr++ = *psdm_reg;
- case 13:
- *start_addr++ = *psdm_reg;
- case 12:
- *start_addr++ = *psdm_reg;
- case 11:
- *start_addr++ = *psdm_reg;
- case 10:
- *start_addr++ = *psdm_reg;
- case 9:
- *start_addr++ = *psdm_reg;
- case 8:
- *start_addr++ = *psdm_reg;
- case 7:
- *start_addr++ = *psdm_reg;
- case 6:
- *start_addr++ = *psdm_reg;
- case 5:
- *start_addr++ = *psdm_reg;
- case 4:
- *start_addr++ = *psdm_reg;
- case 3:
- *start_addr++ = *psdm_reg;
- case 2:
- *start_addr++ = *psdm_reg;
- case 1:
- *start_addr++ = *psdm_reg;
- }
- }
-
- hades_dma_ctrl |= 1; /* Set EOP. */
- udelay(10);
- *start_addr++ = *psdm_reg;
- tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
-
- set_restdata_reg(start_addr);
- }
-
- if (start_addr != end_addr)
- printk(KERN_CRIT "DMA emulation: FATAL: Count is not zero at end of transfer.\n");
-
- dma_cnt = end_addr - start_addr;
-
-scsi_end:
- dma_base = (dma_cnt == 0) ? virt_to_phys(start_addr - 1) + 1 :
- virt_to_phys(start_addr);
-
- SCSI_DMA_WRITE_P(dma_addr, dma_base);
- SCSI_DMA_WRITE_P(dma_cnt, dma_cnt);
-
- /*
- * Restore old bus error routine.
- */
-
- __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
- "move.l %0,8(%%a0)\n\t"
- :
- : "r" (save_buserr)
- : "a0" );
-
- atari_enable_irq(IRQ_TT_MFP_SCSI);
-
- return IRQ_HANDLED;
-
-scsi_bus_error:
- /*
- * First check if the bus error is caused by our code.
- * If not, call the original handler.
- */
-
- __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
- "bcs.s .old_vector\n\t"
- "cmp.l %1,2(%%sp)\n\t"
- "bls.s .scsi_buserr\n"
- ".old_vector:\n\t"
- "move.l %2,-(%%sp)\n\t"
- "rts\n"
- ".scsi_buserr:\n\t"
- :
- : "i" (&&scsi_loop), "i" (&&scsi_end),
- "m" (save_buserr) );
-
- if (CPU_IS_060)
- {
- /*
- * Get effective address and restore the stack.
- */
-
- __asm__ __volatile__ ("move.l 8(%%sp),%0\n\t"
- "move.l %1,%%sp\n\t"
- : "=a&" (eff_addr)
- : "r" (save_sp) );
- }
- else
- {
- register struct m68040_frame *frame;
-
- __asm__ __volatile__ ("lea 8(%%sp),%0\n\t"
- : "=a&" (frame) );
-
- if (tt_scsi_dma.dma_ctrl & 1)
- {
- /*
- * Bus error while writing.
- */
-
- if (frame->wb3s & WBV_040)
- {
- if (frame->wb3a == (long) &hades_psdm_reg)
- start_addr--;
- else
- writeback(frame->wb3s, frame->wb3a,
- frame->wb3d, &&scsi_bus_error);
- }
-
- if (frame->wb2s & WBV_040)
- {
- if (frame->wb2a == (long) &hades_psdm_reg)
- start_addr--;
- else
- writeback(frame->wb2s, frame->wb2a,
- frame->wb2d, &&scsi_bus_error);
- }
-
- if (frame->wb1s & WBV_040)
- {
- if (frame->wb1a == (long) &hades_psdm_reg)
- start_addr--;
- }
- }
- else
- {
- /*
- * Bus error while reading.
- */
-
- if (frame->wb3s & WBV_040)
- writeback(frame->wb3s, frame->wb3a,
- frame->wb3d, &&scsi_bus_error);
- }
-
- eff_addr = (unsigned char *) frame->faddr;
-
- __asm__ __volatile__ ("move.l %0,%%sp\n\t"
- :
- : "r" (save_sp) );
- }
-
- dma_cnt = end_addr - start_addr;
-
- if (eff_addr == &hades_psdm_reg)
- {
- /*
- * Bus error occurred while reading the pseudo
- * DMA register. Time out.
- */
-
- tries--;
-
- if (tries <= 0)
- {
- if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
- set_restdata_reg(start_addr);
-
- if (dma_cnt <= 1)
- printk(KERN_CRIT "DMA emulation: Fatal "
- "error while %s the last byte.\n",
- (tt_scsi_dma.dma_ctrl & 1)
- ? "writing" : "reading");
-
- goto scsi_end;
- }
- else
- goto scsi_loop;
- }
- else
- {
- /*
- * Bus error during pseudo DMA transfer.
- * Terminate the DMA transfer.
- */
-
- hades_dma_ctrl |= 3; /* Set EOP and bus error. */
- if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
- set_restdata_reg(start_addr);
- goto scsi_end;
- }
-}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index f5732d8f67fe..21fe07f9df87 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -249,10 +249,6 @@ static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-#if defined(CONFIG_TT_DMA_EMUL)
-#include "atari_dma_emul.c"
-#endif
-
#if defined(REAL_DMA)
static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
@@ -695,21 +691,8 @@ int atari_scsi_detect(struct scsi_host_template *host)
#ifdef REAL_DMA
tt_scsi_dma.dma_ctrl = 0;
atari_dma_residual = 0;
-#ifdef CONFIG_TT_DMA_EMUL
- if (MACH_IS_HADES) {
- if (request_irq(IRQ_AUTO_2, hades_dma_emulator,
- IRQ_TYPE_PRIO, "Hades DMA emulator",
- hades_dma_emulator)) {
- printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting (MACH_IS_HADES)",IRQ_AUTO_2);
- free_irq(IRQ_TT_MFP_SCSI, instance);
- scsi_unregister(atari_scsi_host);
- atari_stram_free(atari_dma_buffer);
- atari_dma_buffer = 0;
- return 0;
- }
- }
-#endif
- if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+
+ if (MACH_IS_MEDUSA) {
/* While the read overruns (described by Drew Eckhardt in
* NCR5380.c) never happened on TTs, they do in fact on the Medusa
* (This was the cause why SCSI didn't work right for so long
@@ -1007,11 +990,7 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
Scsi_Cmnd *cmd, int write_flag)
{
unsigned long possible_len, limit;
-#ifndef CONFIG_TT_DMA_EMUL
- if (MACH_IS_HADES)
- /* Hades has no SCSI DMA at all :-( Always force use of PIO */
- return 0;
-#endif
+
if (IS_A_TT())
/* TT SCSI DMA can transfer arbitrary #bytes */
return wanted_len;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index d4104a3bbe87..d3ca7d32abe0 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2969,6 +2969,9 @@ static int __init serial8250_init(void)
"%d ports, IRQ sharing %sabled\n", nr_uarts,
share_irqs ? "en" : "dis");
+ for (i = 0; i < NR_IRQS; i++)
+ spin_lock_init(&irq_lists[i].lock);
+
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
#else
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 9cbff84b787d..da91bb16da8a 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1855,8 +1855,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num];
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
- unsigned short saved_ec;
- int ret;
if (fbcon_is_inactive(vc, info))
return -EINVAL;
@@ -1869,11 +1867,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
* whole screen (prevents flicker).
*/
- saved_ec = vc->vc_video_erase_char;
- vc->vc_video_erase_char = vc->vc_scrl_erase_char;
-
- ret = 0;
-
switch (dir) {
case SM_UP:
if (count > vc->vc_rows) /* Maximum realistic size */
@@ -1890,9 +1883,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
+ return 1;
break;
case SCROLL_WRAP_MOVE:
@@ -1962,10 +1955,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
- break;
+ return 1;
}
break;
@@ -1982,9 +1974,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
+ return 1;
break;
case SCROLL_WRAP_MOVE:
@@ -2052,15 +2044,12 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
- break;
+ return 1;
}
- break;
}
- vc->vc_video_erase_char = saved_ec;
- return ret;
+ return 0;
}
@@ -2522,9 +2511,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
c = vc->vc_video_erase_char;
vc->vc_video_erase_char =
((c & 0xfe00) >> 1) | (c & 0xff);
- c = vc->vc_scrl_erase_char;
- vc->vc_scrl_erase_char =
- ((c & 0xFE00) >> 1) | (c & 0xFF);
vc->vc_attr >>= 1;
}
} else if (!vc->vc_hi_font_mask && cnt == 512) {
@@ -2555,14 +2541,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
if (vc->vc_can_do_color) {
vc->vc_video_erase_char =
((c & 0xff00) << 1) | (c & 0xff);
- c = vc->vc_scrl_erase_char;
- vc->vc_scrl_erase_char =
- ((c & 0xFF00) << 1) | (c & 0xFF);
vc->vc_attr <<= 1;
- } else {
+ } else
vc->vc_video_erase_char = c & ~0x100;
- vc->vc_scrl_erase_char = c & ~0x100;
- }
}
}
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 9901064199bd..dd3eaaad4441 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -533,7 +533,7 @@ static void mdacon_cursor(struct vc_data *c, int mode)
static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
{
- u16 eattr = mda_convert_attr(c->vc_scrl_erase_char);
+ u16 eattr = mda_convert_attr(c->vc_video_erase_char);
if (!lines)
return 0;
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 4055dbdd1b42..491c1c1baf4c 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
switch (dir) {
case SM_UP:
sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+ sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
break;
case SM_DOWN:
sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+ sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
break;
}
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index bd1f57b259d9..6df29a62d720 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1350,7 +1350,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
} else
c->vc_origin += delta;
scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
- delta), c->vc_scrl_erase_char,
+ delta), c->vc_video_erase_char,
delta);
} else {
if (oldo - delta < vga_vram_base) {
@@ -1363,7 +1363,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
} else
c->vc_origin -= delta;
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
- scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char,
+ scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
delta);
}
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;