2009-10-01 14:41:14

by Mark Brown

[permalink] [raw]
Subject: [PATCH 1/4] mfd: Refactor WM831x chip identification

Better support future device revisions by moving some of the output
around and making the chip ID enumeration be the value expected in
the ID register.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/mfd/wm831x-core.c | 58 ++++++++++++++-------------------------------
1 files changed, 18 insertions(+), 40 deletions(-)

diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 49b7885..143ab83 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -90,9 +90,9 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL] = {
EXPORT_SYMBOL_GPL(wm831x_isinkv_values);

enum wm831x_parent {
- WM8310 = 0,
- WM8311 = 1,
- WM8312 = 2,
+ WM8310 = 0x8310,
+ WM8311 = 0x8311,
+ WM8312 = 0x8312,
};

static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
@@ -1282,50 +1282,28 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
goto err;
}

+ /* Some engineering samples do not have the ID set, rely on
+ * the device being registered correctly.
+ */
+ if (ret == 0) {
+ dev_info(wm831x->dev, "Device is an engineering sample\n");
+ ret = id;
+ }
+
switch (ret) {
- case 0x8310:
+ case WM8310:
parent = WM8310;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM8310 revision %c\n",
- 'A' + rev);
- break;
- }
+ dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
break;

- case 0x8311:
+ case WM8311:
parent = WM8311;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM8311 revision %c\n",
- 'A' + rev);
- break;
- }
+ dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
break;

- case 0x8312:
+ case WM8312:
parent = WM8312;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM8312 revision %c\n",
- 'A' + rev);
- break;
- }
- break;
-
- case 0:
- /* Some engineering samples do not have the ID set,
- * rely on the device being registered correctly.
- * This will need revisiting for future devices with
- * multiple dies.
- */
- parent = id;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM831%d ES revision %c\n",
- parent, 'A' + rev);
- break;
- }
+ dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
break;

default:
@@ -1338,7 +1316,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
* current parts.
*/
if (parent != id)
- dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n",
+ dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
id);

/* Bootstrap the user key */
--
1.6.4.3


2009-10-01 14:41:20

by Mark Brown

[permalink] [raw]
Subject: [PATCH 2/4] gpiolib: Make WM831x GPIO count dynamic

This supports future devices with fewer GPIOs.

Signed-off-by: Mark Brown <[email protected]>
Cc: David Brownell <[email protected]>
---
drivers/gpio/wm831x-gpio.c | 4 +---
drivers/mfd/wm831x-core.c | 3 +++
include/linux/mfd/wm831x/core.h | 2 ++
3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c
index f9c09a5..f5e4934 100644
--- a/drivers/gpio/wm831x-gpio.c
+++ b/drivers/gpio/wm831x-gpio.c
@@ -23,8 +23,6 @@
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/gpio.h>

-#define WM831X_GPIO_MAX 16
-
struct wm831x_gpio {
struct wm831x *wm831x;
struct gpio_chip gpio_chip;
@@ -192,7 +190,7 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)

wm831x_gpio->wm831x = wm831x;
wm831x_gpio->gpio_chip = template_chip;
- wm831x_gpio->gpio_chip.ngpio = WM831X_GPIO_MAX;
+ wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
wm831x_gpio->gpio_chip.dev = &pdev->dev;
if (pdata && pdata->gpio_base)
wm831x_gpio->gpio_chip.base = pdata->gpio_base;
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 143ab83..fa651e5 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1293,16 +1293,19 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
switch (ret) {
case WM8310:
parent = WM8310;
+ wm831x->num_gpio = 16;
dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
break;

case WM8311:
parent = WM8311;
+ wm831x->num_gpio = 16;
dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
break;

case WM8312:
parent = WM8312;
+ wm831x->num_gpio = 16;
dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
break;

diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index 91eb493..c1bc59f 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -253,6 +253,8 @@ struct wm831x {
unsigned int irq_base;
int irq_masks[5];

+ int num_gpio;
+
struct mutex auxadc_lock;

/* The WM831x has a security key blocking access to certain
--
1.6.4.3

2009-10-01 14:41:32

by Mark Brown

[permalink] [raw]
Subject: [PATCH 3/4] power_supply: Factor out WM831x backup battery charger

The backup battery on WM831x is a separate IP block to the main PMU and
is largely unrelated to the main supply functionality. Factor it out into
a separate driver in order to reflect this and better support future
hardware versions.

Signed-off-by: Mark Brown <[email protected]>
Cc: Anton Vorontsov <[email protected]>
---
drivers/mfd/wm831x-core.c | 9 ++
drivers/power/Kconfig | 7 ++
drivers/power/Makefile | 1 +
drivers/power/wm831x_backup.c | 233 +++++++++++++++++++++++++++++++++++++++++
drivers/power/wm831x_power.c | 144 +-------------------------
5 files changed, 253 insertions(+), 141 deletions(-)
create mode 100644 drivers/power/wm831x_backup.c

diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index fa651e5..45d6770 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -794,6 +794,9 @@ static struct resource wm831x_wdt_resources[] = {

static struct mfd_cell wm8310_devs[] = {
{
+ .name = "wm831x-backup",
+ },
+ {
.name = "wm831x-buckv",
.id = 1,
.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
@@ -947,6 +950,9 @@ static struct mfd_cell wm8310_devs[] = {

static struct mfd_cell wm8311_devs[] = {
{
+ .name = "wm831x-backup",
+ },
+ {
.name = "wm831x-buckv",
.id = 1,
.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
@@ -1081,6 +1087,9 @@ static struct mfd_cell wm8311_devs[] = {

static struct mfd_cell wm8312_devs[] = {
{
+ .name = "wm831x-backup",
+ },
+ {
.name = "wm831x-buckv",
.id = 1,
.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index cea6cef..783e9b7 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 WM831X_BACKUP
+ tristate "WM831X backup battery charger support"
+ depends on MFD_WM831X
+ help
+ Say Y here to enable support for the backup battery charger
+ in the Wolfson Microelectronics WM831x PMICs.
+
config WM831X_POWER
tristate "WM831X PMU support"
depends on MFD_WM831X
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index b96f29d..d1406b9 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_WM831X_BACKUP) += wm831x_backup.o
obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
obj-$(CONFIG_WM8350_POWER) += wm8350_power.o

diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c
new file mode 100644
index 0000000..f181076
--- /dev/null
+++ b/drivers/power/wm831x_backup.c
@@ -0,0 +1,233 @@
+/*
+ * Backup battery driver for Wolfson Microelectronics wm831x PMICs
+ *
+ * Copyright 2009 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 <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/auxadc.h>
+#include <linux/mfd/wm831x/pmu.h>
+#include <linux/mfd/wm831x/pdata.h>
+
+struct wm831x_backup {
+ struct wm831x *wm831x;
+ struct power_supply backup;
+};
+
+static int wm831x_backup_read_voltage(struct wm831x *wm831x,
+ enum wm831x_auxadc src,
+ union power_supply_propval *val)
+{
+ int ret;
+
+ ret = wm831x_auxadc_read_uv(wm831x, src);
+ if (ret >= 0)
+ val->intval = ret;
+
+ return ret;
+}
+
+/*********************************************************************
+ * Backup supply properties
+ *********************************************************************/
+
+static void wm831x_config_backup(struct wm831x *wm831x)
+{
+ struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
+ struct wm831x_backup_pdata *pdata;
+ int ret, reg;
+
+ if (!wm831x_pdata || !wm831x_pdata->backup) {
+ dev_warn(wm831x->dev,
+ "No backup battery charger configuration\n");
+ return;
+ }
+
+ pdata = wm831x_pdata->backup;
+
+ reg = 0;
+
+ if (pdata->charger_enable)
+ reg |= WM831X_BKUP_CHG_ENA | WM831X_BKUP_BATT_DET_ENA;
+ if (pdata->no_constant_voltage)
+ reg |= WM831X_BKUP_CHG_MODE;
+
+ switch (pdata->vlim) {
+ case 2500:
+ break;
+ case 3100:
+ reg |= WM831X_BKUP_CHG_VLIM;
+ break;
+ default:
+ dev_err(wm831x->dev, "Invalid backup voltage limit %dmV\n",
+ pdata->vlim);
+ }
+
+ switch (pdata->ilim) {
+ case 100:
+ break;
+ case 200:
+ reg |= 1;
+ break;
+ case 300:
+ reg |= 2;
+ break;
+ case 400:
+ reg |= 3;
+ break;
+ default:
+ dev_err(wm831x->dev, "Invalid backup current limit %duA\n",
+ pdata->ilim);
+ }
+
+ ret = wm831x_reg_unlock(wm831x);
+ if (ret != 0) {
+ dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret);
+ return;
+ }
+
+ ret = wm831x_set_bits(wm831x, WM831X_BACKUP_CHARGER_CONTROL,
+ WM831X_BKUP_CHG_ENA_MASK |
+ WM831X_BKUP_CHG_MODE_MASK |
+ WM831X_BKUP_BATT_DET_ENA_MASK |
+ WM831X_BKUP_CHG_VLIM_MASK |
+ WM831X_BKUP_CHG_ILIM_MASK,
+ reg);
+ if (ret != 0)
+ dev_err(wm831x->dev,
+ "Failed to set backup charger config: %d\n", ret);
+
+ wm831x_reg_lock(wm831x);
+}
+
+static int wm831x_backup_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wm831x_backup *devdata = dev_get_drvdata(psy->dev->parent);
+ struct wm831x *wm831x = devdata->wm831x;
+ int ret = 0;
+
+ ret = wm831x_reg_read(wm831x, WM831X_BACKUP_CHARGER_CONTROL);
+ if (ret < 0)
+ return ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (ret & WM831X_BKUP_CHG_STS)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = wm831x_backup_read_voltage(wm831x, WM831X_AUX_BKUP_BATT,
+ val);
+ break;
+
+ case POWER_SUPPLY_PROP_PRESENT:
+ if (ret & WM831X_BKUP_CHG_STS)
+ val->intval = 1;
+ else
+ val->intval = 0;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property wm831x_backup_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_PRESENT,
+};
+
+/*********************************************************************
+ * Initialisation
+ *********************************************************************/
+
+static __devinit int wm831x_backup_probe(struct platform_device *pdev)
+{
+ struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+ struct wm831x_backup *devdata;
+ struct power_supply *backup;
+ int ret, irq, i;
+
+ devdata = kzalloc(sizeof(struct wm831x_backup), GFP_KERNEL);
+ if (devdata == NULL)
+ return -ENOMEM;
+
+ devdata->wm831x = wm831x;
+ platform_set_drvdata(pdev, devdata);
+
+ backup = &devdata->backup;
+
+ /* We ignore configuration failures since we can still read
+ * back the status without enabling the charger (which may
+ * already be enabled anyway).
+ */
+ wm831x_config_backup(wm831x);
+
+ backup->name = "wm831x-backup";
+ backup->type = POWER_SUPPLY_TYPE_BATTERY;
+ backup->properties = wm831x_backup_props;
+ backup->num_properties = ARRAY_SIZE(wm831x_backup_props);
+ backup->get_property = wm831x_backup_get_prop;
+ ret = power_supply_register(&pdev->dev, backup);
+ if (ret)
+ goto err_kmalloc;
+
+ return ret;
+
+err_kmalloc:
+ kfree(devdata);
+ return ret;
+}
+
+static __devexit int wm831x_backup_remove(struct platform_device *pdev)
+{
+ struct wm831x_backup *devdata = platform_get_drvdata(pdev);
+
+ power_supply_unregister(&devdata->backup);
+ kfree(devdata);
+
+ return 0;
+}
+
+static struct platform_driver wm831x_backup_driver = {
+ .probe = wm831x_backup_probe,
+ .remove = __devexit_p(wm831x_backup_remove),
+ .driver = {
+ .name = "wm831x-backup",
+ },
+};
+
+static int __init wm831x_backup_init(void)
+{
+ return platform_driver_register(&wm831x_backup_driver);
+}
+module_init(wm831x_backup_init);
+
+static void __exit wm831x_backup_exit(void)
+{
+ platform_driver_unregister(&wm831x_backup_driver);
+}
+module_exit(wm831x_backup_exit);
+
+MODULE_DESCRIPTION("Backup battery charger driver for WM831x PMICs");
+MODULE_AUTHOR("Mark Brown <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-backup");
diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c
index 2a4c8b0..f85e80b 100644
--- a/drivers/power/wm831x_power.c
+++ b/drivers/power/wm831x_power.c
@@ -21,7 +21,6 @@
struct wm831x_power {
struct wm831x *wm831x;
struct power_supply wall;
- struct power_supply backup;
struct power_supply usb;
struct power_supply battery;
};
@@ -454,125 +453,6 @@ static irqreturn_t wm831x_bat_irq(int irq, void *data)


/*********************************************************************
- * Backup supply properties
- *********************************************************************/
-
-static void wm831x_config_backup(struct wm831x *wm831x)
-{
- struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
- struct wm831x_backup_pdata *pdata;
- int ret, reg;
-
- if (!wm831x_pdata || !wm831x_pdata->backup) {
- dev_warn(wm831x->dev,
- "No backup battery charger configuration\n");
- return;
- }
-
- pdata = wm831x_pdata->backup;
-
- reg = 0;
-
- if (pdata->charger_enable)
- reg |= WM831X_BKUP_CHG_ENA | WM831X_BKUP_BATT_DET_ENA;
- if (pdata->no_constant_voltage)
- reg |= WM831X_BKUP_CHG_MODE;
-
- switch (pdata->vlim) {
- case 2500:
- break;
- case 3100:
- reg |= WM831X_BKUP_CHG_VLIM;
- break;
- default:
- dev_err(wm831x->dev, "Invalid backup voltage limit %dmV\n",
- pdata->vlim);
- }
-
- switch (pdata->ilim) {
- case 100:
- break;
- case 200:
- reg |= 1;
- break;
- case 300:
- reg |= 2;
- break;
- case 400:
- reg |= 3;
- break;
- default:
- dev_err(wm831x->dev, "Invalid backup current limit %duA\n",
- pdata->ilim);
- }
-
- ret = wm831x_reg_unlock(wm831x);
- if (ret != 0) {
- dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret);
- return;
- }
-
- ret = wm831x_set_bits(wm831x, WM831X_BACKUP_CHARGER_CONTROL,
- WM831X_BKUP_CHG_ENA_MASK |
- WM831X_BKUP_CHG_MODE_MASK |
- WM831X_BKUP_BATT_DET_ENA_MASK |
- WM831X_BKUP_CHG_VLIM_MASK |
- WM831X_BKUP_CHG_ILIM_MASK,
- reg);
- if (ret != 0)
- dev_err(wm831x->dev,
- "Failed to set backup charger config: %d\n", ret);
-
- wm831x_reg_lock(wm831x);
-}
-
-static int wm831x_backup_get_prop(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent);
- struct wm831x *wm831x = wm831x_power->wm831x;
- int ret = 0;
-
- ret = wm831x_reg_read(wm831x, WM831X_BACKUP_CHARGER_CONTROL);
- if (ret < 0)
- return ret;
-
- switch (psp) {
- case POWER_SUPPLY_PROP_STATUS:
- if (ret & WM831X_BKUP_CHG_STS)
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
- else
- val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
- break;
-
- case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BKUP_BATT,
- val);
- break;
-
- case POWER_SUPPLY_PROP_PRESENT:
- if (ret & WM831X_BKUP_CHG_STS)
- val->intval = 1;
- else
- val->intval = 0;
- break;
-
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static enum power_supply_property wm831x_backup_props[] = {
- POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_VOLTAGE_NOW,
- POWER_SUPPLY_PROP_PRESENT,
-};
-
-/*********************************************************************
* Initialisation
*********************************************************************/

@@ -595,10 +475,7 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)

dev_dbg(wm831x->dev, "Power source changed\n");

- /* Just notify for everything - little harm in overnotifying.
- * The backup battery is not a power source while the system
- * is running so skip that.
- */
+ /* Just notify for everything - little harm in overnotifying. */
power_supply_changed(&wm831x_power->battery);
power_supply_changed(&wm831x_power->usb);
power_supply_changed(&wm831x_power->wall);
@@ -613,7 +490,6 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
struct power_supply *usb;
struct power_supply *battery;
struct power_supply *wall;
- struct power_supply *backup;
int ret, irq, i;

power = kzalloc(sizeof(struct wm831x_power), GFP_KERNEL);
@@ -626,13 +502,11 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
usb = &power->usb;
battery = &power->battery;
wall = &power->wall;
- backup = &power->backup;

/* We ignore configuration failures since we can still read back
- * the status without enabling either of the chargers.
+ * the status without enabling the charger.
*/
wm831x_config_battery(wm831x);
- wm831x_config_backup(wm831x);

wall->name = "wm831x-wall";
wall->type = POWER_SUPPLY_TYPE_MAINS;
@@ -661,15 +535,6 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
if (ret)
goto err_battery;

- backup->name = "wm831x-backup";
- backup->type = POWER_SUPPLY_TYPE_BATTERY;
- backup->properties = wm831x_backup_props;
- backup->num_properties = ARRAY_SIZE(wm831x_backup_props);
- backup->get_property = wm831x_backup_get_prop;
- ret = power_supply_register(&pdev->dev, backup);
- if (ret)
- goto err_usb;
-
irq = platform_get_irq_byname(pdev, "SYSLO");
ret = wm831x_request_irq(wm831x, irq, wm831x_syslo_irq,
IRQF_TRIGGER_RISING, "SYSLO",
@@ -677,7 +542,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
irq, ret);
- goto err_backup;
+ goto err_usb;
}

irq = platform_get_irq_byname(pdev, "PWR SRC");
@@ -716,8 +581,6 @@ err_bat_irq:
err_syslo:
irq = platform_get_irq_byname(pdev, "SYSLO");
wm831x_free_irq(wm831x, irq, power);
-err_backup:
- power_supply_unregister(backup);
err_usb:
power_supply_unregister(usb);
err_battery:
@@ -746,7 +609,6 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev)
irq = platform_get_irq_byname(pdev, "SYSLO");
wm831x_free_irq(wm831x, irq, wm831x_power);

- power_supply_unregister(&wm831x_power->backup);
power_supply_unregister(&wm831x_power->battery);
power_supply_unregister(&wm831x_power->wall);
power_supply_unregister(&wm831x_power->usb);
--
1.6.4.3

2009-10-01 14:41:23

by Mark Brown

[permalink] [raw]
Subject: [PATCH 4/4] mfd: Add support for WM8320 PMICs

The WM8320 is an integrated power management subsystem providing
voltage regulators, RTC, watchdog and other functionality. The
WM8320 is derived from the WM831x and therefore shares most of
the driver code with the WM831x.

Signed-off-by: Mark Brown <[email protected]>
---
drivers/mfd/Kconfig | 6 +-
drivers/mfd/wm831x-core.c | 159 +++++++++++++++++++++++++++++++++++++++
include/linux/mfd/wm831x/core.h | 1 +
3 files changed, 163 insertions(+), 3 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 570be13..f88cce4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -171,12 +171,12 @@ config MFD_WM8400
the functionality of the device.

config MFD_WM831X
- tristate "Support Wolfson Microelectronics WM831x PMICs"
+ tristate "Support Wolfson Microelectronics WM831x/2x PMICs"
select MFD_CORE
depends on I2C
help
- Support for the Wolfson Microelecronics WM831x PMICs. This
- driver provides common support for accessing the device,
+ Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
+ This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.

diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 45d6770..015df29 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -93,6 +93,7 @@ enum wm831x_parent {
WM8310 = 0x8310,
WM8311 = 0x8311,
WM8312 = 0x8312,
+ WM8320 = 0x8320,
};

static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
@@ -478,6 +479,20 @@ static struct resource wm831x_dcdc4_resources[] = {
},
};

+static struct resource wm8320_dcdc4_buck_resources[] = {
+ {
+ .start = WM831X_DC4_CONTROL,
+ .end = WM832X_DC4_SLEEP_CONTROL,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "UV",
+ .start = WM831X_IRQ_UV_DC4,
+ .end = WM831X_IRQ_UV_DC4,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct resource wm831x_gpio_resources[] = {
{
.start = WM831X_IRQ_GPIO_1,
@@ -1246,6 +1261,137 @@ static struct mfd_cell wm8312_devs[] = {
},
};

+static struct mfd_cell wm8320_devs[] = {
+ {
+ .name = "wm831x-backup",
+ },
+ {
+ .name = "wm831x-buckv",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
+ .resources = wm831x_dcdc1_resources,
+ },
+ {
+ .name = "wm831x-buckv",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
+ .resources = wm831x_dcdc2_resources,
+ },
+ {
+ .name = "wm831x-buckp",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
+ .resources = wm831x_dcdc3_resources,
+ },
+ {
+ .name = "wm831x-buckp",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
+ .resources = wm8320_dcdc4_buck_resources,
+ },
+ {
+ .name = "wm831x-gpio",
+ .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
+ .resources = wm831x_gpio_resources,
+ },
+ {
+ .name = "wm831x-hwmon",
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
+ .resources = wm831x_ldo1_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
+ .resources = wm831x_ldo2_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
+ .resources = wm831x_ldo3_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
+ .resources = wm831x_ldo4_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 5,
+ .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
+ .resources = wm831x_ldo5_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 6,
+ .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
+ .resources = wm831x_ldo6_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 7,
+ .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
+ .resources = wm831x_ldo7_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 8,
+ .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
+ .resources = wm831x_ldo8_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 9,
+ .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
+ .resources = wm831x_ldo9_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 10,
+ .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
+ .resources = wm831x_ldo10_resources,
+ },
+ {
+ .name = "wm831x-alive-ldo",
+ .id = 11,
+ .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
+ .resources = wm831x_ldo11_resources,
+ },
+ {
+ .name = "wm831x-on",
+ .num_resources = ARRAY_SIZE(wm831x_on_resources),
+ .resources = wm831x_on_resources,
+ },
+ {
+ .name = "wm831x-rtc",
+ .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
+ .resources = wm831x_rtc_resources,
+ },
+ {
+ .name = "wm831x-status",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(wm831x_status1_resources),
+ .resources = wm831x_status1_resources,
+ },
+ {
+ .name = "wm831x-status",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(wm831x_status2_resources),
+ .resources = wm831x_status2_resources,
+ },
+ {
+ .name = "wm831x-watchdog",
+ .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
+ .resources = wm831x_wdt_resources,
+ },
+};
+
static struct mfd_cell backlight_devs[] = {
{
.name = "wm831x-backlight",
@@ -1318,6 +1464,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
break;

+ case WM8320:
+ parent = WM8320;
+ wm831x->num_gpio = 12;
+ dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
+ break;
+
default:
dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
ret = -EINVAL;
@@ -1376,6 +1528,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
NULL, 0);
break;

+ case WM8320:
+ ret = mfd_add_devices(wm831x->dev, -1,
+ wm8320_devs, ARRAY_SIZE(wm8320_devs),
+ NULL, 0);
+ break;
+
default:
/* If this happens the bus probe function is buggy */
BUG();
@@ -1501,6 +1659,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8310", WM8310 },
{ "wm8311", WM8311 },
{ "wm8312", WM8312 },
+ { "wm8320", WM8320 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index c1bc59f..d01d293 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -117,6 +117,7 @@
#define WM831X_DC3_SLEEP_CONTROL 0x4063
#define WM831X_DC4_CONTROL 0x4064
#define WM831X_DC4_SLEEP_CONTROL 0x4065
+#define WM832X_DC4_SLEEP_CONTROL 0x4067
#define WM831X_EPE1_CONTROL 0x4066
#define WM831X_EPE2_CONTROL 0x4067
#define WM831X_LDO1_CONTROL 0x4068
--
1.6.4.3

2009-10-01 14:55:15

by Anton Vorontsov

[permalink] [raw]
Subject: Re: [PATCH 3/4] power_supply: Factor out WM831x backup battery charger

On Thu, Oct 01, 2009 at 03:41:06PM +0100, Mark Brown wrote:
> The backup battery on WM831x is a separate IP block to the main PMU and
> is largely unrelated to the main supply functionality. Factor it out into
> a separate driver in order to reflect this and better support future
> hardware versions.
>
> Signed-off-by: Mark Brown <[email protected]>
> Cc: Anton Vorontsov <[email protected]>

Looks good. Should I apply it, or it depends on 1/4 and 2/4?

Thanks,

--
Anton Vorontsov
email: [email protected]
irc://irc.freenode.net/bd2

2009-10-01 15:03:29

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 3/4] power_supply: Factor out WM831x backup battery charger

On Thu, Oct 01, 2009 at 06:55:00PM +0400, Anton Vorontsov wrote:

> Looks good. Should I apply it, or it depends on 1/4 and 2/4?

There should be no build time dependency so you should be able to apply
it. It'd mean that the WM8320 won't get the backup battery charger
instantiating until it's merged with the power tree but that's not a
terribly big deal and it would avoid the possibility of any merge issues
from a colliding Makefile/Kconfig change in drivers/power.

Samuel, do you have any preferences?

2009-10-01 15:25:50

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH 3/4] power_supply: Factor out WM831x backup battery charger

On Thu, Oct 01, 2009 at 04:03:31PM +0100, Mark Brown wrote:
> On Thu, Oct 01, 2009 at 06:55:00PM +0400, Anton Vorontsov wrote:
>
> > Looks good. Should I apply it, or it depends on 1/4 and 2/4?
>
> There should be no build time dependency so you should be able to apply
> it. It'd mean that the WM8320 won't get the backup battery charger
> instantiating until it's merged with the power tree but that's not a
> terribly big deal and it would avoid the possibility of any merge issues
> from a colliding Makefile/Kconfig change in drivers/power.
>
> Samuel, do you have any preferences?
I'm fine with Anton taking it if that makes everyone's life easier.
Anton, you can add my Acked-by for the mfd part, if you think that's
necessary.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2009-10-01 15:30:30

by Anton Vorontsov

[permalink] [raw]
Subject: Re: [PATCH 3/4] power_supply: Factor out WM831x backup battery charger

On Thu, Oct 01, 2009 at 05:27:47PM +0200, Samuel Ortiz wrote:
> On Thu, Oct 01, 2009 at 04:03:31PM +0100, Mark Brown wrote:
> > On Thu, Oct 01, 2009 at 06:55:00PM +0400, Anton Vorontsov wrote:
> >
> > > Looks good. Should I apply it, or it depends on 1/4 and 2/4?
> >
> > There should be no build time dependency so you should be able to apply
> > it. It'd mean that the WM8320 won't get the backup battery charger
> > instantiating until it's merged with the power tree but that's not a
> > terribly big deal and it would avoid the possibility of any merge issues
> > from a colliding Makefile/Kconfig change in drivers/power.
> >
> > Samuel, do you have any preferences?
> I'm fine with Anton taking it if that makes everyone's life easier.
> Anton, you can add my Acked-by for the mfd part, if you think that's
> necessary.

Great, thanks!

--
Anton Vorontsov
email: [email protected]
irc://irc.freenode.net/bd2

2009-10-01 15:33:11

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH 1/4] mfd: Refactor WM831x chip identification

Hi Mark,

On Thu, Oct 01, 2009 at 03:41:04PM +0100, Mark Brown wrote:
> Better support future device revisions by moving some of the output
> around and making the chip ID enumeration be the value expected in
> the ID register.
Patches 1,2 and 4 applied to my for-next branch, thanks a lot.

Cheers,
Samuel.


> Signed-off-by: Mark Brown <[email protected]>
> ---
> drivers/mfd/wm831x-core.c | 58 ++++++++++++++-------------------------------
> 1 files changed, 18 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
> index 49b7885..143ab83 100644
> --- a/drivers/mfd/wm831x-core.c
> +++ b/drivers/mfd/wm831x-core.c
> @@ -90,9 +90,9 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL] = {
> EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
>
> enum wm831x_parent {
> - WM8310 = 0,
> - WM8311 = 1,
> - WM8312 = 2,
> + WM8310 = 0x8310,
> + WM8311 = 0x8311,
> + WM8312 = 0x8312,
> };
>
> static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
> @@ -1282,50 +1282,28 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
> goto err;
> }
>
> + /* Some engineering samples do not have the ID set, rely on
> + * the device being registered correctly.
> + */
> + if (ret == 0) {
> + dev_info(wm831x->dev, "Device is an engineering sample\n");
> + ret = id;
> + }
> +
> switch (ret) {
> - case 0x8310:
> + case WM8310:
> parent = WM8310;
> - switch (rev) {
> - case 0:
> - dev_info(wm831x->dev, "WM8310 revision %c\n",
> - 'A' + rev);
> - break;
> - }
> + dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
> break;
>
> - case 0x8311:
> + case WM8311:
> parent = WM8311;
> - switch (rev) {
> - case 0:
> - dev_info(wm831x->dev, "WM8311 revision %c\n",
> - 'A' + rev);
> - break;
> - }
> + dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
> break;
>
> - case 0x8312:
> + case WM8312:
> parent = WM8312;
> - switch (rev) {
> - case 0:
> - dev_info(wm831x->dev, "WM8312 revision %c\n",
> - 'A' + rev);
> - break;
> - }
> - break;
> -
> - case 0:
> - /* Some engineering samples do not have the ID set,
> - * rely on the device being registered correctly.
> - * This will need revisiting for future devices with
> - * multiple dies.
> - */
> - parent = id;
> - switch (rev) {
> - case 0:
> - dev_info(wm831x->dev, "WM831%d ES revision %c\n",
> - parent, 'A' + rev);
> - break;
> - }
> + dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
> break;
>
> default:
> @@ -1338,7 +1316,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
> * current parts.
> */
> if (parent != id)
> - dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n",
> + dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
> id);
>
> /* Bootstrap the user key */
> --
> 1.6.4.3
>

--
Intel Open Source Technology Centre
http://oss.intel.com/