From 0c8a601678960fbcc1c1185a283d6d107575810b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 8 Nov 2008 01:10:16 +0100 Subject: mfd: Add WM8350 revision H support No other software changes are required. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- include/linux/mfd/wm8350/core.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/mfd/wm8350') diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 6ebf97f2a475..9490ec175d5a 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -536,6 +536,7 @@ #define WM8350_REV_E 0x4 #define WM8350_REV_F 0x5 #define WM8350_REV_G 0x6 +#define WM8350_REV_H 0x7 #define WM8350_NUM_IRQ 63 -- cgit v1.2.3 From 67488526349d043372d141c054f4dc6313780b3c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 8 Nov 2008 01:10:21 +0100 Subject: mfd: Add AUXADC support for WM8350 The auxiliary ADC in the WM8350 is shared between several subdevices so access to it needs to be arbitrated by the core driver. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-core.c | 51 ++++++++++++++++++++++++++++++++++- include/linux/mfd/wm8350/comparator.h | 8 ++++++ include/linux/mfd/wm8350/core.h | 2 ++ 3 files changed, 60 insertions(+), 1 deletion(-) (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index c013afde260d..60439bd3984d 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -63,7 +63,6 @@ */ static DEFINE_MUTEX(io_mutex); static DEFINE_MUTEX(reg_lock_mutex); -static DEFINE_MUTEX(auxadc_mutex); /* Perform a physical read from the device. */ @@ -1082,6 +1081,55 @@ int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) } EXPORT_SYMBOL_GPL(wm8350_unmask_irq); +int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) +{ + u16 reg, result = 0; + int tries = 5; + + if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP) + return -EINVAL; + if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP + && (scale != 0 || vref != 0)) + return -EINVAL; + + mutex_lock(&wm8350->auxadc_mutex); + + /* Turn on the ADC */ + reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA); + + if (scale || vref) { + reg = scale << 13; + reg |= vref << 12; + wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg); + } + + reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1); + reg |= 1 << channel | WM8350_AUXADC_POLL; + wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg); + + do { + schedule_timeout_interruptible(1); + reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1); + } while (tries-- && (reg & WM8350_AUXADC_POLL)); + + if (!tries) + dev_err(wm8350->dev, "adc chn %d read timeout\n", channel); + else + result = wm8350_reg_read(wm8350, + WM8350_AUX1_READBACK + channel); + + /* Turn off the ADC */ + reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, + reg & ~WM8350_AUXADC_ENA); + + mutex_unlock(&wm8350->auxadc_mutex); + + return result & WM8350_AUXADC_DATA1_MASK; +} +EXPORT_SYMBOL_GPL(wm8350_read_auxadc); + /* * Cache is always host endian. */ @@ -1239,6 +1287,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, } } + mutex_init(&wm8350->auxadc_mutex); mutex_init(&wm8350->irq_mutex); INIT_WORK(&wm8350->irq_work, wm8350_irq_worker); if (irq) { diff --git a/include/linux/mfd/wm8350/comparator.h b/include/linux/mfd/wm8350/comparator.h index 053788649452..54bc5d0fd502 100644 --- a/include/linux/mfd/wm8350/comparator.h +++ b/include/linux/mfd/wm8350/comparator.h @@ -164,4 +164,12 @@ #define WM8350_AUXADC_BATT 6 #define WM8350_AUXADC_TEMP 7 +struct wm8350; + +/* + * AUX ADC Readback + */ +int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, + int vref); + #endif diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 9490ec175d5a..cc190055b9c4 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -573,6 +573,8 @@ struct wm8350 { void *src); u16 *reg_cache; + struct mutex auxadc_mutex; + /* Interrupt handling */ struct work_struct irq_work; struct mutex irq_mutex; /* IRQ table mutex */ -- cgit v1.2.3 From 14431aa0c5a443d13d24e6f865a8838f97dab973 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 16 Nov 2008 20:16:47 +0100 Subject: power_supply: Add support for WM8350 PMU This patch adds support for the PMU provided by the WM8350 which implements battery, line and USB supplies including a battery charger. The hardware functions largely autonomously, with minimal software control required to initiate fast charging. Support for configuration of the USB supply is not yet implemented. This means that the hardware will remain in the mode configured at startup, by default limiting the current drawn from USB to 100mA. This driver was originally written by Liam Girdwood with subsequent updates for submission by Mark Brown. Signed-off-by: Mark Brown Acked-by: Anton Vorontsov Signed-off-by: Samuel Ortiz --- drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/wm8350_power.c | 515 ++++++++++++++++++++++++++++++++++++++ include/linux/mfd/wm8350/core.h | 26 ++ include/linux/mfd/wm8350/supply.h | 23 +- 5 files changed, 571 insertions(+), 1 deletion(-) create mode 100644 drivers/power/wm8350_power.c (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 8e0c2b47803c..52f86767f72e 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -29,6 +29,13 @@ config APM_POWER Say Y here to enable support APM status emulation using battery class devices. +config WM8350_POWER + tristate "WM8350 PMU support" + depends on MFD_WM8350 + help + Say Y here to enable support for the power management unit + provided by the Wolfson Microelectronics WM8350 PMIC. + config BATTERY_DS2760 tristate "DS2760 battery driver (HP iPAQ & others)" select W1 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index e8f1ecec5d8f..e6f68655d9e8 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_APM_POWER) += apm_power.o +obj-$(CONFIG_WM8350_POWER) += wm8350_power.o obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c new file mode 100644 index 000000000000..9c0a847a1139 --- /dev/null +++ b/drivers/power/wm8350_power.c @@ -0,0 +1,515 @@ +/* + * Battery driver for wm8350 PMIC + * + * Copyright 2007, 2008 Wolfson Microelectronics PLC. + * + * Based on OLPC Battery Driver + * + * Copyright 2006 David Woodhouse + * + * 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 +#include +#include +#include +#include +#include +#include + +static int wm8350_read_battery_uvolts(struct wm8350 *wm8350) +{ + return wm8350_read_auxadc(wm8350, WM8350_AUXADC_BATT, 0, 0) + * WM8350_AUX_COEFF; +} + +static int wm8350_read_line_uvolts(struct wm8350 *wm8350) +{ + return wm8350_read_auxadc(wm8350, WM8350_AUXADC_LINE, 0, 0) + * WM8350_AUX_COEFF; +} + +static int wm8350_read_usb_uvolts(struct wm8350 *wm8350) +{ + return wm8350_read_auxadc(wm8350, WM8350_AUXADC_USB, 0, 0) + * WM8350_AUX_COEFF; +} + +#define WM8350_BATT_SUPPLY 1 +#define WM8350_USB_SUPPLY 2 +#define WM8350_LINE_SUPPLY 4 + +static inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min) +{ + if (wm8350->rev < WM8350_REV_G) + return (((min - 30) / 15) & 0xf) << 8; + else + return (((min - 30) / 30) & 0xf) << 8; +} + +static int wm8350_get_supplies(struct wm8350 *wm8350) +{ + u16 sm, ov, co, chrg; + int supplies = 0; + + sm = wm8350_reg_read(wm8350, WM8350_STATE_MACHINE_STATUS); + ov = wm8350_reg_read(wm8350, WM8350_MISC_OVERRIDES); + co = wm8350_reg_read(wm8350, WM8350_COMPARATOR_OVERRIDES); + chrg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2); + + /* USB_SM */ + sm = (sm & WM8350_USB_SM_MASK) >> WM8350_USB_SM_SHIFT; + + /* CHG_ISEL */ + chrg &= WM8350_CHG_ISEL_MASK; + + /* If the USB state machine is active then we're using that with or + * without battery, otherwise check for wall supply */ + if (((sm == WM8350_USB_SM_100_SLV) || + (sm == WM8350_USB_SM_500_SLV) || + (sm == WM8350_USB_SM_STDBY_SLV)) + && !(ov & WM8350_USB_LIMIT_OVRDE)) + supplies = WM8350_USB_SUPPLY; + else if (((sm == WM8350_USB_SM_100_SLV) || + (sm == WM8350_USB_SM_500_SLV) || + (sm == WM8350_USB_SM_STDBY_SLV)) + && (ov & WM8350_USB_LIMIT_OVRDE) && (chrg == 0)) + supplies = WM8350_USB_SUPPLY | WM8350_BATT_SUPPLY; + else if (co & WM8350_WALL_FB_OVRDE) + supplies = WM8350_LINE_SUPPLY; + else + supplies = WM8350_BATT_SUPPLY; + + return supplies; +} + +static int wm8350_charger_config(struct wm8350 *wm8350, + struct wm8350_charger_policy *policy) +{ + u16 reg, eoc_mA, fast_limit_mA; + + if (!policy) { + dev_warn(wm8350->dev, + "No charger policy, charger not configured.\n"); + return -EINVAL; + } + + /* make sure USB fast charge current is not > 500mA */ + if (policy->fast_limit_USB_mA > 500) { + dev_err(wm8350->dev, "USB fast charge > 500mA\n"); + return -EINVAL; + } + + eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA); + + wm8350_reg_unlock(wm8350); + + reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1) + & WM8350_CHG_ENA_R168; + wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1, + reg | eoc_mA | policy->trickle_start_mV | + WM8350_CHG_TRICKLE_TEMP_CHOKE | + WM8350_CHG_TRICKLE_USB_CHOKE | + WM8350_CHG_FAST_USB_THROTTLE); + + if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) { + fast_limit_mA = + WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA); + wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2, + policy->charge_mV | policy->trickle_charge_USB_mA | + fast_limit_mA | wm8350_charge_time_min(wm8350, + policy->charge_timeout)); + + } else { + fast_limit_mA = + WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA); + wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2, + policy->charge_mV | policy->trickle_charge_mA | + fast_limit_mA | wm8350_charge_time_min(wm8350, + policy->charge_timeout)); + } + + wm8350_reg_lock(wm8350); + return 0; +} + +static int wm8350_batt_status(struct wm8350 *wm8350) +{ + u16 state; + + state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2); + state &= WM8350_CHG_STS_MASK; + + switch (state) { + case WM8350_CHG_STS_OFF: + return POWER_SUPPLY_STATUS_DISCHARGING; + + case WM8350_CHG_STS_TRICKLE: + case WM8350_CHG_STS_FAST: + return POWER_SUPPLY_STATUS_CHARGING; + + default: + return POWER_SUPPLY_STATUS_UNKNOWN; + } +} + +static ssize_t charger_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + char *charge; + int state; + + state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) & + WM8350_CHG_STS_MASK; + switch (state) { + case WM8350_CHG_STS_OFF: + charge = "Charger Off"; + break; + case WM8350_CHG_STS_TRICKLE: + charge = "Trickle Charging"; + break; + case WM8350_CHG_STS_FAST: + charge = "Fast Charging"; + break; + default: + return 0; + } + + return sprintf(buf, "%s\n", charge); +} + +static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL); + +static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data) +{ + struct wm8350_power *power = &wm8350->power; + struct wm8350_charger_policy *policy = power->policy; + + switch (irq) { + case WM8350_IRQ_CHG_BAT_HOT: + dev_err(wm8350->dev, "battery too hot\n"); + break; + case WM8350_IRQ_CHG_BAT_COLD: + dev_err(wm8350->dev, "battery too cold\n"); + break; + case WM8350_IRQ_CHG_BAT_FAIL: + dev_err(wm8350->dev, "battery failed\n"); + break; + case WM8350_IRQ_CHG_TO: + dev_err(wm8350->dev, "charger timeout\n"); + break; + case WM8350_IRQ_CHG_END: + power_supply_changed(&power->battery); + break; + case WM8350_IRQ_CHG_START: + power_supply_changed(&power->battery); + break; + + case WM8350_IRQ_CHG_FAST_RDY: + dev_dbg(wm8350->dev, "fast charger ready\n"); + wm8350_charger_config(wm8350, policy); + wm8350_reg_unlock(wm8350); + wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1, + WM8350_CHG_FAST); + wm8350_reg_lock(wm8350); + break; + + case WM8350_IRQ_CHG_VBATT_LT_3P9: + dev_warn(wm8350->dev, "battery < 3.9V\n"); + break; + case WM8350_IRQ_CHG_VBATT_LT_3P1: + dev_warn(wm8350->dev, "battery < 3.1V\n"); + break; + case WM8350_IRQ_CHG_VBATT_LT_2P85: + dev_warn(wm8350->dev, "battery < 2.85V\n"); + break; + + /* Supply change. We will overnotify but it should do + * no harm. */ + case WM8350_IRQ_EXT_USB_FB: + case WM8350_IRQ_EXT_WALL_FB: + wm8350_charger_config(wm8350, policy); + case WM8350_IRQ_EXT_BAT_FB: /* Fall through */ + power_supply_changed(&power->battery); + power_supply_changed(&power->usb); + power_supply_changed(&power->ac); + break; + + default: + dev_err(wm8350->dev, "Unknown interrupt %d\n", irq); + } +} + +/********************************************************************* + * AC Power + *********************************************************************/ +static int wm8350_ac_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = !!(wm8350_get_supplies(wm8350) & + WM8350_LINE_SUPPLY); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = wm8350_read_line_uvolts(wm8350); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static enum power_supply_property wm8350_ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +/********************************************************************* + * USB Power + *********************************************************************/ +static int wm8350_usb_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = !!(wm8350_get_supplies(wm8350) & + WM8350_USB_SUPPLY); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = wm8350_read_usb_uvolts(wm8350); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static enum power_supply_property wm8350_usb_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +/********************************************************************* + * Battery properties + *********************************************************************/ + +static int wm8350_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = wm8350_batt_status(wm8350); + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = !!(wm8350_get_supplies(wm8350) & + WM8350_BATT_SUPPLY); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = wm8350_read_battery_uvolts(wm8350); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static enum power_supply_property wm8350_bat_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +/********************************************************************* + * Initialisation + *********************************************************************/ + +static void wm8350_init_charger(struct wm8350 *wm8350) +{ + /* register our interest in charger events */ + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_TO); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_END); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_START); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); + + /* and supply change events */ + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_USB_FB); + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, + wm8350_charger_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); +} + +static void free_charger_irq(struct wm8350 *wm8350) +{ + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_TO); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_END); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_START); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); + wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); + wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_USB_FB); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB); + wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); + wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); +} + +static __devinit int wm8350_power_probe(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct wm8350_power *power = &wm8350->power; + struct wm8350_charger_policy *policy = power->policy; + struct power_supply *usb = &power->usb; + struct power_supply *battery = &power->battery; + struct power_supply *ac = &power->ac; + int ret; + + ac->name = "wm8350-ac"; + ac->type = POWER_SUPPLY_TYPE_MAINS; + ac->properties = wm8350_ac_props; + ac->num_properties = ARRAY_SIZE(wm8350_ac_props); + ac->get_property = wm8350_ac_get_prop; + ret = power_supply_register(&pdev->dev, ac); + if (ret) + return ret; + + battery->name = "wm8350-battery"; + battery->properties = wm8350_bat_props; + battery->num_properties = ARRAY_SIZE(wm8350_bat_props); + battery->get_property = wm8350_bat_get_property; + battery->use_for_apm = 1; + ret = power_supply_register(&pdev->dev, battery); + if (ret) + goto battery_failed; + + usb->name = "wm8350-usb", + usb->type = POWER_SUPPLY_TYPE_USB; + usb->properties = wm8350_usb_props; + usb->num_properties = ARRAY_SIZE(wm8350_usb_props); + usb->get_property = wm8350_usb_get_prop; + ret = power_supply_register(&pdev->dev, usb); + if (ret) + goto usb_failed; + + ret = device_create_file(&pdev->dev, &dev_attr_charger_state); + if (ret < 0) + dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret); + ret = 0; + + wm8350_init_charger(wm8350); + if (wm8350_charger_config(wm8350, policy) == 0) { + wm8350_reg_unlock(wm8350); + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA); + wm8350_reg_lock(wm8350); + } + + return ret; + +usb_failed: + power_supply_unregister(battery); +battery_failed: + power_supply_unregister(ac); + + return ret; +} + +static __devexit int wm8350_power_remove(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct wm8350_power *power = &wm8350->power; + + free_charger_irq(wm8350); + device_remove_file(&pdev->dev, &dev_attr_charger_state); + power_supply_unregister(&power->battery); + power_supply_unregister(&power->ac); + power_supply_unregister(&power->usb); + return 0; +} + +static struct platform_driver wm8350_power_driver = { + .probe = wm8350_power_probe, + .remove = __devexit_p(wm8350_power_remove), + .driver = { + .name = "wm8350-power", + }, +}; + +static int __init wm8350_power_init(void) +{ + return platform_driver_register(&wm8350_power_driver); +} +module_init(wm8350_power_init); + +static void __exit wm8350_power_exit(void) +{ + platform_driver_unregister(&wm8350_power_driver); +} +module_exit(wm8350_power_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Power supply driver for WM8350"); +MODULE_ALIAS("platform:wm8350-power"); diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index cc190055b9c4..d2614dfc9397 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -57,6 +57,9 @@ #define WM8350_OVER_CURRENT_INT_STATUS_MASK 0x25 #define WM8350_GPIO_INT_STATUS_MASK 0x26 #define WM8350_COMPARATOR_INT_STATUS_MASK 0x27 +#define WM8350_MISC_OVERRIDES 0xE3 +#define WM8350_COMPARATOR_OVERRIDES 0xE7 +#define WM8350_STATE_MACHINE_STATUS 0xE9 #define WM8350_MAX_REGISTER 0xFF @@ -523,6 +526,29 @@ #define WM8350_DC2_STS 0x0002 #define WM8350_DC1_STS 0x0001 +/* + * R227 (0xE3) - Misc Overrides + */ +#define WM8350_USB_LIMIT_OVRDE 0x0400 + +/* + * R227 (0xE7) - Comparator Overrides + */ +#define WM8350_USB_FB_OVRDE 0x8000 +#define WM8350_WALL_FB_OVRDE 0x4000 +#define WM8350_BATT_FB_OVRDE 0x2000 + + +/* + * R233 (0xE9) - State Machinine Status + */ +#define WM8350_USB_SM_MASK 0x0700 +#define WM8350_USB_SM_SHIFT 8 + +#define WM8350_USB_SM_100_SLV 1 +#define WM8350_USB_SM_500_SLV 5 +#define WM8350_USB_SM_STDBY_SLV 7 + /* WM8350 wake up conditions */ #define WM8350_IRQ_WKUP_OFF_STATE 43 #define WM8350_IRQ_WKUP_HIB_STATE 44 diff --git a/include/linux/mfd/wm8350/supply.h b/include/linux/mfd/wm8350/supply.h index 1c8f3cde79b0..79721513fa9f 100644 --- a/include/linux/mfd/wm8350/supply.h +++ b/include/linux/mfd/wm8350/supply.h @@ -13,7 +13,8 @@ #ifndef __LINUX_MFD_WM8350_SUPPLY_H_ #define __LINUX_MFD_WM8350_SUPPLY_H_ -#include +#include +#include /* * Charger registers @@ -104,8 +105,28 @@ #define WM8350_IRQ_EXT_WALL_FB 37 #define WM8350_IRQ_EXT_BAT_FB 38 +/* + * Policy to control charger state machine. + */ +struct wm8350_charger_policy { + + /* charger state machine policy - set in machine driver */ + int eoc_mA; /* end of charge current (mA) */ + int charge_mV; /* charge voltage */ + int fast_limit_mA; /* fast charge current limit */ + int fast_limit_USB_mA; /* USB fast charge current limit */ + int charge_timeout; /* charge timeout (mins) */ + int trickle_start_mV; /* trickle charge starts at mV */ + int trickle_charge_mA; /* trickle charge current */ + int trickle_charge_USB_mA; /* USB trickle charge current */ +}; + struct wm8350_power { struct platform_device *pdev; + struct power_supply battery; + struct power_supply usb; + struct power_supply ac; + struct wm8350_charger_policy *policy; }; #endif -- cgit v1.2.3 From d756f4a4446227ca9626087939a6769ca55ab036 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 20:20:30 +0100 Subject: mfd: Switch WM8350 revision detection to a feature based model Rather than check for chip revisions in the WM8350 drivers have the core code set flags for relevant differences. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-core.c | 6 ++---- drivers/power/wm8350_power.c | 2 +- include/linux/mfd/wm8350/core.h | 2 -- include/linux/mfd/wm8350/supply.h | 2 ++ 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 60439bd3984d..764bf15ea684 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -1240,19 +1240,17 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, 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; + wm8350->power.rev_g_coeff = 1; break; case WM8350_REV_H: dev_info(wm8350->dev, "Found Rev H device\n"); - wm8350->rev = WM8350_REV_H; + wm8350->power.rev_g_coeff = 1; break; default: /* For safety we refuse to run on unknown hardware */ diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index 9c0a847a1139..74e7593beffb 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c @@ -44,7 +44,7 @@ static int wm8350_read_usb_uvolts(struct wm8350 *wm8350) static inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min) { - if (wm8350->rev < WM8350_REV_G) + if (!wm8350->power.rev_g_coeff) return (((min - 30) / 15) & 0xf) << 8; else return (((min - 30) / 30) & 0xf) << 8; diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index d2614dfc9397..3c9735663f36 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -585,8 +585,6 @@ struct wm8350_irq { }; struct wm8350 { - int rev; /* chip revision */ - struct device *dev; /* device IO */ diff --git a/include/linux/mfd/wm8350/supply.h b/include/linux/mfd/wm8350/supply.h index 79721513fa9f..2b9479310bbd 100644 --- a/include/linux/mfd/wm8350/supply.h +++ b/include/linux/mfd/wm8350/supply.h @@ -127,6 +127,8 @@ struct wm8350_power { struct power_supply usb; struct power_supply ac; struct wm8350_charger_policy *policy; + + int rev_g_coeff; }; #endif -- cgit v1.2.3 From b797a5551979da22b0a35632198ffc8a330d9537 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 20:22:58 +0100 Subject: mfd: Refactor WM8350 chip identification Since the WM8350 driver was originally written the semantics for the identification registers of the chip have been clarified, allowing us to do an exact match on all the fields. This avoids mistakenly running on unsupported hardware. Also change to using the datasheet names more consistently for legibility and fix a printk() that should be dev_err(). Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-core.c | 54 ++++++++++++++++++++++++++++------------- include/linux/mfd/wm8350/core.h | 6 +++++ 2 files changed, 43 insertions(+), 17 deletions(-) (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 764bf15ea684..2188d759cbde 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -1227,52 +1227,72 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, struct wm8350_platform_data *pdata) { int ret = -EINVAL; - u16 id1, id2, mask, mode; + u16 id1, id2, mask_rev; + u16 cust_id, mode, chip_rev; /* get WM8350 revision and config mode */ wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1); wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2); + wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev), &mask_rev); id1 = be16_to_cpu(id1); id2 = be16_to_cpu(id2); + mask_rev = be16_to_cpu(mask_rev); - if (id1 == 0x6143) { - switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) { + if (id1 != 0x6143) { + dev_err(wm8350->dev, + "Device with ID %x is not a WM8350\n", id1); + ret = -ENODEV; + goto err; + } + + mode = id2 & WM8350_CONF_STS_MASK >> 10; + cust_id = id2 & WM8350_CUST_ID_MASK; + chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12; + dev_info(wm8350->dev, + "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n", + mode, cust_id, mask_rev, chip_rev); + + if (cust_id != 0) { + dev_err(wm8350->dev, "Unsupported CUST_ID\n"); + ret = -ENODEV; + goto err; + } + + switch (mask_rev) { + case 0: + switch (chip_rev) { case WM8350_REV_E: - dev_info(wm8350->dev, "Found Rev E device\n"); + dev_info(wm8350->dev, "WM8350 Rev E\n"); break; case WM8350_REV_F: - dev_info(wm8350->dev, "Found Rev F device\n"); + dev_info(wm8350->dev, "WM8350 Rev F\n"); break; case WM8350_REV_G: - dev_info(wm8350->dev, "Found Rev G device\n"); + dev_info(wm8350->dev, "WM8350 Rev G\n"); wm8350->power.rev_g_coeff = 1; break; case WM8350_REV_H: - dev_info(wm8350->dev, "Found Rev H device\n"); + dev_info(wm8350->dev, "WM8350 Rev H\n"); wm8350->power.rev_g_coeff = 1; break; default: /* For safety we refuse to run on unknown hardware */ - dev_info(wm8350->dev, "Found unknown rev %x\n", - (id2 & WM8350_CHIP_REV_MASK) >> 12); + dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n"); ret = -ENODEV; goto err; } - } else { - dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n", - id1); + break; + + default: + dev_err(wm8350->dev, "Unknown MASK_REV\n"); ret = -ENODEV; goto err; } - mode = id2 & WM8350_CONF_STS_MASK >> 10; - mask = id2 & WM8350_CUST_ID_MASK; - dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask); - ret = wm8350_create_cache(wm8350, mode); if (ret < 0) { - printk(KERN_ERR "wm8350: failed to create register cache\n"); + dev_err(wm8350->dev, "Failed to create register cache\n"); return ret; } diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 3c9735663f36..2a7abeebe777 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -29,6 +29,7 @@ */ #define WM8350_RESET_ID 0x00 #define WM8350_ID 0x01 +#define WM8350_REVISION 0x02 #define WM8350_SYSTEM_CONTROL_1 0x03 #define WM8350_SYSTEM_CONTROL_2 0x04 #define WM8350_SYSTEM_HIBERNATE 0x05 @@ -79,6 +80,11 @@ #define WM8350_CONF_STS_MASK 0x0C00 #define WM8350_CUST_ID_MASK 0x00FF +/* + * R2 (0x02) - Revision + */ +#define WM8350_MASK_REV_MASK 0x00FF + /* * R3 (0x03) - System Control 1 */ -- cgit v1.2.3 From 4008e879e1325c29362aa2c3fa4b527273ae15a8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Nov 2008 22:45:14 +0100 Subject: power_supply: Add battery health reporting for WM8350 Implement support for reporting battery health in the WM8350 battery interface. Since we are now able to report this via the classs remove the diagnostics from the interrupt handler. Signed-off-by: Mark Brown Acked-by: Anton Vorontsov Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-regmap.c | 2 +- drivers/power/wm8350_power.c | 33 +++++++++++++++++++++++++-------- include/linux/mfd/wm8350/core.h | 7 +++++++ 3 files changed, 33 insertions(+), 9 deletions(-) (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c index aaf394aa9c2d..b43d64c2b920 100644 --- a/drivers/mfd/wm8350-regmap.c +++ b/drivers/mfd/wm8350-regmap.c @@ -1314,7 +1314,7 @@ const struct wm8350_reg_access wm8350_reg_io_map[] = { { 0xFFFF, 0xFFFF, 0xFFFF }, /* R223 */ { 0x0000, 0x0000, 0x0000 }, /* R224 */ { 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */ - { 0x0000, 0x0000, 0x0000 }, /* R226 */ + { 0x0000, 0x0000, 0xFFFF }, /* R226 - Charger status */ { 0x0000, 0x0000, 0xFFFF }, /* R227 */ { 0x0000, 0x0000, 0x0000 }, /* R228 */ { 0x0000, 0x0000, 0x0000 }, /* R229 */ diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index 74e7593beffb..1b16bf343f2f 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c @@ -190,22 +190,18 @@ static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data) struct wm8350_charger_policy *policy = power->policy; switch (irq) { - case WM8350_IRQ_CHG_BAT_HOT: - dev_err(wm8350->dev, "battery too hot\n"); - break; - case WM8350_IRQ_CHG_BAT_COLD: - dev_err(wm8350->dev, "battery too cold\n"); - break; case WM8350_IRQ_CHG_BAT_FAIL: dev_err(wm8350->dev, "battery failed\n"); break; case WM8350_IRQ_CHG_TO: dev_err(wm8350->dev, "charger timeout\n"); - break; - case WM8350_IRQ_CHG_END: power_supply_changed(&power->battery); break; + + case WM8350_IRQ_CHG_BAT_HOT: + case WM8350_IRQ_CHG_BAT_COLD: case WM8350_IRQ_CHG_START: + case WM8350_IRQ_CHG_END: power_supply_changed(&power->battery); break; @@ -308,6 +304,23 @@ static enum power_supply_property wm8350_usb_props[] = { * Battery properties *********************************************************************/ +static int wm8350_bat_check_health(struct wm8350 *wm8350) +{ + u16 reg; + + if (wm8350_read_battery_uvolts(wm8350) < 2850000) + return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + + reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES); + if (reg & WM8350_CHG_BATT_HOT_OVRDE) + return POWER_SUPPLY_HEALTH_OVERHEAT; + + if (reg & WM8350_CHG_BATT_COLD_OVRDE) + return POWER_SUPPLY_HEALTH_COLD; + + return POWER_SUPPLY_HEALTH_GOOD; +} + static int wm8350_bat_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -326,6 +339,9 @@ static int wm8350_bat_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = wm8350_read_battery_uvolts(wm8350); break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = wm8350_bat_check_health(wm8350); + break; default: ret = -EINVAL; break; @@ -338,6 +354,7 @@ static enum power_supply_property wm8350_bat_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_HEALTH, }; /********************************************************************* diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 2a7abeebe777..afeff6f1316c 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -58,6 +58,7 @@ #define WM8350_OVER_CURRENT_INT_STATUS_MASK 0x25 #define WM8350_GPIO_INT_STATUS_MASK 0x26 #define WM8350_COMPARATOR_INT_STATUS_MASK 0x27 +#define WM8350_CHARGER_OVERRIDES 0xE2 #define WM8350_MISC_OVERRIDES 0xE3 #define WM8350_COMPARATOR_OVERRIDES 0xE7 #define WM8350_STATE_MACHINE_STATUS 0xE9 @@ -532,6 +533,12 @@ #define WM8350_DC2_STS 0x0002 #define WM8350_DC1_STS 0x0001 +/* + * R226 (0xE2) - Charger status + */ +#define WM8350_CHG_BATT_HOT_OVRDE 0x8000 +#define WM8350_CHG_BATT_COLD_OVRDE 0x4000 + /* * R227 (0xE3) - Misc Overrides */ -- cgit v1.2.3 From 96920630624868add3f63f596523e70dbb64549a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Dec 2008 23:09:50 +0100 Subject: mfd: Add WM8352 support The WM8352 is a variant of the WM8350. Aside from the register defaults there are no software visible differences to the WM8350. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 16 + drivers/mfd/wm8350-core.c | 86 +++- drivers/mfd/wm8350-i2c.c | 1 + drivers/mfd/wm8350-regmap.c | 1052 +++++++++++++++++++++++++++++++++++++++ include/linux/mfd/wm8350/core.h | 4 + 5 files changed, 1143 insertions(+), 16 deletions(-) (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ddfb12b52f54..76a482dfc177 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -143,6 +143,22 @@ config MFD_WM8350_CONFIG_MODE_3 bool depends on MFD_WM8350 +config MFD_WM8352_CONFIG_MODE_0 + bool + depends on MFD_WM8350 + +config MFD_WM8352_CONFIG_MODE_1 + bool + depends on MFD_WM8350 + +config MFD_WM8352_CONFIG_MODE_2 + bool + depends on MFD_WM8350 + +config MFD_WM8352_CONFIG_MODE_3 + bool + depends on MFD_WM8350 + config MFD_WM8350_I2C tristate "Support Wolfson Microelectronics WM8350 with I2C" select MFD_WM8350 diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 2188d759cbde..fa505ac76c84 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -1133,35 +1133,75 @@ EXPORT_SYMBOL_GPL(wm8350_read_auxadc); /* * Cache is always host endian. */ -static int wm8350_create_cache(struct wm8350 *wm8350, int mode) +static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode) { int i, ret = 0; u16 value; const u16 *reg_map; - switch (mode) { -#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0 + switch (type) { case 0: - reg_map = wm8350_mode0_defaults; - break; + switch (mode) { +#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0 + case 0: + reg_map = wm8350_mode0_defaults; + break; #endif #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1 - case 1: - reg_map = wm8350_mode1_defaults; - break; + case 1: + reg_map = wm8350_mode1_defaults; + break; #endif #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2 - case 2: - reg_map = wm8350_mode2_defaults; - break; + case 2: + reg_map = wm8350_mode2_defaults; + break; #endif #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3 - case 3: - reg_map = wm8350_mode3_defaults; - break; + case 3: + reg_map = wm8350_mode3_defaults; + break; #endif + default: + dev_err(wm8350->dev, + "WM8350 configuration mode %d not supported\n", + mode); + return -EINVAL; + } + + case 2: + switch (mode) { +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0 + case 0: + reg_map = wm8352_mode0_defaults; + break; +#endif +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1 + case 1: + reg_map = wm8352_mode1_defaults; + break; +#endif +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2 + case 2: + reg_map = wm8352_mode2_defaults; + break; +#endif +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3 + case 3: + reg_map = wm8352_mode3_defaults; + break; +#endif + default: + dev_err(wm8350->dev, + "WM8352 configuration mode %d not supported\n", + mode); + return -EINVAL; + } + break; + default: - dev_err(wm8350->dev, "Configuration mode %d not supported\n", + dev_err(wm8350->dev, + "WM835x configuration mode %d not supported\n", mode); return -EINVAL; } @@ -1284,13 +1324,27 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, } break; + case 2: + switch (chip_rev) { + case 0: + dev_info(wm8350->dev, "WM8352 Rev A\n"); + wm8350->power.rev_g_coeff = 1; + break; + + default: + dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n"); + ret = -ENODEV; + goto err; + } + break; + default: dev_err(wm8350->dev, "Unknown MASK_REV\n"); ret = -ENODEV; goto err; } - ret = wm8350_create_cache(wm8350, mode); + ret = wm8350_create_cache(wm8350, mask_rev, mode); if (ret < 0) { dev_err(wm8350->dev, "Failed to create register cache\n"); return ret; diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 876e693582bd..878051253084 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -97,6 +97,7 @@ static int wm8350_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id wm8350_i2c_id[] = { { "wm8350", 0 }, + { "wm8352", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id); diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c index b43d64c2b920..3e2cc37961f3 100644 --- a/drivers/mfd/wm8350-regmap.c +++ b/drivers/mfd/wm8350-regmap.c @@ -1074,6 +1074,1058 @@ const u16 wm8350_mode3_defaults[] = { }; #endif +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8352_mode0_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0002, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0004, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0000, /* R129 - GPIO Pin pull up Control */ + 0x0000, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x0FFC, /* R134 - GPIO Configuration (i/o) */ + 0x0FFC, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x0013, /* R140 - GPIO Function Select 1 */ + 0x0000, /* R141 - GPIO Function Select 2 */ + 0x0000, /* R142 - GPIO Function Select 3 */ + 0x0003, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 - Current Sink Driver B */ + 0x0000, /* R175 - CSB Flash control */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x000E, /* R180 - DCDC1 Control */ + 0x0000, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0000, /* R186 - DCDC3 Control */ + 0x0000, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x0000, /* R189 - DCDC4 Control */ + 0x0000, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 - DCDC5 Control */ + 0x0000, /* R193 - DCDC5 Timeouts */ + 0x0000, /* R194 */ + 0x0000, /* R195 - DCDC6 Control */ + 0x0000, /* R196 - DCDC6 Timeouts */ + 0x0006, /* R197 - DCDC6 Low Power */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x001C, /* R200 - LDO1 Control */ + 0x0000, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x001B, /* R203 - LDO2 Control */ + 0x0000, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x001B, /* R206 - LDO3 Control */ + 0x0000, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x001B, /* R209 - LDO4 Control */ + 0x0000, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x0000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x5000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ + 0x5100, /* R252 */ + 0x1000, /* R253 - DCDC6 Test Controls */ +}; +#endif + +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8352_mode1_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0002, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0204, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0000, /* R129 - GPIO Pin pull up Control */ + 0x0000, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x0BFB, /* R134 - GPIO Configuration (i/o) */ + 0x0FFF, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x0300, /* R140 - GPIO Function Select 1 */ + 0x0000, /* R141 - GPIO Function Select 2 */ + 0x2300, /* R142 - GPIO Function Select 3 */ + 0x0003, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 - Current Sink Driver B */ + 0x0000, /* R175 - CSB Flash control */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x0062, /* R180 - DCDC1 Control */ + 0x0400, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0006, /* R186 - DCDC3 Control */ + 0x0800, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x0006, /* R189 - DCDC4 Control */ + 0x0C00, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 - DCDC5 Control */ + 0x0000, /* R193 - DCDC5 Timeouts */ + 0x0000, /* R194 */ + 0x0026, /* R195 - DCDC6 Control */ + 0x1000, /* R196 - DCDC6 Timeouts */ + 0x0006, /* R197 - DCDC6 Low Power */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x0002, /* R200 - LDO1 Control */ + 0x0000, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x001A, /* R203 - LDO2 Control */ + 0x0000, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x001F, /* R206 - LDO3 Control */ + 0x0000, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x001F, /* R209 - LDO4 Control */ + 0x0000, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x0000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x5000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ + 0x5100, /* R252 */ + 0x1000, /* R253 - DCDC6 Test Controls */ +}; +#endif + +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8352_mode2_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0002, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0204, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0000, /* R129 - GPIO Pin pull up Control */ + 0x0110, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x09DA, /* R134 - GPIO Configuration (i/o) */ + 0x0DD6, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x1310, /* R140 - GPIO Function Select 1 */ + 0x0033, /* R141 - GPIO Function Select 2 */ + 0x2000, /* R142 - GPIO Function Select 3 */ + 0x0000, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 - Current Sink Driver B */ + 0x0000, /* R175 - CSB Flash control */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x000E, /* R180 - DCDC1 Control */ + 0x0800, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0056, /* R186 - DCDC3 Control */ + 0x1800, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x000E, /* R189 - DCDC4 Control */ + 0x1000, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 - DCDC5 Control */ + 0x0000, /* R193 - DCDC5 Timeouts */ + 0x0000, /* R194 */ + 0x0026, /* R195 - DCDC6 Control */ + 0x0C00, /* R196 - DCDC6 Timeouts */ + 0x0006, /* R197 - DCDC6 Low Power */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x001C, /* R200 - LDO1 Control */ + 0x0000, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x0006, /* R203 - LDO2 Control */ + 0x0400, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x001C, /* R206 - LDO3 Control */ + 0x1400, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x001A, /* R209 - LDO4 Control */ + 0x0000, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x0000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x5000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ + 0x5100, /* R252 */ + 0x1000, /* R253 - DCDC6 Test Controls */ +}; +#endif + +#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8352_mode3_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0002, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0204, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0010, /* R129 - GPIO Pin pull up Control */ + 0x0000, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x0BFB, /* R134 - GPIO Configuration (i/o) */ + 0x0FFD, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x0310, /* R140 - GPIO Function Select 1 */ + 0x0001, /* R141 - GPIO Function Select 2 */ + 0x2300, /* R142 - GPIO Function Select 3 */ + 0x0003, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 - Current Sink Driver B */ + 0x0000, /* R175 - CSB Flash control */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x0006, /* R180 - DCDC1 Control */ + 0x0400, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0050, /* R186 - DCDC3 Control */ + 0x0C00, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x000E, /* R189 - DCDC4 Control */ + 0x0400, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 - DCDC5 Control */ + 0x0000, /* R193 - DCDC5 Timeouts */ + 0x0000, /* R194 */ + 0x0029, /* R195 - DCDC6 Control */ + 0x0800, /* R196 - DCDC6 Timeouts */ + 0x0006, /* R197 - DCDC6 Low Power */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x001D, /* R200 - LDO1 Control */ + 0x1000, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x0017, /* R203 - LDO2 Control */ + 0x1000, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x0006, /* R206 - LDO3 Control */ + 0x1000, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x0010, /* R209 - LDO4 Control */ + 0x1000, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x0000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x5000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ + 0x5100, /* R252 */ + 0x1000, /* R253 - DCDC6 Test Controls */ +}; +#endif + /* The register defaults for the config mode used must be compiled in but * due to the impact on kernel size it is possible to disable */ diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index afeff6f1316c..737579086d01 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -589,6 +589,10 @@ extern const u16 wm8350_mode0_defaults[]; extern const u16 wm8350_mode1_defaults[]; extern const u16 wm8350_mode2_defaults[]; extern const u16 wm8350_mode3_defaults[]; +extern const u16 wm8352_mode0_defaults[]; +extern const u16 wm8352_mode1_defaults[]; +extern const u16 wm8352_mode2_defaults[]; +extern const u16 wm8352_mode3_defaults[]; struct wm8350; -- cgit v1.2.3 From 645524a9c6e1e42dc4fe03217befb20e2fc4d43e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Dec 2008 23:12:16 +0100 Subject: mfd: Support configurable numbers of DCDCs and ISINKs on WM8350 Some WM8350 variants have fewer DCDCs and ISINKs. Identify these at probe and refuse to use the absent DCDCs when running on these chips. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-core.c | 6 ++++++ drivers/regulator/wm8350-regulator.c | 7 +++++++ include/linux/mfd/wm8350/pmic.h | 4 ++++ 3 files changed, 17 insertions(+) (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 03af3b12c020..56c363c240a9 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -1301,6 +1301,9 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, switch (mask_rev) { case 0: + wm8350->pmic.max_dcdc = WM8350_DCDC_6; + wm8350->pmic.max_isink = WM8350_ISINK_B; + switch (chip_rev) { case WM8350_REV_E: dev_info(wm8350->dev, "WM8350 Rev E\n"); @@ -1325,6 +1328,9 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, break; case 2: + wm8350->pmic.max_dcdc = WM8350_DCDC_6; + wm8350->pmic.max_isink = WM8350_ISINK_B; + switch (chip_rev) { case 0: dev_info(wm8350->dev, "WM8352 Rev A\n"); diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 1f44b17e23b1..c68c496b2c49 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1380,6 +1380,13 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg, if (wm8350->pmic.pdev[reg]) return -EBUSY; + if (reg >= WM8350_DCDC_1 && reg <= WM8350_DCDC_6 && + reg > wm8350->pmic.max_dcdc) + return -ENODEV; + if (reg >= WM8350_ISINK_A && reg <= WM8350_ISINK_B && + reg > wm8350->pmic.max_isink) + return -ENODEV; + pdev = platform_device_alloc("wm8350-regulator", reg); if (!pdev) return -ENOMEM; diff --git a/include/linux/mfd/wm8350/pmic.h b/include/linux/mfd/wm8350/pmic.h index 69b69e07f62f..96acbfc8aa12 100644 --- a/include/linux/mfd/wm8350/pmic.h +++ b/include/linux/mfd/wm8350/pmic.h @@ -701,6 +701,10 @@ struct platform_device; struct regulator_init_data; struct wm8350_pmic { + /* Number of regulators of each type on this device */ + int max_dcdc; + int max_isink; + /* ISINK to DCDC mapping */ int isink_A_dcdc; int isink_B_dcdc; -- cgit v1.2.3 From ca23f8c1b0aa15dc69565244fc5dffa67a72dd02 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Dec 2008 23:12:28 +0100 Subject: mfd: Add WM8351 support The WM8351 is a WM8350 variant. As well as register default changes the WM8351 has fewer voltage and current regulators than the WM8350. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 16 + drivers/mfd/wm8350-core.c | 47 ++ drivers/mfd/wm8350-i2c.c | 1 + drivers/mfd/wm8350-regmap.c | 1044 +++++++++++++++++++++++++++++++++++++++ include/linux/mfd/wm8350/core.h | 4 + 5 files changed, 1112 insertions(+) (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 76a482dfc177..781a27955ff5 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -143,6 +143,22 @@ config MFD_WM8350_CONFIG_MODE_3 bool depends on MFD_WM8350 +config MFD_WM8351_CONFIG_MODE_0 + bool + depends on MFD_WM8350 + +config MFD_WM8351_CONFIG_MODE_1 + bool + depends on MFD_WM8350 + +config MFD_WM8351_CONFIG_MODE_2 + bool + depends on MFD_WM8350 + +config MFD_WM8351_CONFIG_MODE_3 + bool + depends on MFD_WM8350 + config MFD_WM8352_CONFIG_MODE_0 bool depends on MFD_WM8350 diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 56c363c240a9..e03fe60b55bf 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -1169,6 +1169,36 @@ static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode) return -EINVAL; } + case 1: + switch (mode) { +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0 + case 0: + reg_map = wm8351_mode0_defaults; + break; +#endif +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1 + case 1: + reg_map = wm8351_mode1_defaults; + break; +#endif +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2 + case 2: + reg_map = wm8351_mode2_defaults; + break; +#endif +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3 + case 3: + reg_map = wm8351_mode3_defaults; + break; +#endif + default: + dev_err(wm8350->dev, + "WM8351 configuration mode %d not supported\n", + mode); + return -EINVAL; + } + break; + case 2: switch (mode) { #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0 @@ -1327,6 +1357,23 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, } break; + case 1: + wm8350->pmic.max_dcdc = WM8350_DCDC_4; + wm8350->pmic.max_isink = WM8350_ISINK_A; + + switch (chip_rev) { + case 0: + dev_info(wm8350->dev, "WM8351 Rev A\n"); + wm8350->power.rev_g_coeff = 1; + break; + + default: + dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n"); + ret = -ENODEV; + goto err; + } + break; + case 2: wm8350->pmic.max_dcdc = WM8350_DCDC_6; wm8350->pmic.max_isink = WM8350_ISINK_B; diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 878051253084..8d8c93217572 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -97,6 +97,7 @@ static int wm8350_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id wm8350_i2c_id[] = { { "wm8350", 0 }, + { "wm8351", 0 }, { "wm8352", 0 }, { } }; diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c index 3e2cc37961f3..68887b817d17 100644 --- a/drivers/mfd/wm8350-regmap.c +++ b/drivers/mfd/wm8350-regmap.c @@ -1074,6 +1074,1050 @@ const u16 wm8350_mode3_defaults[] = { }; #endif +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8351_mode0_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0001, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0004, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0000, /* R129 - GPIO Pin pull up Control */ + 0x0000, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x0FFC, /* R134 - GPIO Configuration (i/o) */ + 0x0FFC, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x0013, /* R140 - GPIO Function Select 1 */ + 0x0000, /* R141 - GPIO Function Select 2 */ + 0x0000, /* R142 - GPIO Function Select 3 */ + 0x0003, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 */ + 0x0000, /* R175 */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x000E, /* R180 - DCDC1 Control */ + 0x0000, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0000, /* R186 - DCDC3 Control */ + 0x0000, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x0000, /* R189 - DCDC4 Control */ + 0x0000, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 */ + 0x0000, /* R193 */ + 0x0000, /* R194 */ + 0x0000, /* R195 */ + 0x0000, /* R196 */ + 0x0006, /* R197 */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x001C, /* R200 - LDO1 Control */ + 0x0000, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x001B, /* R203 - LDO2 Control */ + 0x0000, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x001B, /* R206 - LDO3 Control */ + 0x0000, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x001B, /* R209 - LDO4 Control */ + 0x0000, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 - FLL Test 1 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x0000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x1000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ +}; +#endif + +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8351_mode1_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0001, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0204, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0000, /* R129 - GPIO Pin pull up Control */ + 0x0000, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x0CFB, /* R134 - GPIO Configuration (i/o) */ + 0x0C1F, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x0300, /* R140 - GPIO Function Select 1 */ + 0x1110, /* R141 - GPIO Function Select 2 */ + 0x0013, /* R142 - GPIO Function Select 3 */ + 0x0003, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 */ + 0x0000, /* R175 */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x000E, /* R180 - DCDC1 Control */ + 0x0C00, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0026, /* R186 - DCDC3 Control */ + 0x0400, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x0062, /* R189 - DCDC4 Control */ + 0x0800, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 */ + 0x0000, /* R193 */ + 0x0000, /* R194 */ + 0x000A, /* R195 */ + 0x1000, /* R196 */ + 0x0006, /* R197 */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x0006, /* R200 - LDO1 Control */ + 0x0000, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x0010, /* R203 - LDO2 Control */ + 0x0C00, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x001F, /* R206 - LDO3 Control */ + 0x0800, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x000A, /* R209 - LDO4 Control */ + 0x0800, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 - FLL Test 1 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x1000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x1000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ +}; +#endif + +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8351_mode2_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0001, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0214, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0000, /* R129 - GPIO Pin pull up Control */ + 0x0110, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x09FA, /* R134 - GPIO Configuration (i/o) */ + 0x0DF6, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x1310, /* R140 - GPIO Function Select 1 */ + 0x0003, /* R141 - GPIO Function Select 2 */ + 0x2000, /* R142 - GPIO Function Select 3 */ + 0x0000, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 */ + 0x0000, /* R175 */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x001A, /* R180 - DCDC1 Control */ + 0x0800, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0056, /* R186 - DCDC3 Control */ + 0x0400, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x0026, /* R189 - DCDC4 Control */ + 0x0C00, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 */ + 0x0000, /* R193 */ + 0x0000, /* R194 */ + 0x0026, /* R195 */ + 0x0C00, /* R196 */ + 0x0006, /* R197 */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x001C, /* R200 - LDO1 Control */ + 0x0400, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x0010, /* R203 - LDO2 Control */ + 0x0C00, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x0015, /* R206 - LDO3 Control */ + 0x0000, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x001A, /* R209 - LDO4 Control */ + 0x0000, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 - FLL Test 1 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x0000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x1000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ +}; +#endif + +#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3 + +#undef WM8350_HAVE_CONFIG_MODE +#define WM8350_HAVE_CONFIG_MODE + +const u16 wm8351_mode3_defaults[] = { + 0x6143, /* R0 - Reset/ID */ + 0x0000, /* R1 - ID */ + 0x0001, /* R2 - Revision */ + 0x1C02, /* R3 - System Control 1 */ + 0x0204, /* R4 - System Control 2 */ + 0x0000, /* R5 - System Hibernate */ + 0x8A00, /* R6 - Interface Control */ + 0x0000, /* R7 */ + 0x8000, /* R8 - Power mgmt (1) */ + 0x0000, /* R9 - Power mgmt (2) */ + 0x0000, /* R10 - Power mgmt (3) */ + 0x2000, /* R11 - Power mgmt (4) */ + 0x0E00, /* R12 - Power mgmt (5) */ + 0x0000, /* R13 - Power mgmt (6) */ + 0x0000, /* R14 - Power mgmt (7) */ + 0x0000, /* R15 */ + 0x0000, /* R16 - RTC Seconds/Minutes */ + 0x0100, /* R17 - RTC Hours/Day */ + 0x0101, /* R18 - RTC Date/Month */ + 0x1400, /* R19 - RTC Year */ + 0x0000, /* R20 - Alarm Seconds/Minutes */ + 0x0000, /* R21 - Alarm Hours/Day */ + 0x0000, /* R22 - Alarm Date/Month */ + 0x0320, /* R23 - RTC Time Control */ + 0x0000, /* R24 - System Interrupts */ + 0x0000, /* R25 - Interrupt Status 1 */ + 0x0000, /* R26 - Interrupt Status 2 */ + 0x0000, /* R27 */ + 0x0000, /* R28 - Under Voltage Interrupt status */ + 0x0000, /* R29 - Over Current Interrupt status */ + 0x0000, /* R30 - GPIO Interrupt Status */ + 0x0000, /* R31 - Comparator Interrupt Status */ + 0x3FFF, /* R32 - System Interrupts Mask */ + 0x0000, /* R33 - Interrupt Status 1 Mask */ + 0x0000, /* R34 - Interrupt Status 2 Mask */ + 0x0000, /* R35 */ + 0x0000, /* R36 - Under Voltage Interrupt status Mask */ + 0x0000, /* R37 - Over Current Interrupt status Mask */ + 0x0000, /* R38 - GPIO Interrupt Status Mask */ + 0x0000, /* R39 - Comparator Interrupt Status Mask */ + 0x0040, /* R40 - Clock Control 1 */ + 0x0000, /* R41 - Clock Control 2 */ + 0x3A00, /* R42 - FLL Control 1 */ + 0x7086, /* R43 - FLL Control 2 */ + 0xC226, /* R44 - FLL Control 3 */ + 0x0000, /* R45 - FLL Control 4 */ + 0x0000, /* R46 */ + 0x0000, /* R47 */ + 0x0000, /* R48 - DAC Control */ + 0x0000, /* R49 */ + 0x00C0, /* R50 - DAC Digital Volume L */ + 0x00C0, /* R51 - DAC Digital Volume R */ + 0x0000, /* R52 */ + 0x0040, /* R53 - DAC LR Rate */ + 0x0000, /* R54 - DAC Clock Control */ + 0x0000, /* R55 */ + 0x0000, /* R56 */ + 0x0000, /* R57 */ + 0x4000, /* R58 - DAC Mute */ + 0x0000, /* R59 - DAC Mute Volume */ + 0x0000, /* R60 - DAC Side */ + 0x0000, /* R61 */ + 0x0000, /* R62 */ + 0x0000, /* R63 */ + 0x8000, /* R64 - ADC Control */ + 0x0000, /* R65 */ + 0x00C0, /* R66 - ADC Digital Volume L */ + 0x00C0, /* R67 - ADC Digital Volume R */ + 0x0000, /* R68 - ADC Divider */ + 0x0000, /* R69 */ + 0x0040, /* R70 - ADC LR Rate */ + 0x0000, /* R71 */ + 0x0303, /* R72 - Input Control */ + 0x0000, /* R73 - IN3 Input Control */ + 0x0000, /* R74 - Mic Bias Control */ + 0x0000, /* R75 */ + 0x0000, /* R76 - Output Control */ + 0x0000, /* R77 - Jack Detect */ + 0x0000, /* R78 - Anti Pop Control */ + 0x0000, /* R79 */ + 0x0040, /* R80 - Left Input Volume */ + 0x0040, /* R81 - Right Input Volume */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 */ + 0x0000, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 */ + 0x0800, /* R88 - Left Mixer Control */ + 0x1000, /* R89 - Right Mixer Control */ + 0x0000, /* R90 */ + 0x0000, /* R91 */ + 0x0000, /* R92 - OUT3 Mixer Control */ + 0x0000, /* R93 - OUT4 Mixer Control */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 - Output Left Mixer Volume */ + 0x0000, /* R97 - Output Right Mixer Volume */ + 0x0000, /* R98 - Input Mixer Volume L */ + 0x0000, /* R99 - Input Mixer Volume R */ + 0x0000, /* R100 - Input Mixer Volume */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x00E4, /* R104 - OUT1L Volume */ + 0x00E4, /* R105 - OUT1R Volume */ + 0x00E4, /* R106 - OUT2L Volume */ + 0x02E4, /* R107 - OUT2R Volume */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 - BEEP Volume */ + 0x0A00, /* R112 - AI Formating */ + 0x0000, /* R113 - ADC DAC COMP */ + 0x0020, /* R114 - AI ADC Control */ + 0x0020, /* R115 - AI DAC Control */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x1FFF, /* R128 - GPIO Debounce */ + 0x0010, /* R129 - GPIO Pin pull up Control */ + 0x0000, /* R130 - GPIO Pull down Control */ + 0x0000, /* R131 - GPIO Interrupt Mode */ + 0x0000, /* R132 */ + 0x0000, /* R133 - GPIO Control */ + 0x0BFB, /* R134 - GPIO Configuration (i/o) */ + 0x0FFD, /* R135 - GPIO Pin Polarity / Type */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x0310, /* R140 - GPIO Function Select 1 */ + 0x0001, /* R141 - GPIO Function Select 2 */ + 0x2300, /* R142 - GPIO Function Select 3 */ + 0x0003, /* R143 - GPIO Function Select 4 */ + 0x0000, /* R144 - Digitiser Control (1) */ + 0x0002, /* R145 - Digitiser Control (2) */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x7000, /* R152 - AUX1 Readback */ + 0x7000, /* R153 - AUX2 Readback */ + 0x7000, /* R154 - AUX3 Readback */ + 0x7000, /* R155 - AUX4 Readback */ + 0x0000, /* R156 - USB Voltage Readback */ + 0x0000, /* R157 - LINE Voltage Readback */ + 0x0000, /* R158 - BATT Voltage Readback */ + 0x0000, /* R159 - Chip Temp Readback */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 - Generic Comparator Control */ + 0x0000, /* R164 - Generic comparator 1 */ + 0x0000, /* R165 - Generic comparator 2 */ + 0x0000, /* R166 - Generic comparator 3 */ + 0x0000, /* R167 - Generic comparator 4 */ + 0xA00F, /* R168 - Battery Charger Control 1 */ + 0x0B06, /* R169 - Battery Charger Control 2 */ + 0x0000, /* R170 - Battery Charger Control 3 */ + 0x0000, /* R171 */ + 0x0000, /* R172 - Current Sink Driver A */ + 0x0000, /* R173 - CSA Flash control */ + 0x0000, /* R174 */ + 0x0000, /* R175 */ + 0x0000, /* R176 - DCDC/LDO requested */ + 0x032D, /* R177 - DCDC Active options */ + 0x0000, /* R178 - DCDC Sleep options */ + 0x0025, /* R179 - Power-check comparator */ + 0x000E, /* R180 - DCDC1 Control */ + 0x0400, /* R181 - DCDC1 Timeouts */ + 0x1006, /* R182 - DCDC1 Low Power */ + 0x0018, /* R183 - DCDC2 Control */ + 0x0000, /* R184 - DCDC2 Timeouts */ + 0x0000, /* R185 */ + 0x0026, /* R186 - DCDC3 Control */ + 0x0800, /* R187 - DCDC3 Timeouts */ + 0x0006, /* R188 - DCDC3 Low Power */ + 0x0062, /* R189 - DCDC4 Control */ + 0x1400, /* R190 - DCDC4 Timeouts */ + 0x0006, /* R191 - DCDC4 Low Power */ + 0x0008, /* R192 */ + 0x0000, /* R193 */ + 0x0000, /* R194 */ + 0x0026, /* R195 */ + 0x0400, /* R196 */ + 0x0006, /* R197 */ + 0x0000, /* R198 */ + 0x0003, /* R199 - Limit Switch Control */ + 0x0006, /* R200 - LDO1 Control */ + 0x0C00, /* R201 - LDO1 Timeouts */ + 0x001C, /* R202 - LDO1 Low Power */ + 0x0016, /* R203 - LDO2 Control */ + 0x0000, /* R204 - LDO2 Timeouts */ + 0x001C, /* R205 - LDO2 Low Power */ + 0x0019, /* R206 - LDO3 Control */ + 0x0000, /* R207 - LDO3 Timeouts */ + 0x001C, /* R208 - LDO3 Low Power */ + 0x001A, /* R209 - LDO4 Control */ + 0x1000, /* R210 - LDO4 Timeouts */ + 0x001C, /* R211 - LDO4 Low Power */ + 0x0000, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 - VCC_FAULT Masks */ + 0x001F, /* R216 - Main Bandgap Control */ + 0x0000, /* R217 - OSC Control */ + 0x9000, /* R218 - RTC Tick Control */ + 0x0000, /* R219 - Security1 */ + 0x4000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0000, /* R223 */ + 0x0000, /* R224 - Signal overrides */ + 0x0000, /* R225 - DCDC/LDO status */ + 0x0000, /* R226 - Charger Overides/status */ + 0x0000, /* R227 - misc overrides */ + 0x0000, /* R228 - Supply overrides/status 1 */ + 0x0000, /* R229 - Supply overrides/status 2 */ + 0xE000, /* R230 - GPIO Pin Status */ + 0x0000, /* R231 - comparotor overrides */ + 0x0000, /* R232 */ + 0x0000, /* R233 - State Machine status */ + 0x1200, /* R234 - FLL Test 1 */ + 0x0000, /* R235 */ + 0x8000, /* R236 */ + 0x0000, /* R237 */ + 0x0000, /* R238 */ + 0x0000, /* R239 */ + 0x0003, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0004, /* R243 */ + 0x0300, /* R244 */ + 0x0000, /* R245 */ + 0x0200, /* R246 */ + 0x0000, /* R247 */ + 0x1000, /* R248 - DCDC1 Test Controls */ + 0x1000, /* R249 */ + 0x1000, /* R250 - DCDC3 Test Controls */ + 0x1000, /* R251 - DCDC4 Test Controls */ +}; +#endif + #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0 #undef WM8350_HAVE_CONFIG_MODE diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 737579086d01..980669d50dca 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -589,6 +589,10 @@ extern const u16 wm8350_mode0_defaults[]; extern const u16 wm8350_mode1_defaults[]; extern const u16 wm8350_mode2_defaults[]; extern const u16 wm8350_mode3_defaults[]; +extern const u16 wm8351_mode0_defaults[]; +extern const u16 wm8351_mode1_defaults[]; +extern const u16 wm8351_mode2_defaults[]; +extern const u16 wm8351_mode3_defaults[]; extern const u16 wm8352_mode0_defaults[]; extern const u16 wm8352_mode1_defaults[]; extern const u16 wm8352_mode2_defaults[]; -- cgit v1.2.3 From 0081e8020ebd814a99e45720a10e869a54ee08a6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Dec 2008 16:52:33 +0000 Subject: leds: Add WM8350 LED driver The voltage and current regulators on the WM8350 AudioPlus PMIC can be used in concert to provide a power efficient LED driver. This driver implements support for this within the standard LED class. Platform initialisation code should configure the LED hardware in the init callback provided by the WM8350 core driver. The callback should use wm8350_isink_set_flash(), wm8350_dcdc25_set_mode() and wm8350_dcdc_set_slot() to configure the operating parameters of the regulators for their hardware and then then use wm8350_register_led() to instantiate the LED driver. This driver was originally written by Liam Girdwood, though it has been extensively modified since then. Signed-off-by: Mark Brown Signed-off-by: Richard Purdie --- drivers/leds/Kconfig | 7 + drivers/leds/Makefile | 1 + drivers/leds/leds-wm8350.c | 333 +++++++++++++++++++++++++++++++++++ drivers/mfd/wm8350-core.c | 3 + drivers/regulator/wm8350-regulator.c | 91 ++++++++++ include/linux/mfd/wm8350/pmic.h | 36 ++++ 6 files changed, 471 insertions(+) create mode 100644 drivers/leds/leds-wm8350.c (limited to 'include/linux/mfd/wm8350') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 3d0d2625f6ab..a4a1ae214630 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -164,6 +164,13 @@ config LEDS_PCA955X LED driver chips accessed via the I2C bus. Supported devices include PCA9550, PCA9551, PCA9552, and PCA9553. +config LEDS_WM8350 + tristate "LED Support for WM8350 AudioPlus PMIC" + depends on LEDS_CLASS && MFD_WM8350 + help + This option enables support for LEDs driven by the Wolfson + Microelectronics WM8350 AudioPlus PMIC. + config LEDS_DA903X tristate "LED Support for DA9030/DA9034 PMIC" depends on LEDS_CLASS && PMIC_DA903X diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index ff4616a49043..bc247cb02e82 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_HP_DISK) += leds-hp-disk.o +obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o # LED Triggers obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c new file mode 100644 index 000000000000..846ed978103f --- /dev/null +++ b/drivers/leds/leds-wm8350.c @@ -0,0 +1,333 @@ +/* + * LED driver for WM8350 driven LEDS. + * + * Copyright(C) 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 version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 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 +}; + +#define to_wm8350_led(led_cdev) \ + container_of(led_cdev, struct wm8350_led, cdev) + +static void wm8350_led_enable(struct wm8350_led *led) +{ + int ret; + + if (led->enabled) + return; + + ret = regulator_enable(led->isink); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to enable ISINK: %d\n", ret); + return; + } + + ret = regulator_enable(led->dcdc); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to enable DCDC: %d\n", ret); + regulator_disable(led->isink); + return; + } + + led->enabled = 1; +} + +static void wm8350_led_disable(struct wm8350_led *led) +{ + int ret; + + if (!led->enabled) + return; + + ret = regulator_disable(led->dcdc); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to disable DCDC: %d\n", ret); + return; + } + + ret = regulator_disable(led->isink); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to disable ISINK: %d\n", ret); + regulator_enable(led->dcdc); + return; + } + + led->enabled = 0; +} + +static void led_work(struct work_struct *work) +{ + struct wm8350_led *led = container_of(work, struct wm8350_led, work); + int ret; + int uA; + unsigned long flags; + + mutex_lock(&led->mutex); + + spin_lock_irqsave(&led->value_lock, flags); + + if (led->value == LED_OFF) { + spin_unlock_irqrestore(&led->value_lock, flags); + wm8350_led_disable(led); + goto out; + } + + /* This scales linearly into the index of valid current + * settings which results in a linear scaling of perceived + * brightness due to the non-linear current settings provided + * by the hardware. + */ + uA = (led->max_uA_index * led->value) / LED_FULL; + spin_unlock_irqrestore(&led->value_lock, flags); + BUG_ON(uA >= ARRAY_SIZE(isink_cur)); + + ret = regulator_set_current_limit(led->isink, isink_cur[uA], + isink_cur[uA]); + if (ret != 0) + dev_err(led->cdev.dev, "Failed to set %duA: %d\n", + isink_cur[uA], ret); + + wm8350_led_enable(led); + +out: + mutex_unlock(&led->mutex); +} + +static void wm8350_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct wm8350_led *led = to_wm8350_led(led_cdev); + unsigned long flags; + + spin_lock_irqsave(&led->value_lock, flags); + led->value = value; + schedule_work(&led->work); + spin_unlock_irqrestore(&led->value_lock, flags); +} + +#ifdef CONFIG_PM +static int wm8350_led_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct wm8350_led *led = platform_get_drvdata(pdev); + + led_classdev_suspend(&led->cdev); + return 0; +} + +static int wm8350_led_resume(struct platform_device *pdev) +{ + struct wm8350_led *led = platform_get_drvdata(pdev); + + led_classdev_resume(&led->cdev); + return 0; +} +#else +#define wm8350_led_suspend NULL +#define wm8350_led_resume NULL +#endif + +static void wm8350_led_shutdown(struct platform_device *pdev) +{ + struct wm8350_led *led = platform_get_drvdata(pdev); + + mutex_lock(&led->mutex); + led->value = LED_OFF; + wm8350_led_disable(led); + mutex_unlock(&led->mutex); +} + +static int wm8350_led_probe(struct platform_device *pdev) +{ + struct regulator *isink, *dcdc; + struct wm8350_led *led; + struct wm8350_led_platform_data *pdata = pdev->dev.platform_data; + int ret, i; + + if (pdata == NULL) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; + } + + if (pdata->max_uA < isink_cur[0]) { + dev_err(&pdev->dev, "Invalid maximum current %duA\n", + pdata->max_uA); + return -EINVAL; + } + + isink = regulator_get(&pdev->dev, "led_isink"); + if (IS_ERR(isink)) { + printk(KERN_ERR "%s: cant get ISINK\n", __func__); + return PTR_ERR(isink); + } + + dcdc = regulator_get(&pdev->dev, "led_vcc"); + if (IS_ERR(dcdc)) { + printk(KERN_ERR "%s: cant get DCDC\n", __func__); + ret = PTR_ERR(dcdc); + goto err_isink; + } + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (led == NULL) { + ret = -ENOMEM; + goto err_dcdc; + } + + led->cdev.brightness_set = wm8350_led_set; + led->cdev.default_trigger = pdata->default_trigger; + led->cdev.name = pdata->name; + led->enabled = regulator_is_enabled(isink); + led->isink = isink; + led->dcdc = dcdc; + + for (i = 0; i < ARRAY_SIZE(isink_cur) - 1; i++) + if (isink_cur[i] >= pdata->max_uA) + break; + led->max_uA_index = i; + if (pdata->max_uA != isink_cur[i]) + dev_warn(&pdev->dev, + "Maximum current %duA is not directly supported," + " check platform data\n", + pdata->max_uA); + + spin_lock_init(&led->value_lock); + mutex_init(&led->mutex); + INIT_WORK(&led->work, led_work); + led->value = LED_OFF; + platform_set_drvdata(pdev, led); + + ret = led_classdev_register(&pdev->dev, &led->cdev); + if (ret < 0) + goto err_led; + + return 0; + + err_led: + kfree(led); + err_dcdc: + regulator_put(dcdc); + err_isink: + regulator_put(isink); + return ret; +} + +static int wm8350_led_remove(struct platform_device *pdev) +{ + struct wm8350_led *led = platform_get_drvdata(pdev); + + led_classdev_unregister(&led->cdev); + flush_scheduled_work(); + wm8350_led_disable(led); + regulator_put(led->dcdc); + regulator_put(led->isink); + kfree(led); + return 0; +} + +static struct platform_driver wm8350_led_driver = { + .driver = { + .name = "wm8350-led", + .owner = THIS_MODULE, + }, + .probe = wm8350_led_probe, + .remove = wm8350_led_remove, + .shutdown = wm8350_led_shutdown, + .suspend = wm8350_led_suspend, + .resume = wm8350_led_resume, +}; + +static int __devinit wm8350_led_init(void) +{ + return platform_driver_register(&wm8350_led_driver); +} +module_init(wm8350_led_init); + +static void wm8350_led_exit(void) +{ + platform_driver_unregister(&wm8350_led_driver); +} +module_exit(wm8350_led_exit); + +MODULE_AUTHOR("Mark Brown"); +MODULE_DESCRIPTION("WM8350 LED driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-led"); diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 3a273ccef3f2..f92595c8f165 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -1453,6 +1453,9 @@ void wm8350_device_exit(struct wm8350 *wm8350) { int i; + for (i = 0; i < ARRAY_SIZE(wm8350->pmic.led); i++) + platform_device_unregister(wm8350->pmic.led[i].pdev); + for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++) platform_device_unregister(wm8350->pmic.pdev[i]); diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index c68c496b2c49..7aa35248181b 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1412,6 +1412,97 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg, } EXPORT_SYMBOL_GPL(wm8350_register_regulator); +/** + * wm8350_register_led - Register a WM8350 LED output + * + * @param wm8350 The WM8350 device to configure. + * @param lednum LED device index to create. + * @param dcdc The DCDC to use for the LED. + * @param isink The ISINK to use for the LED. + * @param pdata Configuration for the LED. + * + * The WM8350 supports the use of an ISINK together with a DCDC to + * provide a power-efficient LED driver. This function registers the + * regulators and instantiates the platform device for a LED. The + * operating modes for the LED regulators must be configured using + * wm8350_isink_set_flash(), wm8350_dcdc25_set_mode() and + * wm8350_dcdc_set_slot() prior to calling this function. + */ +int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, + struct wm8350_led_platform_data *pdata) +{ + struct wm8350_led *led; + struct platform_device *pdev; + int ret; + + if (lednum > ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) { + dev_err(wm8350->dev, "Invalid LED index %d\n", lednum); + return -ENODEV; + } + + led = &wm8350->pmic.led[lednum]; + + if (led->pdev) { + dev_err(wm8350->dev, "LED %d already allocated\n", lednum); + return -EINVAL; + } + + pdev = platform_device_alloc("wm8350-led", lednum); + if (pdev == NULL) { + dev_err(wm8350->dev, "Failed to allocate LED %d\n", lednum); + return -ENOMEM; + } + + led->isink_consumer.dev = &pdev->dev; + led->isink_consumer.supply = "led_isink"; + led->isink_init.num_consumer_supplies = 1; + led->isink_init.consumer_supplies = &led->isink_consumer; + led->isink_init.constraints.min_uA = 0; + led->isink_init.constraints.max_uA = pdata->max_uA; + led->isink_init.constraints.valid_ops_mask = REGULATOR_CHANGE_CURRENT; + led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL; + ret = wm8350_register_regulator(wm8350, isink, &led->isink_init); + if (ret != 0) { + platform_device_put(pdev); + return ret; + } + + led->dcdc_consumer.dev = &pdev->dev; + led->dcdc_consumer.supply = "led_vcc"; + led->dcdc_init.num_consumer_supplies = 1; + led->dcdc_init.consumer_supplies = &led->dcdc_consumer; + led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL; + ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init); + if (ret != 0) { + platform_device_put(pdev); + return ret; + } + + switch (isink) { + case WM8350_ISINK_A: + wm8350->pmic.isink_A_dcdc = dcdc; + break; + case WM8350_ISINK_B: + wm8350->pmic.isink_B_dcdc = dcdc; + break; + } + + pdev->dev.platform_data = pdata; + pdev->dev.parent = wm8350->dev; + ret = platform_device_add(pdev); + if (ret != 0) { + dev_err(wm8350->dev, "Failed to register LED %d: %d\n", + lednum, ret); + platform_device_put(pdev); + return ret; + } + + led->pdev = pdev; + + return 0; +} +EXPORT_SYMBOL_GPL(wm8350_register_led); + static struct platform_driver wm8350_regulator_driver = { .probe = wm8350_regulator_probe, .remove = wm8350_regulator_remove, diff --git a/include/linux/mfd/wm8350/pmic.h b/include/linux/mfd/wm8350/pmic.h index 96acbfc8aa12..be3264e286e0 100644 --- a/include/linux/mfd/wm8350/pmic.h +++ b/include/linux/mfd/wm8350/pmic.h @@ -13,6 +13,10 @@ #ifndef __LINUX_MFD_WM8350_PMIC_H #define __LINUX_MFD_WM8350_PMIC_H +#include +#include +#include + /* * Register values. */ @@ -700,6 +704,33 @@ struct wm8350; struct platform_device; struct regulator_init_data; +/* + * WM8350 LED platform data + */ +struct wm8350_led_platform_data { + const char *name; + const char *default_trigger; + int max_uA; +}; + +struct wm8350_led { + struct platform_device *pdev; + struct mutex mutex; + struct work_struct work; + spinlock_t value_lock; + enum led_brightness value; + struct led_classdev cdev; + int max_uA_index; + int enabled; + + struct regulator *isink; + struct regulator_consumer_supply isink_consumer; + struct regulator_init_data isink_init; + struct regulator *dcdc; + struct regulator_consumer_supply dcdc_consumer; + struct regulator_init_data dcdc_init; +}; + struct wm8350_pmic { /* Number of regulators of each type on this device */ int max_dcdc; @@ -717,10 +748,15 @@ struct wm8350_pmic { /* regulator devices */ struct platform_device *pdev[NUM_WM8350_REGULATORS]; + + /* LED devices */ + struct wm8350_led led[2]; }; int wm8350_register_regulator(struct wm8350 *wm8350, int reg, struct regulator_init_data *initdata); +int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, + struct wm8350_led_platform_data *pdata); /* * Additional DCDC control not supported via regulator API -- cgit v1.2.3