Re: [PATCH] mfd: twl4030: Driver for twl4030 madc module
Hi all Janakiram Sistla wrote: On Mon, Jul 19, 2010 at 10:46 AM, Michael Trimarchi mich...@panicking.kicks-ass.org wrote: Janakiram Sistla wrote: drivers/mfd/Kconfig | 21 ++ drivers/mfd/Makefile |3 +- drivers/mfd/twl4030-madc.c | 548 ++ include/linux/i2c/twl4030-madc.h | 126 + 4 files changed, 697 insertions(+), 1 deletions(-) create mode 100644 drivers/mfd/twl4030-madc.c create mode 100644 include/linux/i2c/twl4030-madc.h We have just tried to adopt this driver to our custom OMAP3 board, but were unable to get any interrupts. Any ideas on what is missing? We've checked whole TRM and found nothing wrong yet :( we tried the same driver for Omap zoom platform ,I too dont see any interrupts from this driver.I also observe that duing bluetooth file transfer i see the below crash from twl4030-madc driver. Once i disable the madc driver in kernel configuration my Bluetooth works fine,while Bluetooth has nothing to do with i2c or madc driver.A similar crash is also observed during GFX operation Regards, Ram. here is the log: i2c_omap i2c_omap.1: controller timed out waiting for start condition to finish twl: i2c_write failed to transfer all messages Unable to handle kernel NULL pointer dereference at virtual address 0044 pgd = c0004000 [0044] *pgd= Internal error: Oops: 17 [#1] PREEMPT last sysfs file: /sys/devices/platform/kim/firmware/kim/loading Modules linked in: bt_drv st_drv CPU: 0Not tainted (2.6.32-14922-g86eec44 #1) PC is at dev_driver_string+0x0/0x38 LR is at twl4030_madc_write+0x2c/0x4c pc : [c01f2bc0]lr : [c01fede0]psr: a013 sp : cf02bf08 ip : 738f fp : r10: cf002cc8 r9 : c038a839 r8 : r7 : cf02bf3c r6 : c04edff8 r5 : 0007 r4 : cf227a00 r3 : 0007 r2 : 02070002 r1 : 0007 r0 : Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 8d23c019 DAC: 0017 Process events/0 (pid: 5, stack limit = 0xcf02a2e8) Stack: (0xcf02bf08 to 0xcf02c000) bf00: 0006 0002 c04edff8 c01fef6c cf179680 cf179680 bf20: cf02a000 cf002cc0 c028a5a8 cf002cc8 c028a5dc 0200 bf40: cf020001 cf020d40 0017 cf0213c0 c007f1dc cd277e40 bf60: cf02bf94 c036e58c cd0bac9c cf020ed4 6013 cf002cc0 cf002cbc cf02a000 bf80: cf002cc0 c01dcc00 cf002cc0 cf179684 c0076ff4 cf02bfcc bfa0: cf020d40 c007a660 cf02bfa8 cf02bfa8 cf023f60 cf02bfd4 cf023f60 cf002cc0 bfc0: c0076e8c c007a334 cf02bfd8 cf02bfd8 bfe0: c0035f80 [c01f2bc0] (dev_driver_string+0x0/0x38) from [c01fede0] (twl4030_madc_write+ 0x2c/0x4c) [c01fede0] (twl4030_madc_write+0x2c/0x4c) from [c01fef6c] (twl4030_madc_conv ersion+0x74/0x288) [c01fef6c] (twl4030_madc_conversion+0x74/0x288) from [c028a5dc] (twl4030_bk_ bci_battery_work+0x34/0x60) [c028a5dc] (twl4030_bk_bci_battery_work+0x34/0x60) from [c0076ff4] (worker_t hread+0x168/0x214) [c0076ff4] (worker_thread+0x168/0x214) from [c007a334] (kthread+0x7c/0x84) [c007a334] (kthread+0x7c/0x84) from [c0035f80] (kernel_thread_exit+0x0/0x8) Code: c04edd3c c04eddcc c042bef5 c040d709 (e5903044) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 2d2aa87..e12ac1a 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -478,6 +478,7 @@ static int __init twl4030_madc_probe(struct platform_device madc-imr = (pdata-irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IM madc-isr = (pdata-irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_IS + madc-dev = pdev-dev; ret = misc_register(twl4030_madc_device); if (ret) { This is the reason of the crash Michael Trimarchi I think its fixed already.. .. I'm testing in overo and I have notice varius issue: +#if 0 if (dev-rev = OMAP_I2C_REV_ON_3430) { while (!(stat OMAP_I2C_STAT_XU if (stat (OMAP_I2C_STA @@ -826,7 +826,7 @@ complete: stat = omap_i2c_read_reg } } - +#endif I need to comment out this code, because it loop and it doesn't have an exit condition. This couse the kernel to stuck, but after comment out this I have every 5sec/10 seconds some error on i2c bus during write Michael -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at
Re: [PATCH] mfd: twl4030: Driver for twl4030 madc module
drivers/mfd/Kconfig | 21 ++ drivers/mfd/Makefile |3 +- drivers/mfd/twl4030-madc.c | 548 ++ include/linux/i2c/twl4030-madc.h | 126 + 4 files changed, 697 insertions(+), 1 deletions(-) create mode 100644 drivers/mfd/twl4030-madc.c create mode 100644 include/linux/i2c/twl4030-madc.h We have just tried to adopt this driver to our custom OMAP3 board, but were unable to get any interrupts. Any ideas on what is missing? We've checked whole TRM and found nothing wrong yet :( we tried the same driver for Omap zoom platform ,I too dont see any interrupts from this driver.I also observe that duing bluetooth file transfer i see the below crash from twl4030-madc driver. Once i disable the madc driver in kernel configuration my Bluetooth works fine,while Bluetooth has nothing to do with i2c or madc driver.A similar crash is also observed during GFX operation Regards, Ram. here is the log: i2c_omap i2c_omap.1: controller timed out waiting for start condition to finish twl: i2c_write failed to transfer all messages Unable to handle kernel NULL pointer dereference at virtual address 0044 pgd = c0004000 [0044] *pgd= Internal error: Oops: 17 [#1] PREEMPT last sysfs file: /sys/devices/platform/kim/firmware/kim/loading Modules linked in: bt_drv st_drv CPU: 0Not tainted (2.6.32-14922-g86eec44 #1) PC is at dev_driver_string+0x0/0x38 LR is at twl4030_madc_write+0x2c/0x4c pc : [c01f2bc0]lr : [c01fede0]psr: a013 sp : cf02bf08 ip : 738f fp : r10: cf002cc8 r9 : c038a839 r8 : r7 : cf02bf3c r6 : c04edff8 r5 : 0007 r4 : cf227a00 r3 : 0007 r2 : 02070002 r1 : 0007 r0 : Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 8d23c019 DAC: 0017 Process events/0 (pid: 5, stack limit = 0xcf02a2e8) Stack: (0xcf02bf08 to 0xcf02c000) bf00: 0006 0002 c04edff8 c01fef6c cf179680 cf179680 bf20: cf02a000 cf002cc0 c028a5a8 cf002cc8 c028a5dc 0200 bf40: cf020001 cf020d40 0017 cf0213c0 c007f1dc cd277e40 bf60: cf02bf94 c036e58c cd0bac9c cf020ed4 6013 cf002cc0 cf002cbc cf02a000 bf80: cf002cc0 c01dcc00 cf002cc0 cf179684 c0076ff4 cf02bfcc bfa0: cf020d40 c007a660 cf02bfa8 cf02bfa8 cf023f60 cf02bfd4 cf023f60 cf002cc0 bfc0: c0076e8c c007a334 cf02bfd8 cf02bfd8 bfe0: c0035f80 [c01f2bc0] (dev_driver_string+0x0/0x38) from [c01fede0] (twl4030_madc_write+ 0x2c/0x4c) [c01fede0] (twl4030_madc_write+0x2c/0x4c) from [c01fef6c] (twl4030_madc_conv ersion+0x74/0x288) [c01fef6c] (twl4030_madc_conversion+0x74/0x288) from [c028a5dc] (twl4030_bk_ bci_battery_work+0x34/0x60) [c028a5dc] (twl4030_bk_bci_battery_work+0x34/0x60) from [c0076ff4] (worker_t hread+0x168/0x214) [c0076ff4] (worker_thread+0x168/0x214) from [c007a334] (kthread+0x7c/0x84) [c007a334] (kthread+0x7c/0x84) from [c0035f80] (kernel_thread_exit+0x0/0x8) Code: c04edd3c c04eddcc c042bef5 c040d709 (e5903044) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] mfd: twl4030: Driver for twl4030 madc module
Hi, all! On Wed, Nov 25, 2009 at 1:47 PM, Amit Kucheria amit.kuche...@verdurent.com wrote: From: Mikko Ylinen mikko.k.yli...@nokia.com This ADC allows monitoring of analog signals such as battery levels, temperatures, etc. Several people have contributed to this driver on the linux-omap list. Signed-off-by: Amit Kucheria amit.kuche...@verdurent.com --- drivers/mfd/Kconfig | 21 ++ drivers/mfd/Makefile | 3 +- drivers/mfd/twl4030-madc.c | 548 ++ include/linux/i2c/twl4030-madc.h | 126 + 4 files changed, 697 insertions(+), 1 deletions(-) create mode 100644 drivers/mfd/twl4030-madc.c create mode 100644 include/linux/i2c/twl4030-madc.h We have just tried to adopt this driver to our custom OMAP3 board, but were unable to get any interrupts. Any ideas on what is missing? We've checked whole TRM and found nothing wrong yet :( Thanks a lot. S. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] mfd: twl4030: Driver for twl4030 madc module
Hi Amit, On Mon, Nov 30, 2009 at 03:58:39PM +0200, Amit Kucheria wrote: + * drivers/i2c/chips/twl4030-madc.c drivers/mfd/twl4030-madc.c By the way, have you considered moving this one to drivers/hwmon ? I haven't. I moved it from i2c/chips/ to the most obvious place I could think of - drivers/mfd. But wasn't this the point of mfd - that various subcomponents drivers could live there instead of being scattered across the driver tree? Not really. Most of the drivers in mfd/ are for the core parts of the corresponding chip (chip init and setup, subdevices definitions and declarations, API export, IRQ setups, etc...). I can take this driver for now, but converting it to a proper hwmon driver would make sense because that's what it is after all. +static struct twl4030_madc_data *the_madc; I dont particularly enjoy that. All of the twl4030 drivers have this bad habit of assuming they will be alone on a platform. Although it's certainly very likely, I still think having this kind of design is not so nice. I agree. Unfortunately, twl4030-core.c is unable to handle multiple devices currently. See note from line 779 in twl4030-core below: Oh, I know about that. That's also something the code maintainers (Nokia I assume) of that driver should start looking at. +static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg) +{ + int ret; + u8 val; + + ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, val, reg); + if (ret) { + dev_dbg(madc-dev, unable to read register 0x%X\n, reg); + return ret; + } + + return val; +} FWIW, you're not checking the return value on any of the madc_read calls below. I've changed the dev_dbg above to dev_err now. If we see those error messages, then anything that follows from the higher level functions is overhead IMHO. I usually expect code to check for function return values :) And also exit if a IO fails. The higher level functions in this case aren't adding any more useful information to the error. E.g. I could check the return value again in twl4030_madc_channel_raw_read() below. But if would simply repeat the same error message we show in twl4030_madc_read(). The error message matter less than the code flow itself. For example if twl4030_madc_start_conversion() fails because of your i2c failing, you will still busy loop (Yes, only for 5ms, but still) waiting for a register bit to toggle. Hmm, perhaps twl4030_madc_read should return void? That would be weird, imho. In fact, your write routine returning void is already weird. +static void twl4030_madc_work(struct work_struct *ws) +{ + const struct twl4030_madc_conversion_method *method; + struct twl4030_madc_data *madc; + struct twl4030_madc_request *r; + int len, i; + + madc = container_of(ws, struct twl4030_madc_data, ws); + mutex_lock(madc-lock); + + for (i = 0; i TWL4030_MADC_NUM_METHODS; i++) { + + r = madc-requests[i]; + + /* No pending results for this method, move to next one */ + if (!r-result_pending) + continue; + + method = twl4030_conversion_methods[r-method]; + + /* Read results */ + len = twl4030_madc_read_channels(madc, method-rbase, + r-channels, r-rbuf); + + /* Return results to caller */ + if (r-func_cb != NULL) { + r-func_cb(len, r-channels, r-rbuf); + r-func_cb = NULL; + } + + /* Free request */ + r-result_pending = 0; + r-active = 0; + } + + mutex_unlock(madc-lock); +} I think you may want to consider using a threaded irq here, see request_threaded_irq(). I am working on moving the entire twl* driver set to use threaded irqs on the side. Will you consider merging this code with the work_struct since it is known to work while I work on the conversion? That's fine, yes. Thanks in advance for the conversion. +static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on); +int twl4030_madc_conversion(struct twl4030_madc_request *req) +{ + const struct twl4030_madc_conversion_method *method; + u8 ch_msb, ch_lsb; + int ret; + + if (unlikely(!req)) + return -EINVAL; + + mutex_lock(the_madc-lock); + + twl4030_madc_set_power(the_madc, 1); + + /* Do we have a conversion request ongoing */ + if (the_madc-requests[req-method].active) { + ret = -EBUSY; + goto out; + } + + ch_msb = (req-channels 8) 0xff; + ch_lsb = req-channels 0xff; + + method = twl4030_conversion_methods[req-method]; + + /* Select channels to be converted */ + twl4030_madc_write(the_madc, method-sel
Re: [PATCH] mfd: twl4030: Driver for twl4030 madc module
Hi Samuel, On Fri, Nov 27, 2009 at 9:36 PM, Samuel Ortiz sa...@linux.intel.com wrote: Hi Amit, On Wed, Nov 25, 2009 at 12:47:51PM +0200, Amit Kucheria wrote: diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index af0fc90..df1897b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -25,8 +25,9 @@ obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o -obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o +obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o +obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_MFD_MC13783) += mc13783-core.o diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c new file mode 100644 index 000..90ce99a --- /dev/null +++ b/drivers/mfd/twl4030-madc.c @@ -0,0 +1,548 @@ +/* + * drivers/i2c/chips/twl4030-madc.c drivers/mfd/twl4030-madc.c By the way, have you considered moving this one to drivers/hwmon ? I haven't. I moved it from i2c/chips/ to the most obvious place I could think of - drivers/mfd. But wasn't this the point of mfd - that various subcomponents drivers could live there instead of being scattered across the driver tree? Adding Jean to CC, if he would consider taking this driver in drivers/hwmon. + * TWL4030 MADC module driver + * + * Copyright (C) 2008 Nokia Corporation + * Mikko Ylinen mikko.k.yli...@nokia.com + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include linux/init.h +#include linux/interrupt.h +#include linux/kernel.h +#include linux/types.h +#include linux/module.h +#include linux/delay.h +#include linux/fs.h +#include linux/platform_device.h +#include linux/miscdevice.h +#include linux/i2c/twl4030.h +#include linux/i2c/twl4030-madc.h + +#include asm/uaccess.h + +#define TWL4030_MADC_PFX twl4030-madc: + +struct twl4030_madc_data { + struct device *dev; + struct mutex lock; + struct work_struct ws; + struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; Typically, I'd expect to have a list (limited in length) of requests here, but I guess you're happy with that array . + int imr; + int isr; +}; + +static struct twl4030_madc_data *the_madc; I dont particularly enjoy that. All of the twl4030 drivers have this bad habit of assuming they will be alone on a platform. Although it's certainly very likely, I still think having this kind of design is not so nice. I agree. Unfortunately, twl4030-core.c is unable to handle multiple devices currently. See note from line 779 in twl4030-core below: /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ static int twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, int chan, int on); + +static +const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { + [TWL4030_MADC_RT] = { + .sel = TWL4030_MADC_RTSELECT_LSB, + .avg = TWL4030_MADC_RTAVERAGE_LSB, + .rbase = TWL4030_MADC_RTCH0_LSB, + }, + [TWL4030_MADC_SW1] = { + .sel = TWL4030_MADC_SW1SELECT_LSB, + .avg = TWL4030_MADC_SW1AVERAGE_LSB, + .rbase = TWL4030_MADC_GPCH0_LSB, + .ctrl = TWL4030_MADC_CTRL_SW1, + }, + [TWL4030_MADC_SW2] = { + .sel = TWL4030_MADC_SW2SELECT_LSB, + .avg = TWL4030_MADC_SW2AVERAGE_LSB, + .rbase = TWL4030_MADC_GPCH0_LSB, + .ctrl = TWL4030_MADC_CTRL_SW2, + }, +}; + +static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg) +{ + int ret; + u8 val; + + ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, val, reg); + if (ret) { + dev_dbg(madc-dev, unable to read register 0x%X\n, reg); + return ret; + } + + return val; +} FWIW, you're not checking the return value on any of the madc_read calls below. I've changed the dev_dbg above to dev_err now. If we see those error messages, then anything that follows from the higher level functions is overhead IMHO. The higher level functions in
Re: [PATCH] mfd: twl4030: Driver for twl4030 madc module
On Mon, 30 Nov 2009 15:58:39 +0200, Amit Kucheria wrote: On Fri, Nov 27, 2009 at 9:36 PM, Samuel Ortiz sa...@linux.intel.com wrote: By the way, have you considered moving this one to drivers/hwmon ? I haven't. I moved it from i2c/chips/ to the most obvious place I could think of - drivers/mfd. But wasn't this the point of mfd - that various subcomponents drivers could live there instead of being scattered across the driver tree? Adding Jean to CC, if he would consider taking this driver in drivers/hwmon.. In its current form, no. This driver doesn't implement the sysfs interface described in Documentation/hwmon/sysfs-interface. It doesn't even register a hwmon class device. So it doesn't belong in drivers/hwmon. -- Jean Delvare -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] mfd: twl4030: Driver for twl4030 madc module
Hi Amit, On Wed, Nov 25, 2009 at 12:47:51PM +0200, Amit Kucheria wrote: diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index af0fc90..df1897b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -25,8 +25,9 @@ obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o -obj-$(CONFIG_TWL4030_POWER)+= twl4030-power.o +obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o +obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_MFD_MC13783)+= mc13783-core.o diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c new file mode 100644 index 000..90ce99a --- /dev/null +++ b/drivers/mfd/twl4030-madc.c @@ -0,0 +1,548 @@ +/* + * drivers/i2c/chips/twl4030-madc.c drivers/mfd/twl4030-madc.c By the way, have you considered moving this one to drivers/hwmon ? + * TWL4030 MADC module driver + * + * Copyright (C) 2008 Nokia Corporation + * Mikko Ylinen mikko.k.yli...@nokia.com + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include linux/init.h +#include linux/interrupt.h +#include linux/kernel.h +#include linux/types.h +#include linux/module.h +#include linux/delay.h +#include linux/fs.h +#include linux/platform_device.h +#include linux/miscdevice.h +#include linux/i2c/twl4030.h +#include linux/i2c/twl4030-madc.h + +#include asm/uaccess.h + +#define TWL4030_MADC_PFX twl4030-madc: + +struct twl4030_madc_data { + struct device *dev; + struct mutexlock; + struct work_struct ws; + struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; Typically, I'd expect to have a list (limited in length) of requests here, but I guess you're happy with that array . + int imr; + int isr; +}; + +static struct twl4030_madc_data *the_madc; I dont particularly enjoy that. All of the twl4030 drivers have this bad habit of assuming they will be alone on a platform. Although it's certainly very likely, I still think having this kind of design is not so nice. +static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, int chan, int on); + +static +const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { + [TWL4030_MADC_RT] = { + .sel= TWL4030_MADC_RTSELECT_LSB, + .avg= TWL4030_MADC_RTAVERAGE_LSB, + .rbase = TWL4030_MADC_RTCH0_LSB, + }, + [TWL4030_MADC_SW1] = { + .sel= TWL4030_MADC_SW1SELECT_LSB, + .avg= TWL4030_MADC_SW1AVERAGE_LSB, + .rbase = TWL4030_MADC_GPCH0_LSB, + .ctrl = TWL4030_MADC_CTRL_SW1, + }, + [TWL4030_MADC_SW2] = { + .sel= TWL4030_MADC_SW2SELECT_LSB, + .avg= TWL4030_MADC_SW2AVERAGE_LSB, + .rbase = TWL4030_MADC_GPCH0_LSB, + .ctrl = TWL4030_MADC_CTRL_SW2, + }, +}; + +static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg) +{ + int ret; + u8 val; + + ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, val, reg); + if (ret) { + dev_dbg(madc-dev, unable to read register 0x%X\n, reg); + return ret; + } + + return val; +} FWIW, you're not checking the return value on any of the madc_read calls below. +static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val) +{ + int ret; + + ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg); + if (ret) + dev_err(madc-dev, unable to write register 0x%X\n, reg); +} + +static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) +{ + u8 msb, lsb; + + /* For each ADC channel, we have MSB and LSB register pair. MSB address + * is always LSB address+1. reg parameter is the addr of LSB register */ + msb = twl4030_madc_read(madc, reg + 1); + lsb = twl4030_madc_read(madc, reg); + + return (int)(((msb 8) | lsb) 6); +} + +static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, + u8 reg_base, u16 channels, int *buf) +{ + int count = 0; + u8 reg, i; + + if (unlikely(!buf))