All of lore.kernel.org
 help / color / mirror / Atom feed
From: Amit Kucheria <amit.kucheria@verdurent.com>
To: sameo@linux.intel.com
Cc: List Linux Kernel <linux-kernel@vger.kernel.org>,
	linux-omap@vger.kernel.org,
	Mikko Ylinen <mikko.k.ylinen@nokia.com>
Subject: [PATCH] mfd: twl4030: Driver for twl4030 madc module
Date: Wed, 25 Nov 2009 12:47:51 +0200	[thread overview]
Message-ID: <1259146071-2372-1-git-send-email-amit.kucheria@verdurent.com> (raw)

From: Mikko Ylinen <mikko.k.ylinen@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.kucheria@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

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 08f2d07..fb1ba3a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -127,6 +127,27 @@ config TWL4030_CODEC
 	select MFD_CORE
 	default n
 
+config TWL4030_MADC
+	tristate "TWL4030 MADC Driver"
+       	depends on TWL4030_CORE
+       	help
+          The TWL4030 Monitoring ADC driver enables the host
+          processor to monitor analog signals using analog-to-digital
+          conversions on the input source. TWL4030 MADC provides the
+          following features:
+           - Single 10-bit ADC with successive approximation register (SAR) conversion;
+           - Analog multiplexer for 16 inputs;
+           - Seven (of the 16) inputs are freely available;
+           - Battery voltage monitoring;
+           - Concurrent conversion request management;
+           - Interrupt signal to Primary Interrupt Handler;
+           - Averaging feature;
+           - Selective enable/disable of the averaging feature.
+
+          Say 'y' here to statically link this module into the kernel or 'm'
+          to build it as a dinamically loadable module. The module will be
+          called twl4030-madc.ko
+
 config MFD_TMIO
 	bool
 	default n
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 0000000..90ce99a
--- /dev/null
+++ b/drivers/mfd/twl4030-madc.c
@@ -0,0 +1,548 @@
+/*
+ * drivers/i2c/chips/twl4030-madc.c
+ *
+ * TWL4030 MADC module driver
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@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];
+	int imr;
+	int isr;
+};
+
+static struct twl4030_madc_data *the_madc;
+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;
+}
+
+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))
+		return 0;
+
+	for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
+		if (channels & (1<<i)) {
+			reg = reg_base + 2*i;
+			buf[i] = twl4030_madc_channel_raw_read(madc, reg);
+			count++;
+		}
+	}
+	return count;
+}
+
+static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
+{
+	u8 val;
+
+	val = twl4030_madc_read(madc, madc->imr);
+	val &= ~(1 << id);
+	twl4030_madc_write(madc, madc->imr, val);
+}
+
+static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
+{
+	u8 val;
+
+	val = twl4030_madc_read(madc, madc->imr);
+	val |= (1 << id);
+	twl4030_madc_write(madc, madc->imr, val);
+}
+
+static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
+{
+	struct twl4030_madc_data *madc = _madc;
+	u8 isr_val, imr_val;
+	int i;
+
+#ifdef CONFIG_LOCKDEP
+	/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+	 * we don't want and can't tolerate.  Although it might be
+	 * friendlier not to borrow this thread context...
+	 */
+	local_irq_enable();
+#endif
+
+	/* Use COR to ack interrupts since we have no shared IRQs in ISRx */
+	isr_val = twl4030_madc_read(madc, madc->isr);
+	imr_val = twl4030_madc_read(madc, madc->imr);
+
+	isr_val &= ~imr_val;
+
+	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+
+		if (!(isr_val & (1<<i)))
+			continue;
+
+		twl4030_madc_disable_irq(madc, i);
+		madc->requests[i].result_pending = 1;
+	}
+
+	schedule_work(&madc->ws);
+
+	return IRQ_HANDLED;
+}
+
+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);
+}
+
+static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
+		struct twl4030_madc_request *req)
+{
+	struct twl4030_madc_request *p;
+
+	p = &madc->requests[req->method];
+
+	memcpy(p, req, sizeof *req);
+
+	twl4030_madc_enable_irq(madc, req->method);
+
+	return 0;
+}
+
+static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
+		int conv_method)
+{
+	const struct twl4030_madc_conversion_method *method;
+
+	method = &twl4030_conversion_methods[conv_method];
+
+	switch (conv_method) {
+	case TWL4030_MADC_SW1:
+	case TWL4030_MADC_SW2:
+		twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
+		break;
+	case TWL4030_MADC_RT:
+	default:
+		break;
+	}
+}
+
+static int twl4030_madc_wait_conversion_ready(
+		struct twl4030_madc_data *madc,
+		unsigned int timeout_ms, u8 status_reg)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(timeout_ms);
+	do {
+		int reg;
+
+		reg = twl4030_madc_read(madc, status_reg);
+		if (unlikely(reg < 0))
+			return reg;
+		if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
+			return 0;
+	} while (!time_after(jiffies, timeout));
+
+	return -EAGAIN;
+}
+
+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 + 1, ch_msb);
+	twl4030_madc_write(the_madc, method->sel, ch_lsb);
+
+	/* Select averaging for all channels if do_avg is set */
+	if (req->do_avg) {
+		twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
+		twl4030_madc_write(the_madc, method->avg, ch_lsb);
+	}
+
+	if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
+		twl4030_madc_set_irq(the_madc, req);
+		twl4030_madc_start_conversion(the_madc, req->method);
+		the_madc->requests[req->method].active = 1;
+		ret = 0;
+		goto out;
+	}
+
+	/* With RT method we should not be here anymore */
+	if (req->method == TWL4030_MADC_RT) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	twl4030_madc_start_conversion(the_madc, req->method);
+	the_madc->requests[req->method].active = 1;
+
+	/* Wait until conversion is ready (ctrl register returns EOC) */
+	ret = twl4030_madc_wait_conversion_ready(the_madc, 5, method->ctrl);
+	if (ret) {
+		dev_dbg(the_madc->dev, "conversion timeout!\n");
+		the_madc->requests[req->method].active = 0;
+		goto out;
+	}
+
+	ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
+					 req->rbuf);
+
+	the_madc->requests[req->method].active = 0;
+
+	twl4030_madc_set_power(the_madc, 0);
+
+out:
+	mutex_unlock(&the_madc->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(twl4030_madc_conversion);
+
+static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
+		int chan, int on)
+{
+	int ret;
+	u8 regval;
+
+	/* Current generator is only available for ADCIN0 and ADCIN1. NB:
+	 * ADCIN1 current generator only works when AC or VBUS is present */
+	if (chan > 1)
+		return EINVAL;
+
+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+				  &regval, TWL4030_BCI_BCICTL1);
+	if (ret) {
+		dev_dbg(madc->dev, "unable to read register 0x%X\n", TWL4030_BCI_BCICTL1);
+		return ret;
+	}
+
+	if (on) {
+		regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
+		regval |= TWL4030_BCI_MESBAT;
+	}
+	else {
+		regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
+		regval &= ~TWL4030_BCI_MESBAT;
+	}
+
+	ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
+				   regval, TWL4030_BCI_BCICTL1);
+	if (ret) {
+		dev_dbg(madc->dev, "unable to write register 0x%X\n", TWL4030_BCI_BCICTL1);
+	}
+	return ret;
+}
+
+static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
+{
+	int ret = 0;
+	u8 regval;
+
+	if (on) {
+		regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
+		regval |= TWL4030_MADC_MADCON;
+		twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
+
+		ret |= twl4030_madc_set_current_generator(madc, 0, 1);
+
+	} else {
+		ret |= twl4030_madc_set_current_generator(madc, 0, 0);
+
+		regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
+		regval &= ~TWL4030_MADC_MADCON;
+		twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
+	}
+	return ret;
+}
+
+static long twl4030_madc_ioctl(struct file *filp, unsigned int cmd,
+			       unsigned long arg)
+{
+	struct twl4030_madc_user_parms par;
+	int val, ret;
+
+	ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
+	if (ret) {
+		dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
+		return -EACCES;
+	}
+
+	switch (cmd) {
+	case TWL4030_MADC_IOCX_ADC_RAW_READ: {
+		struct twl4030_madc_request req;
+		if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
+			return -EINVAL;
+
+		req.channels = (1 << par.channel);
+		req.do_avg	= par.average;
+		req.method	= TWL4030_MADC_SW1;
+		req.func_cb	= NULL;
+		req.type	= TWL4030_MADC_WAIT;
+
+		val = twl4030_madc_conversion(&req);
+		if (likely(val > 0)) {
+			par.status = 0;
+			par.result = (u16)req.rbuf[par.channel];
+		} else if (val == 0) {
+			par.status = -ENODATA;
+		} else {
+			par.status = val;
+		}
+		break;
+					     }
+	default:
+		return -EINVAL;
+	}
+
+	ret = copy_to_user((void __user *) arg, &par, sizeof(par));
+	if (ret) {
+		dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
+		return -EACCES;
+	}
+
+	return 0;
+}
+
+static struct file_operations twl4030_madc_fileops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = twl4030_madc_ioctl
+};
+
+static struct miscdevice twl4030_madc_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "twl4030-adc",
+	.fops = &twl4030_madc_fileops
+};
+
+static int __init twl4030_madc_probe(struct platform_device *pdev)
+{
+	struct twl4030_madc_data *madc;
+	struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
+
+	int ret;
+	u8 regval;
+
+	madc = kzalloc(sizeof *madc, GFP_KERNEL);
+	if (!madc)
+		return -ENOMEM;
+
+	if (!pdata) {
+		dev_dbg(&pdev->dev, "platform_data not available\n");
+		ret = -EINVAL;
+		goto err_pdata;
+	}
+
+	madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+	madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
+
+	ret = misc_register(&twl4030_madc_device);
+	if (ret) {
+		dev_dbg(&pdev->dev, "could not register misc_device\n");
+		goto err_misc;
+	}
+
+	ret = request_irq(platform_get_irq(pdev, 0), twl4030_madc_irq_handler,
+			  0, "twl4030_madc", madc);
+	if (ret) {
+		dev_dbg(&pdev->dev, "could not request irq\n");
+		goto err_irq;
+	}
+
+	platform_set_drvdata(pdev, madc);
+	mutex_init(&madc->lock);
+	INIT_WORK(&madc->ws, twl4030_madc_work);
+
+	the_madc = madc;
+
+	return 0;
+
+err_irq:
+	misc_deregister(&twl4030_madc_device);
+
+err_misc:
+err_pdata:
+	kfree(madc);
+
+	return ret;
+}
+
+static int __exit twl4030_madc_remove(struct platform_device *pdev)
+{
+	struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
+
+	free_irq(platform_get_irq(pdev, 0), madc);
+	cancel_work_sync(&madc->ws);
+	misc_deregister(&twl4030_madc_device);
+
+	return 0;
+}
+
+static struct platform_driver twl4030_madc_driver = {
+	.probe		= twl4030_madc_probe,
+	.remove		= __exit_p(twl4030_madc_remove),
+	.driver		= {
+		.name	= "twl4030_madc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init twl4030_madc_init(void)
+{
+	return platform_driver_register(&twl4030_madc_driver);
+}
+module_init(twl4030_madc_init);
+
+static void __exit twl4030_madc_exit(void)
+{
+	platform_driver_unregister(&twl4030_madc_driver);
+}
+module_exit(twl4030_madc_exit);
+
+MODULE_ALIAS("platform:twl4030-madc");
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("twl4030 ADC driver");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
new file mode 100644
index 0000000..24523b5
--- /dev/null
+++ b/include/linux/i2c/twl4030-madc.h
@@ -0,0 +1,126 @@
+/*
+ * include/linux/i2c/twl4030-madc.h
+ *
+ * TWL4030 MADC module driver header
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@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
+ *
+ */
+
+#ifndef _TWL4030_MADC_H
+#define _TWL4030_MADC_H
+
+struct twl4030_madc_conversion_method {
+	u8 sel;
+	u8 avg;
+	u8 rbase;
+	u8 ctrl;
+};
+
+#define TWL4030_MADC_MAX_CHANNELS 16
+
+struct twl4030_madc_request {
+	u16 channels;
+	u16 do_avg;
+	u16 method;
+	u16 type;
+	int active;
+	int result_pending;
+	int rbuf[TWL4030_MADC_MAX_CHANNELS];
+	void (*func_cb)(int len, int channels, int *buf);
+};
+
+enum conversion_methods {
+	TWL4030_MADC_RT,
+	TWL4030_MADC_SW1,
+	TWL4030_MADC_SW2,
+	TWL4030_MADC_NUM_METHODS
+};
+
+enum sample_type {
+	TWL4030_MADC_WAIT,
+	TWL4030_MADC_IRQ_ONESHOT,
+	TWL4030_MADC_IRQ_REARM
+};
+
+#define TWL4030_MADC_CTRL1		0x00
+#define TWL4030_MADC_CTRL2		0x01
+
+#define TWL4030_MADC_RTSELECT_LSB	0x02
+#define TWL4030_MADC_SW1SELECT_LSB	0x06
+#define TWL4030_MADC_SW2SELECT_LSB	0x0A
+
+#define TWL4030_MADC_RTAVERAGE_LSB	0x04
+#define TWL4030_MADC_SW1AVERAGE_LSB	0x08
+#define TWL4030_MADC_SW2AVERAGE_LSB	0x0C
+
+#define TWL4030_MADC_CTRL_SW1		0x12
+#define TWL4030_MADC_CTRL_SW2		0x13
+
+#define TWL4030_MADC_RTCH0_LSB		0x17
+#define TWL4030_MADC_GPCH0_LSB		0x37
+
+#define TWL4030_MADC_MADCON		(1<<0)	/* MADC power on */
+#define TWL4030_MADC_BUSY		(1<<0)	/* MADC busy */
+#define TWL4030_MADC_EOC_SW		(1<<1)	/* MADC conversion completion */
+#define TWL4030_MADC_SW_START		(1<<5)  /* MADC SWx start conversion */
+
+#define	TWL4030_MADC_ADCIN0		(1<<0)
+#define	TWL4030_MADC_ADCIN1		(1<<1)
+#define	TWL4030_MADC_ADCIN2		(1<<2)
+#define	TWL4030_MADC_ADCIN3		(1<<3)
+#define	TWL4030_MADC_ADCIN4		(1<<4)
+#define	TWL4030_MADC_ADCIN5		(1<<5)
+#define	TWL4030_MADC_ADCIN6		(1<<6)
+#define	TWL4030_MADC_ADCIN7		(1<<7)
+#define	TWL4030_MADC_ADCIN8		(1<<8)
+#define	TWL4030_MADC_ADCIN9		(1<<9)
+#define	TWL4030_MADC_ADCIN10		(1<<10)
+#define	TWL4030_MADC_ADCIN11		(1<<11)
+#define	TWL4030_MADC_ADCIN12		(1<<12)
+#define	TWL4030_MADC_ADCIN13		(1<<13)
+#define	TWL4030_MADC_ADCIN14		(1<<14)
+#define	TWL4030_MADC_ADCIN15		(1<<15)
+
+/* Fixed channels */
+#define TWL4030_MADC_BTEMP		TWL4030_MADC_ADCIN1
+#define TWL4030_MADC_VBUS		TWL4030_MADC_ADCIN8
+#define TWL4030_MADC_VBKB		TWL4030_MADC_ADCIN9
+#define	TWL4030_MADC_ICHG		TWL4030_MADC_ADCIN10
+#define TWL4030_MADC_VCHG		TWL4030_MADC_ADCIN11
+#define	TWL4030_MADC_VBAT		TWL4030_MADC_ADCIN12
+
+/* BCI related - XXX To be moved elsewhere */
+#define TWL4030_BCI_BCICTL1		0x23
+#define	TWL4030_BCI_MESBAT		(1<<1)
+#define	TWL4030_BCI_TYPEN		(1<<4)
+#define	TWL4030_BCI_ITHEN		(1<<3)
+
+#define TWL4030_MADC_IOC_MAGIC '`'
+#define TWL4030_MADC_IOCX_ADC_RAW_READ		_IO(TWL4030_MADC_IOC_MAGIC, 0)
+
+struct twl4030_madc_user_parms {
+	int channel;
+	int average;
+	int status;
+	u16 result;
+};
+
+int twl4030_madc_conversion(struct twl4030_madc_request *conv);
+
+#endif
-- 
1.6.3.3


             reply	other threads:[~2009-11-25 10:48 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-11-25 10:47 Amit Kucheria [this message]
2009-11-27 19:36 ` [PATCH] mfd: twl4030: Driver for twl4030 madc module Samuel Ortiz
2009-11-30 13:58   ` Amit Kucheria
2009-11-30 17:52     ` Jean Delvare
2009-12-01 10:19     ` Samuel Ortiz
2009-12-01 10:19       ` Samuel Ortiz
2010-01-20 12:12 ` Sergey Lapin
2010-01-20 12:12   ` Sergey Lapin
2010-01-25  9:34   ` Janakiram Sistla
2010-07-19 17:46     ` Michael Trimarchi
     [not found]       ` <AANLkTim2tgfAOHXXXlTBuDzEj5ndWfCX7XUXtjvkCNmq@mail.gmail.com>
2010-07-19 18:24         ` Michael Trimarchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1259146071-2372-1-git-send-email-amit.kucheria@verdurent.com \
    --to=amit.kucheria@verdurent.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=mikko.k.ylinen@nokia.com \
    --cc=sameo@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.