From eb503dc16b04d07a42a37892da73c74461fd06da Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Jun 2011 19:18:48 +0100 Subject: mfd: Implement support for multiple WM831x devices Systems using this functionality will be uncommon. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/mfd/wm831x-core.c') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 265f75fc6a2..04994b23bb6 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1440,7 +1440,7 @@ static struct mfd_cell backlight_devs[] = { int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) { struct wm831x_pdata *pdata = wm831x->dev->platform_data; - int rev; + int rev, wm831x_num; enum wm831x_parent parent; int ret, i; @@ -1592,6 +1592,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) } } + /* Multiply by 10 as we have many subdevices of the same type */ + if (pdata && pdata->wm831x_num) + wm831x_num = pdata->wm831x_num * 10; + else + wm831x_num = -1; + ret = wm831x_irq_init(wm831x, irq); if (ret != 0) goto err; @@ -1609,19 +1615,19 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) /* The core device is up, instantiate the subdevices. */ switch (parent) { case WM8310: - ret = mfd_add_devices(wm831x->dev, -1, + ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8310_devs, ARRAY_SIZE(wm8310_devs), NULL, wm831x->irq_base); break; case WM8311: - ret = mfd_add_devices(wm831x->dev, -1, + ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8311_devs, ARRAY_SIZE(wm8311_devs), NULL, wm831x->irq_base); break; case WM8312: - ret = mfd_add_devices(wm831x->dev, -1, + ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8312_devs, ARRAY_SIZE(wm8312_devs), NULL, wm831x->irq_base); break; @@ -1630,7 +1636,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) case WM8321: case WM8325: case WM8326: - ret = mfd_add_devices(wm831x->dev, -1, + ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8320_devs, ARRAY_SIZE(wm8320_devs), NULL, wm831x->irq_base); break; @@ -1647,7 +1653,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) if (pdata && pdata->backlight) { /* Treat errors as non-critical */ - ret = mfd_add_devices(wm831x->dev, -1, backlight_devs, + ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs, ARRAY_SIZE(backlight_devs), NULL, wm831x->irq_base); if (ret < 0) -- cgit v1.2.3-70-g09d2 From 266a5e02fe2690637b2318c9fc5c3513937128f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Jun 2011 19:18:49 +0100 Subject: mfd: Allow touchscreen to be disabled on wm831x devices Allow platform data to flag the touchscreen as disabled so that if the touch driver is built in we don't end up causing lots of work by spuriously detecting touchscreen activity on systems where it isn't in use. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 27 +++++++++++++++++---------- include/linux/mfd/wm831x/pdata.h | 3 +++ 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers/mfd/wm831x-core.c') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 04994b23bb6..ff57a167475 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1124,11 +1124,6 @@ static struct mfd_cell wm8311_devs[] = { .num_resources = ARRAY_SIZE(wm831x_status2_resources), .resources = wm831x_status2_resources, }, - { - .name = "wm831x-touch", - .num_resources = ARRAY_SIZE(wm831x_touch_resources), - .resources = wm831x_touch_resources, - }, { .name = "wm831x-watchdog", .num_resources = ARRAY_SIZE(wm831x_wdt_resources), @@ -1285,11 +1280,6 @@ static struct mfd_cell wm8312_devs[] = { .num_resources = ARRAY_SIZE(wm831x_status2_resources), .resources = wm831x_status2_resources, }, - { - .name = "wm831x-touch", - .num_resources = ARRAY_SIZE(wm831x_touch_resources), - .resources = wm831x_touch_resources, - }, { .name = "wm831x-watchdog", .num_resources = ARRAY_SIZE(wm831x_wdt_resources), @@ -1428,6 +1418,15 @@ static struct mfd_cell wm8320_devs[] = { }, }; +static struct mfd_cell touch_devs[] = { + { + .name = "wm831x-touch", + .num_resources = ARRAY_SIZE(wm831x_touch_resources), + .resources = wm831x_touch_resources, + }, +}; + + static struct mfd_cell backlight_devs[] = { { .name = "wm831x-backlight", @@ -1624,12 +1623,20 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8311_devs, ARRAY_SIZE(wm8311_devs), NULL, wm831x->irq_base); + if (!pdata || !pdata->disable_touch) + mfd_add_devices(wm831x->dev, wm831x_num, + touch_devs, ARRAY_SIZE(touch_devs), + NULL, wm831x->irq_base); break; case WM8312: ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8312_devs, ARRAY_SIZE(wm8312_devs), NULL, wm831x->irq_base); + if (!pdata || !pdata->disable_touch) + mfd_add_devices(wm831x->dev, wm831x_num, + touch_devs, ARRAY_SIZE(touch_devs), + NULL, wm831x->irq_base); break; case WM8320: diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index ff42d700293..0ba24599fe5 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -120,6 +120,9 @@ struct wm831x_pdata { /** Put the /IRQ line into CMOS mode */ bool irq_cmos; + /** Disable the touchscreen */ + bool disable_touch; + int irq_base; int gpio_base; int gpio_defaults[WM831X_GPIO_NUM]; -- cgit v1.2.3-70-g09d2 From b9d03d999b46f0897492f3aac3e794312e5282db Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Jun 2011 19:18:50 +0100 Subject: mfd: Only register wm831x RTC device if the 32.768kHz crystal is enabled The RTC uses the 32.768kHz crystal so if it's not enabled (and it can only be enabled via OTP or InstantConfig, not runtime software) the RTC can't function. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 48 +++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'drivers/mfd/wm831x-core.c') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index ff57a167475..58f033b57ef 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -975,11 +975,6 @@ static struct mfd_cell wm8310_devs[] = { .num_resources = ARRAY_SIZE(wm831x_power_resources), .resources = wm831x_power_resources, }, - { - .name = "wm831x-rtc", - .num_resources = ARRAY_SIZE(wm831x_rtc_resources), - .resources = wm831x_rtc_resources, - }, { .name = "wm831x-status", .id = 1, @@ -1107,11 +1102,6 @@ static struct mfd_cell wm8311_devs[] = { .num_resources = ARRAY_SIZE(wm831x_power_resources), .resources = wm831x_power_resources, }, - { - .name = "wm831x-rtc", - .num_resources = ARRAY_SIZE(wm831x_rtc_resources), - .resources = wm831x_rtc_resources, - }, { .name = "wm831x-status", .id = 1, @@ -1263,11 +1253,6 @@ static struct mfd_cell wm8312_devs[] = { .num_resources = ARRAY_SIZE(wm831x_power_resources), .resources = wm831x_power_resources, }, - { - .name = "wm831x-rtc", - .num_resources = ARRAY_SIZE(wm831x_rtc_resources), - .resources = wm831x_rtc_resources, - }, { .name = "wm831x-status", .id = 1, @@ -1394,11 +1379,6 @@ static struct mfd_cell wm8320_devs[] = { .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, @@ -1426,6 +1406,13 @@ static struct mfd_cell touch_devs[] = { }, }; +static struct mfd_cell rtc_devs[] = { + { + .name = "wm831x-rtc", + .num_resources = ARRAY_SIZE(wm831x_rtc_resources), + .resources = wm831x_rtc_resources, + }, +}; static struct mfd_cell backlight_devs[] = { { @@ -1658,6 +1645,27 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) goto err_irq; } + /* The RTC can only be used if the 32.768kHz crystal is + * enabled; this can't be controlled by software at runtime. + */ + ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to read clock status: %d\n", ret); + goto err_irq; + } + + if (ret & WM831X_XTAL_ENA) { + ret = mfd_add_devices(wm831x->dev, wm831x_num, + rtc_devs, ARRAY_SIZE(rtc_devs), + NULL, wm831x->irq_base); + if (ret != 0) { + dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret); + goto err_irq; + } + } else { + dev_info(wm831x->dev, "32.768kHz clock disabled, no RTC\n"); + } + if (pdata && pdata->backlight) { /* Treat errors as non-critical */ ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs, -- cgit v1.2.3-70-g09d2 From c1a82780b41e78f31636c49279ce940afe60a453 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Jun 2011 19:18:52 +0100 Subject: mfd: Read wm831x AUXADC conversion results before acknowledging interrupt Ensure that there's no possibility of loosing an AUXADC interrupt by reading the conversion result in the IRQ handler when using interrupts. Otherwise it's possible that under very heavy load a new conversion could be initiated before the acknowledgement for a previous interrupt has happened. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 47 +++++++++++++++++++++++++++-------------- include/linux/mfd/wm831x/core.h | 1 + 2 files changed, 32 insertions(+), 16 deletions(-) (limited to 'drivers/mfd/wm831x-core.c') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 58f033b57ef..480abc18f9f 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -376,6 +376,16 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) goto disable; } } + + ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); + if (ret < 0) { + dev_err(wm831x->dev, + "Failed to read AUXADC data: %d\n", ret); + goto disable; + } + + wm831x->auxadc_data = ret; + } else { /* If we are using interrupts then wait for the * interrupt to complete. Use an extremely long @@ -390,23 +400,18 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) } } - ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret); + src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK) + >> WM831X_AUX_DATA_SRC_SHIFT) - 1; + + if (src == 14) + src = WM831X_AUX_CAL; + + if (src != input) { + dev_err(wm831x->dev, "Data from source %d not %d\n", + src, input); + ret = -EINVAL; } else { - src = ((ret & WM831X_AUX_DATA_SRC_MASK) - >> WM831X_AUX_DATA_SRC_SHIFT) - 1; - - if (src == 14) - src = WM831X_AUX_CAL; - - if (src != input) { - dev_err(wm831x->dev, "Data from source %d not %d\n", - src, input); - ret = -EINVAL; - } else { - ret &= WM831X_AUX_DATA_MASK; - } + ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK; } disable: @@ -420,6 +425,16 @@ EXPORT_SYMBOL_GPL(wm831x_auxadc_read); static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) { struct wm831x *wm831x = irq_data; + int ret; + + ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); + if (ret < 0) { + dev_err(wm831x->dev, + "Failed to read AUXADC data: %d\n", ret); + wm831x->auxadc_data = 0xffff; + } else { + wm831x->auxadc_data = ret; + } complete(&wm831x->auxadc_done); diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h index 9564cf31527..592e4fd6ab3 100644 --- a/include/linux/mfd/wm831x/core.h +++ b/include/linux/mfd/wm831x/core.h @@ -278,6 +278,7 @@ struct wm831x { struct mutex auxadc_lock; struct completion auxadc_done; + u16 auxadc_data; /* The WM831x has a security key blocking access to certain * registers. The mutex is taken by the accessors for locking -- cgit v1.2.3-70-g09d2 From e69b6de181167a132eee7c38c7e4b47dea3d8e49 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Jun 2011 19:18:53 +0100 Subject: mfd: Refactor wm831x AUXADC handling into a separate file In preparation for some additional work on the wm831x AUXADC code move the support into a separate file. This is a simple code motion patch, there should be no functional changes. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Makefile | 1 + drivers/mfd/wm831x-auxadc.c | 199 ++++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/wm831x-core.c | 167 +------------------------------------ 3 files changed, 201 insertions(+), 166 deletions(-) create mode 100644 drivers/mfd/wm831x-auxadc.c (limited to 'drivers/mfd/wm831x-core.c') diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 22a280fcb70..0889f53c8b0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o obj-$(CONFIG_MFD_WM8400) += wm8400-core.o wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o +wm831x-objs += wm831x-auxadc.o obj-$(CONFIG_MFD_WM831X) += wm831x.o obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c new file mode 100644 index 00000000000..2fc9531b243 --- /dev/null +++ b/drivers/mfd/wm831x-auxadc.c @@ -0,0 +1,199 @@ +/* + * wm831x-auxadc.c -- AUXADC for Wolfson WM831x PMICs + * + * Copyright 2009-2011 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/** + * wm831x_auxadc_read: Read a value from the WM831x AUXADC + * + * @wm831x: Device to read from. + * @input: AUXADC input to read. + */ +int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) +{ + int ret, src, irq_masked, timeout; + + /* Are we using the interrupt? */ + irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK); + irq_masked &= WM831X_AUXADC_DATA_EINT; + + mutex_lock(&wm831x->auxadc_lock); + + ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, + WM831X_AUX_ENA, WM831X_AUX_ENA); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); + goto out; + } + + /* We force a single source at present */ + src = input; + ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, + 1 << src); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); + goto out; + } + + /* Clear any notification from a very late arriving interrupt */ + try_wait_for_completion(&wm831x->auxadc_done); + + ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, + WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); + if (ret < 0) { + dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); + goto disable; + } + + if (irq_masked) { + /* If we're not using interrupts then poll the + * interrupt status register */ + timeout = 5; + while (timeout) { + msleep(1); + + ret = wm831x_reg_read(wm831x, + WM831X_INTERRUPT_STATUS_1); + if (ret < 0) { + dev_err(wm831x->dev, + "ISR 1 read failed: %d\n", ret); + goto disable; + } + + /* Did it complete? */ + if (ret & WM831X_AUXADC_DATA_EINT) { + wm831x_reg_write(wm831x, + WM831X_INTERRUPT_STATUS_1, + WM831X_AUXADC_DATA_EINT); + break; + } else { + dev_err(wm831x->dev, + "AUXADC conversion timeout\n"); + ret = -EBUSY; + goto disable; + } + } + + ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); + if (ret < 0) { + dev_err(wm831x->dev, + "Failed to read AUXADC data: %d\n", ret); + goto disable; + } + + wm831x->auxadc_data = ret; + + } else { + /* If we are using interrupts then wait for the + * interrupt to complete. Use an extremely long + * timeout to handle situations with heavy load where + * the notification of the interrupt may be delayed by + * threaded IRQ handling. */ + if (!wait_for_completion_timeout(&wm831x->auxadc_done, + msecs_to_jiffies(500))) { + dev_err(wm831x->dev, "Timed out waiting for AUXADC\n"); + ret = -EBUSY; + goto disable; + } + } + + src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK) + >> WM831X_AUX_DATA_SRC_SHIFT) - 1; + + if (src == 14) + src = WM831X_AUX_CAL; + + if (src != input) { + dev_err(wm831x->dev, "Data from source %d not %d\n", + src, input); + ret = -EINVAL; + } else { + ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK; + } + +disable: + wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); +out: + mutex_unlock(&wm831x->auxadc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(wm831x_auxadc_read); + +static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) +{ + struct wm831x *wm831x = irq_data; + int ret; + + ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); + if (ret < 0) { + dev_err(wm831x->dev, + "Failed to read AUXADC data: %d\n", ret); + wm831x->auxadc_data = 0xffff; + } else { + wm831x->auxadc_data = ret; + } + + complete(&wm831x->auxadc_done); + + return IRQ_HANDLED; +} + +/** + * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC + * + * @wm831x: Device to read from. + * @input: AUXADC input to read. + */ +int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) +{ + int ret; + + ret = wm831x_auxadc_read(wm831x, input); + if (ret < 0) + return ret; + + ret *= 1465; + + return ret; +} +EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); + +void wm831x_auxadc_init(struct wm831x *wm831x) +{ + int ret; + + mutex_init(&wm831x->auxadc_lock); + init_completion(&wm831x->auxadc_done); + + if (wm831x->irq_base) { + ret = request_threaded_irq(wm831x->irq_base + + WM831X_IRQ_AUXADC_DATA, + NULL, wm831x_auxadc_irq, 0, + "auxadc", wm831x); + if (ret < 0) + dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", + ret); + } +} diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 480abc18f9f..772fe584f3b 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -306,161 +306,6 @@ out: } EXPORT_SYMBOL_GPL(wm831x_set_bits); -/** - * wm831x_auxadc_read: Read a value from the WM831x AUXADC - * - * @wm831x: Device to read from. - * @input: AUXADC input to read. - */ -int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) -{ - int ret, src, irq_masked, timeout; - - /* Are we using the interrupt? */ - irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK); - irq_masked &= WM831X_AUXADC_DATA_EINT; - - mutex_lock(&wm831x->auxadc_lock); - - ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, - WM831X_AUX_ENA, WM831X_AUX_ENA); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); - goto out; - } - - /* We force a single source at present */ - src = input; - ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, - 1 << src); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); - goto out; - } - - /* Clear any notification from a very late arriving interrupt */ - try_wait_for_completion(&wm831x->auxadc_done); - - ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, - WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); - goto disable; - } - - if (irq_masked) { - /* If we're not using interrupts then poll the - * interrupt status register */ - timeout = 5; - while (timeout) { - msleep(1); - - ret = wm831x_reg_read(wm831x, - WM831X_INTERRUPT_STATUS_1); - if (ret < 0) { - dev_err(wm831x->dev, - "ISR 1 read failed: %d\n", ret); - goto disable; - } - - /* Did it complete? */ - if (ret & WM831X_AUXADC_DATA_EINT) { - wm831x_reg_write(wm831x, - WM831X_INTERRUPT_STATUS_1, - WM831X_AUXADC_DATA_EINT); - break; - } else { - dev_err(wm831x->dev, - "AUXADC conversion timeout\n"); - ret = -EBUSY; - goto disable; - } - } - - ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); - if (ret < 0) { - dev_err(wm831x->dev, - "Failed to read AUXADC data: %d\n", ret); - goto disable; - } - - wm831x->auxadc_data = ret; - - } else { - /* If we are using interrupts then wait for the - * interrupt to complete. Use an extremely long - * timeout to handle situations with heavy load where - * the notification of the interrupt may be delayed by - * threaded IRQ handling. */ - if (!wait_for_completion_timeout(&wm831x->auxadc_done, - msecs_to_jiffies(500))) { - dev_err(wm831x->dev, "Timed out waiting for AUXADC\n"); - ret = -EBUSY; - goto disable; - } - } - - src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK) - >> WM831X_AUX_DATA_SRC_SHIFT) - 1; - - if (src == 14) - src = WM831X_AUX_CAL; - - if (src != input) { - dev_err(wm831x->dev, "Data from source %d not %d\n", - src, input); - ret = -EINVAL; - } else { - ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK; - } - -disable: - wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); -out: - mutex_unlock(&wm831x->auxadc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(wm831x_auxadc_read); - -static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) -{ - struct wm831x *wm831x = irq_data; - int ret; - - ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); - if (ret < 0) { - dev_err(wm831x->dev, - "Failed to read AUXADC data: %d\n", ret); - wm831x->auxadc_data = 0xffff; - } else { - wm831x->auxadc_data = ret; - } - - complete(&wm831x->auxadc_done); - - return IRQ_HANDLED; -} - -/** - * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC - * - * @wm831x: Device to read from. - * @input: AUXADC input to read. - */ -int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) -{ - int ret; - - ret = wm831x_auxadc_read(wm831x, input); - if (ret < 0) - return ret; - - ret *= 1465; - - return ret; -} -EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); - static struct resource wm831x_dcdc1_resources[] = { { .start = WM831X_DC1_CONTROL_1, @@ -1447,8 +1292,6 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) mutex_init(&wm831x->io_lock); mutex_init(&wm831x->key_lock); - mutex_init(&wm831x->auxadc_lock); - init_completion(&wm831x->auxadc_done); dev_set_drvdata(wm831x->dev, wm831x); ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); @@ -1603,15 +1446,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) if (ret != 0) goto err; - if (wm831x->irq_base) { - ret = request_threaded_irq(wm831x->irq_base + - WM831X_IRQ_AUXADC_DATA, - NULL, wm831x_auxadc_irq, 0, - "auxadc", wm831x); - if (ret < 0) - dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", - ret); - } + wm831x_auxadc_init(wm831x); /* The core device is up, instantiate the subdevices. */ switch (parent) { -- cgit v1.2.3-70-g09d2 From b00cd68eb3f6c81525e43f6259b65665ef32499a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 20 Jun 2011 12:25:58 +0100 Subject: mfd: Ensure value written by wm831x_set_bits() is within the mask Purely for defensiveness. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd/wm831x-core.c') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 772fe584f3b..baae9e47bff 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -295,7 +295,7 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, goto out; r &= ~mask; - r |= val; + r |= val & mask; ret = wm831x_write(wm831x, reg, 2, &r); -- cgit v1.2.3-70-g09d2 From a5e06781f073842beb81d088eb787f0ea23d6499 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 24 Jun 2011 12:17:07 +0100 Subject: mfd: Add devices for WM831x clocking module With the new generic clk API that should appear at some point we should be able to support the clocking sensibly in Linux. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/mfd/wm831x-core.c') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index baae9e47bff..282e76ab678 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -731,6 +731,9 @@ static struct mfd_cell wm8310_devs[] = { .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources), .resources = wm831x_dcdc4_resources, }, + { + .name = "wm831x-clk", + }, { .name = "wm831x-epe", .id = 1, @@ -882,6 +885,9 @@ static struct mfd_cell wm8311_devs[] = { .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources), .resources = wm831x_dcdc4_resources, }, + { + .name = "wm831x-clk", + }, { .name = "wm831x-epe", .id = 1, @@ -1009,6 +1015,9 @@ static struct mfd_cell wm8312_devs[] = { .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources), .resources = wm831x_dcdc4_resources, }, + { + .name = "wm831x-clk", + }, { .name = "wm831x-epe", .id = 1, @@ -1160,6 +1169,9 @@ static struct mfd_cell wm8320_devs[] = { .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources), .resources = wm8320_dcdc4_buck_resources, }, + { + .name = "wm831x-clk", + }, { .name = "wm831x-gpio", .num_resources = ARRAY_SIZE(wm831x_gpio_resources), -- cgit v1.2.3-70-g09d2