* [PATCH 2/9] mfd: Implement support for multiple WM831x devices
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
2011-06-02 18:18 ` [PATCH 3/9] mfd: Allow touchscreen to be disabled on wm831x devices Mark Brown
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Mark Brown
Systems using this functionality will be uncommon.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/mfd/wm831x-core.c | 18 ++++++++++++------
1 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 265f75f..04994b2 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)
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 3/9] mfd: Allow touchscreen to be disabled on wm831x devices
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
2011-06-02 18:18 ` [PATCH 2/9] mfd: Implement support for multiple WM831x devices Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
2011-06-02 18:18 ` [PATCH 4/9] mfd: Only register wm831x RTC device if the 32.768kHz crystal is enabled Mark Brown
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
drivers/mfd/wm831x-core.c | 27 +++++++++++++++++----------
include/linux/mfd/wm831x/pdata.h | 3 +++
2 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 04994b2..ff57a16 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1125,11 +1125,6 @@ static struct mfd_cell wm8311_devs[] = {
.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),
.resources = wm831x_wdt_resources,
@@ -1286,11 +1281,6 @@ static struct mfd_cell wm8312_devs[] = {
.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),
.resources = 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 ff42d70..0ba2459 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];
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 4/9] mfd: Only register wm831x RTC device if the 32.768kHz crystal is enabled
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
2011-06-02 18:18 ` [PATCH 2/9] mfd: Implement support for multiple WM831x devices Mark Brown
2011-06-02 18:18 ` [PATCH 3/9] mfd: Allow touchscreen to be disabled on wm831x devices Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
2011-06-02 18:18 ` [PATCH 5/9] mfd: Support dynamic allocation of IRQ range for wm831x Mark Brown
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
drivers/mfd/wm831x-core.c | 48 ++++++++++++++++++++++++++------------------
1 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index ff57a16..58f033b 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -976,11 +976,6 @@ static struct mfd_cell wm8310_devs[] = {
.resources = wm831x_power_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),
@@ -1108,11 +1103,6 @@ static struct mfd_cell wm8311_devs[] = {
.resources = wm831x_power_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),
@@ -1264,11 +1254,6 @@ static struct mfd_cell wm8312_devs[] = {
.resources = wm831x_power_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),
@@ -1395,11 +1380,6 @@ static struct mfd_cell wm8320_devs[] = {
.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),
@@ -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,
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 5/9] mfd: Support dynamic allocation of IRQ range for wm831x
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
` (2 preceding siblings ...)
2011-06-02 18:18 ` [PATCH 4/9] mfd: Only register wm831x RTC device if the 32.768kHz crystal is enabled Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
2011-06-02 18:18 ` [PATCH 6/9] mfd: Read wm831x AUXADC conversion results before acknowledging interrupt Mark Brown
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Mark Brown
Use irq_allocate_desc() to get the IRQ range, which turns into a noop on
non-sparse systems. Since all existing users are non-sparse there should
be no compatibility issues.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/mfd/wm831x-irq.c | 18 +++++++++++++-----
include/linux/mfd/wm831x/core.h | 2 +-
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index b23d8d5..1808deb 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -527,13 +527,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
0xffff);
}
- if (!pdata || !pdata->irq_base) {
- dev_err(wm831x->dev,
- "No interrupt base specified, no interrupts\n");
+ /* Try to dynamically allocate IRQs if no base is specified */
+ if (!pdata || !pdata->irq_base)
+ wm831x->irq_base = -1;
+ else
+ wm831x->irq_base = pdata->irq_base;
+
+ wm831x->irq_base = irq_alloc_descs(wm831x->irq_base, 0,
+ WM831X_NUM_IRQS, 0);
+ if (wm831x->irq_base < 0) {
+ dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
+ wm831x->irq_base);
+ wm831x->irq_base = 0;
return 0;
}
- if (pdata->irq_cmos)
+ if (pdata && pdata->irq_cmos)
i = 0;
else
i = WM831X_IRQ_OD;
@@ -553,7 +562,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
}
wm831x->irq = irq;
- wm831x->irq_base = pdata->irq_base;
/* Register them with genirq */
for (cur_irq = wm831x->irq_base;
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index ebead1c..9564cf3 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -262,7 +262,7 @@ struct wm831x {
int irq; /* Our chip IRQ */
struct mutex irq_lock;
- unsigned int irq_base;
+ int irq_base;
int irq_masks_cur[WM831X_NUM_IRQ_REGS]; /* Currently active value */
int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 6/9] mfd: Read wm831x AUXADC conversion results before acknowledging interrupt
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
` (3 preceding siblings ...)
2011-06-02 18:18 ` [PATCH 5/9] mfd: Support dynamic allocation of IRQ range for wm831x Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
2011-06-02 18:18 ` [PATCH 7/9] mfd: Refactor wm831x AUXADC handling into a separate file Mark Brown
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
drivers/mfd/wm831x-core.c | 47 +++++++++++++++++++++++++-------------
include/linux/mfd/wm831x/core.h | 1 +
2 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 58f033b..480abc1 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 9564cf3..592e4fd 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
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 7/9] mfd: Refactor wm831x AUXADC handling into a separate file
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
` (4 preceding siblings ...)
2011-06-02 18:18 ` [PATCH 6/9] mfd: Read wm831x AUXADC conversion results before acknowledging interrupt Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
2011-06-02 18:18 ` [PATCH 8/9] mfd: Allocate wm835x irq descs dynamically Mark Brown
2011-06-02 18:18 ` [PATCH 9/9] mfd: Restructure wm8994-core device revision handling Mark Brown
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Mark Brown
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 <broonie@opensource.wolfsonmicro.com>
---
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
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index efe3cc3..9f41923 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 0000000..2fc9531
--- /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 <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/pdata.h>
+#include <linux/mfd/wm831x/irq.h>
+#include <linux/mfd/wm831x/auxadc.h>
+#include <linux/mfd/wm831x/otp.h>
+#include <linux/mfd/wm831x/regulator.h>
+
+/**
+ * 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 480abc1..772fe58 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) {
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 8/9] mfd: Allocate wm835x irq descs dynamically
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
` (5 preceding siblings ...)
2011-06-02 18:18 ` [PATCH 7/9] mfd: Refactor wm831x AUXADC handling into a separate file Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
2011-06-02 18:18 ` [PATCH 9/9] mfd: Restructure wm8994-core device revision handling Mark Brown
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Sascha Hauer, Mark Brown
From: Sascha Hauer <s.hauer@pengutronix.de>
This allows boards to leave the irq_base field unitialized and
prevents them having to reserve irqs in the platform.
pdata can be optional for irq support now. Without pdata the
driver allocates some free irq range. With pdata and irq_base > 0
the driver allocates exactly the specified irq.
Without pdata the irq defaults to IRQF_TRIGGER_LOW.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/mfd/wm8350-irq.c | 18 ++++++++++++------
1 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index ed4b22a..8a1fafd 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -473,17 +473,13 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
{
int ret, cur_irq, i;
int flags = IRQF_ONESHOT;
+ int irq_base = -1;
if (!irq) {
dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
return 0;
}
- if (!pdata || !pdata->irq_base) {
- dev_warn(wm8350->dev, "No interrupt support, no IRQ base\n");
- return 0;
- }
-
/* Mask top level interrupts */
wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
@@ -502,7 +498,17 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
wm8350->chip_irq = irq;
wm8350->irq_base = pdata->irq_base;
- if (pdata->irq_high) {
+ if (pdata && pdata->irq_base > 0)
+ irq_base = pdata->irq_base;
+
+ wm8350->irq_base = irq_alloc_descs(irq_base, 0, ARRAY_SIZE(wm8350_irqs), 0);
+ if (wm8350->irq_base < 0) {
+ dev_warn(wm8350->dev, "Allocating irqs failed with %d\n",
+ wm8350->irq_base);
+ return 0;
+ }
+
+ if (pdata && pdata->irq_high) {
flags |= IRQF_TRIGGER_HIGH;
wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 9/9] mfd: Restructure wm8994-core device revision handling
2011-06-02 18:18 ` [PATCH 1/9] mfd: Fix bus lock interaction for WM831x IRQ set_type() operation Mark Brown
` (6 preceding siblings ...)
2011-06-02 18:18 ` [PATCH 8/9] mfd: Allocate wm835x irq descs dynamically Mark Brown
@ 2011-06-02 18:18 ` Mark Brown
7 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2011-06-02 18:18 UTC (permalink / raw)
To: Samuel Ortiz; +Cc: patches, linux-kernel, Mark Brown
Switch on the device type before revision since anything we do here will
be device as well as revision specific.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/mfd/wm8994-core.c | 13 +++++++++----
1 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index e198d40..18f19b7 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -476,13 +476,18 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
goto err_enable;
}
- switch (ret) {
- case 0:
- case 1:
- if (wm8994->type == WM8994)
+ switch (wm8994->type) {
+ case WM8994:
+ switch (ret) {
+ case 0:
+ case 1:
dev_warn(wm8994->dev,
"revision %c not fully supported\n",
'A' + ret);
+ break;
+ default:
+ break;
+ }
break;
default:
break;
--
1.7.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread