summaryrefslogtreecommitdiffstats
path: root/extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch')
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch740
1 files changed, 740 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch b/extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch
new file mode 100644
index 00000000..a55136db
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch
@@ -0,0 +1,740 @@
1From 562dc52ebe3df1e5d23416e78306db7c568dc427 Mon Sep 17 00:00:00 2001
2From: Steve Sakoman <steve@sakoman.com>
3Date: Thu, 17 Dec 2009 14:19:34 -0800
4Subject: [PATCH 18/28] MFD: add twl4030 madc driver
5
6---
7 drivers/mfd/Kconfig | 21 ++
8 drivers/mfd/Makefile | 1 +
9 drivers/mfd/twl4030-madc.c | 537 ++++++++++++++++++++++++++++++++++++++
10 include/linux/i2c/twl4030-madc.h | 130 +++++++++
11 4 files changed, 689 insertions(+), 0 deletions(-)
12 create mode 100644 drivers/mfd/twl4030-madc.c
13 create mode 100644 include/linux/i2c/twl4030-madc.h
14
15diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
16index 3a1493b..26ca160 100644
17--- a/drivers/mfd/Kconfig
18+++ b/drivers/mfd/Kconfig
19@@ -186,6 +186,27 @@ config TWL4030_CODEC
20 select MFD_CORE
21 default n
22
23+config TWL4030_MADC
24+ tristate "TWL4030 MADC Driver"
25+ depends on TWL4030_CORE
26+ help
27+ The TWL4030 Monitoring ADC driver enables the host
28+ processor to monitor analog signals using analog-to-digital
29+ conversions on the input source. TWL4030 MADC provides the
30+ following features:
31+ - Single 10-bit ADC with successive approximation register (SAR) conversion;
32+ - Analog multiplexer for 16 inputs;
33+ - Seven (of the 16) inputs are freely available;
34+ - Battery voltage monitoring;
35+ - Concurrent conversion request management;
36+ - Interrupt signal to Primary Interrupt Handler;
37+ - Averaging feature;
38+ - Selective enable/disable of the averaging feature.
39+
40+ Say 'y' here to statically link this module into the kernel or 'm'
41+ to build it as a dinamically loadable module. The module will be
42+ called twl4030-madc.ko
43+
44 config TWL6030_PWM
45 tristate "TWL6030 PWM (Pulse Width Modulator) Support"
46 depends on TWL4030_CORE
47diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
48index f54b365..8c4ccb2 100644
49--- a/drivers/mfd/Makefile
50+++ b/drivers/mfd/Makefile
51@@ -39,6 +39,7 @@ obj-$(CONFIG_MENELAUS) += menelaus.o
52 obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
53 obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
54 obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
55+obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
56 obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
57
58 obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
59diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
60new file mode 100644
61index 0000000..4adf880
62--- /dev/null
63+++ b/drivers/mfd/twl4030-madc.c
64@@ -0,0 +1,537 @@
65+/*
66+ * TWL4030 MADC module driver
67+ *
68+ * Copyright (C) 2008 Nokia Corporation
69+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
70+ *
71+ * This program is free software; you can redistribute it and/or
72+ * modify it under the terms of the GNU General Public License
73+ * version 2 as published by the Free Software Foundation.
74+ *
75+ * This program is distributed in the hope that it will be useful, but
76+ * WITHOUT ANY WARRANTY; without even the implied warranty of
77+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
78+ * General Public License for more details.
79+ *
80+ * You should have received a copy of the GNU General Public License
81+ * along with this program; if not, write to the Free Software
82+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
83+ * 02110-1301 USA
84+ *
85+ */
86+
87+#include <linux/delay.h>
88+#include <linux/fs.h>
89+#include <linux/init.h>
90+#include <linux/interrupt.h>
91+#include <linux/kernel.h>
92+#include <linux/miscdevice.h>
93+#include <linux/module.h>
94+#include <linux/platform_device.h>
95+#include <linux/slab.h>
96+#include <linux/types.h>
97+#include <linux/i2c/twl.h>
98+#include <linux/i2c/twl4030-madc.h>
99+
100+#include <asm/uaccess.h>
101+
102+#define TWL4030_MADC_PFX "twl4030-madc: "
103+
104+struct twl4030_madc_data {
105+ struct device *dev;
106+ struct mutex lock;
107+ struct work_struct ws;
108+ struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
109+ int imr;
110+ int isr;
111+};
112+
113+static struct twl4030_madc_data *the_madc;
114+
115+static
116+const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
117+ [TWL4030_MADC_RT] = {
118+ .sel = TWL4030_MADC_RTSELECT_LSB,
119+ .avg = TWL4030_MADC_RTAVERAGE_LSB,
120+ .rbase = TWL4030_MADC_RTCH0_LSB,
121+ },
122+ [TWL4030_MADC_SW1] = {
123+ .sel = TWL4030_MADC_SW1SELECT_LSB,
124+ .avg = TWL4030_MADC_SW1AVERAGE_LSB,
125+ .rbase = TWL4030_MADC_GPCH0_LSB,
126+ .ctrl = TWL4030_MADC_CTRL_SW1,
127+ },
128+ [TWL4030_MADC_SW2] = {
129+ .sel = TWL4030_MADC_SW2SELECT_LSB,
130+ .avg = TWL4030_MADC_SW2AVERAGE_LSB,
131+ .rbase = TWL4030_MADC_GPCH0_LSB,
132+ .ctrl = TWL4030_MADC_CTRL_SW2,
133+ },
134+};
135+
136+static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
137+{
138+ int ret;
139+ u8 val;
140+
141+ ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
142+ if (ret) {
143+ dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
144+ return ret;
145+ }
146+
147+ return val;
148+}
149+
150+static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
151+{
152+ int ret;
153+
154+ ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
155+ if (ret)
156+ dev_err(madc->dev, "unable to write register 0x%X\n", reg);
157+}
158+
159+static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
160+{
161+ u8 msb, lsb;
162+
163+ /* For each ADC channel, we have MSB and LSB register pair. MSB address
164+ * is always LSB address+1. reg parameter is the addr of LSB register */
165+ msb = twl4030_madc_read(madc, reg + 1);
166+ lsb = twl4030_madc_read(madc, reg);
167+
168+ return (int)(((msb << 8) | lsb) >> 6);
169+}
170+
171+static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
172+ u8 reg_base, u16 channels, int *buf)
173+{
174+ int count = 0;
175+ u8 reg, i;
176+
177+ if (unlikely(!buf))
178+ return 0;
179+
180+ for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
181+ if (channels & (1<<i)) {
182+ reg = reg_base + 2*i;
183+ buf[i] = twl4030_madc_channel_raw_read(madc, reg);
184+ count++;
185+ }
186+ }
187+ return count;
188+}
189+
190+static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
191+{
192+ u8 val;
193+
194+ val = twl4030_madc_read(madc, madc->imr);
195+ val &= ~(1 << id);
196+ twl4030_madc_write(madc, madc->imr, val);
197+}
198+
199+static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
200+{
201+ u8 val;
202+
203+ val = twl4030_madc_read(madc, madc->imr);
204+ val |= (1 << id);
205+ twl4030_madc_write(madc, madc->imr, val);
206+}
207+
208+static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
209+{
210+ struct twl4030_madc_data *madc = _madc;
211+ u8 isr_val, imr_val;
212+ int i;
213+
214+#ifdef CONFIG_LOCKDEP
215+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
216+ * we don't want and can't tolerate. Although it might be
217+ * friendlier not to borrow this thread context...
218+ */
219+ local_irq_enable();
220+#endif
221+
222+ /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
223+ isr_val = twl4030_madc_read(madc, madc->isr);
224+ imr_val = twl4030_madc_read(madc, madc->imr);
225+
226+ isr_val &= ~imr_val;
227+
228+ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
229+
230+ if (!(isr_val & (1<<i)))
231+ continue;
232+
233+ twl4030_madc_disable_irq(madc, i);
234+ madc->requests[i].result_pending = 1;
235+ }
236+
237+ schedule_work(&madc->ws);
238+
239+ return IRQ_HANDLED;
240+}
241+
242+static void twl4030_madc_work(struct work_struct *ws)
243+{
244+ const struct twl4030_madc_conversion_method *method;
245+ struct twl4030_madc_data *madc;
246+ struct twl4030_madc_request *r;
247+ int len, i;
248+
249+ madc = container_of(ws, struct twl4030_madc_data, ws);
250+ mutex_lock(&madc->lock);
251+
252+ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
253+
254+ r = &madc->requests[i];
255+
256+ /* No pending results for this method, move to next one */
257+ if (!r->result_pending)
258+ continue;
259+
260+ method = &twl4030_conversion_methods[r->method];
261+
262+ /* Read results */
263+ len = twl4030_madc_read_channels(madc, method->rbase,
264+ r->channels, r->rbuf);
265+
266+ /* Return results to caller */
267+ if (r->func_cb != NULL) {
268+ r->func_cb(len, r->channels, r->rbuf);
269+ r->func_cb = NULL;
270+ }
271+
272+ /* Free request */
273+ r->result_pending = 0;
274+ r->active = 0;
275+ }
276+
277+ mutex_unlock(&madc->lock);
278+}
279+
280+static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
281+ struct twl4030_madc_request *req)
282+{
283+ struct twl4030_madc_request *p;
284+
285+ p = &madc->requests[req->method];
286+
287+ memcpy(p, req, sizeof *req);
288+
289+ twl4030_madc_enable_irq(madc, req->method);
290+
291+ return 0;
292+}
293+
294+static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
295+ int conv_method)
296+{
297+ const struct twl4030_madc_conversion_method *method;
298+
299+ method = &twl4030_conversion_methods[conv_method];
300+
301+ switch (conv_method) {
302+ case TWL4030_MADC_SW1:
303+ case TWL4030_MADC_SW2:
304+ twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
305+ break;
306+ case TWL4030_MADC_RT:
307+ default:
308+ break;
309+ }
310+}
311+
312+static int twl4030_madc_wait_conversion_ready(
313+ struct twl4030_madc_data *madc,
314+ unsigned int timeout_ms, u8 status_reg)
315+{
316+ unsigned long timeout;
317+
318+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
319+ do {
320+ u8 reg;
321+
322+ reg = twl4030_madc_read(madc, status_reg);
323+ if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
324+ return 0;
325+ } while (!time_after(jiffies, timeout));
326+
327+ return -EAGAIN;
328+}
329+
330+int twl4030_madc_conversion(struct twl4030_madc_request *req)
331+{
332+ const struct twl4030_madc_conversion_method *method;
333+ u8 ch_msb, ch_lsb;
334+ int ret;
335+
336+ if (unlikely(!req))
337+ return -EINVAL;
338+
339+ mutex_lock(&the_madc->lock);
340+
341+ /* Do we have a conversion request ongoing */
342+ if (the_madc->requests[req->method].active) {
343+ ret = -EBUSY;
344+ goto out;
345+ }
346+
347+ ch_msb = (req->channels >> 8) & 0xff;
348+ ch_lsb = req->channels & 0xff;
349+
350+ method = &twl4030_conversion_methods[req->method];
351+
352+ /* Select channels to be converted */
353+ twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
354+ twl4030_madc_write(the_madc, method->sel, ch_lsb);
355+
356+ /* Select averaging for all channels if do_avg is set */
357+ if (req->do_avg) {
358+ twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
359+ twl4030_madc_write(the_madc, method->avg, ch_lsb);
360+ }
361+
362+ if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
363+ twl4030_madc_set_irq(the_madc, req);
364+ twl4030_madc_start_conversion(the_madc, req->method);
365+ the_madc->requests[req->method].active = 1;
366+ ret = 0;
367+ goto out;
368+ }
369+
370+ /* With RT method we should not be here anymore */
371+ if (req->method == TWL4030_MADC_RT) {
372+ ret = -EINVAL;
373+ goto out;
374+ }
375+
376+ twl4030_madc_start_conversion(the_madc, req->method);
377+ the_madc->requests[req->method].active = 1;
378+
379+ /* Wait until conversion is ready (ctrl register returns EOC) */
380+ ret = twl4030_madc_wait_conversion_ready(the_madc, 5, method->ctrl);
381+ if (ret) {
382+ dev_dbg(the_madc->dev, "conversion timeout!\n");
383+ the_madc->requests[req->method].active = 0;
384+ goto out;
385+ }
386+
387+ ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
388+ req->rbuf);
389+
390+ the_madc->requests[req->method].active = 0;
391+
392+out:
393+ mutex_unlock(&the_madc->lock);
394+
395+ return ret;
396+}
397+EXPORT_SYMBOL(twl4030_madc_conversion);
398+
399+static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
400+ int chan, int on)
401+{
402+ int ret;
403+ u8 regval;
404+
405+ /* Current generator is only available for ADCIN0 and ADCIN1. NB:
406+ * ADCIN1 current generator only works when AC or VBUS is present */
407+ if (chan > 1)
408+ return EINVAL;
409+
410+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
411+ &regval, TWL4030_BCI_BCICTL1);
412+ if (on)
413+ regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
414+ else
415+ regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
416+ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
417+ regval, TWL4030_BCI_BCICTL1);
418+
419+ return ret;
420+}
421+
422+static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
423+{
424+ u8 regval;
425+
426+ regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
427+ if (on)
428+ regval |= TWL4030_MADC_MADCON;
429+ else
430+ regval &= ~TWL4030_MADC_MADCON;
431+ twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
432+
433+ return 0;
434+}
435+
436+static long twl4030_madc_ioctl(struct file *filp, unsigned int cmd,
437+ unsigned long arg)
438+{
439+ struct twl4030_madc_user_parms par;
440+ int val, ret;
441+
442+ ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
443+ if (ret) {
444+ dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
445+ return -EACCES;
446+ }
447+
448+ switch (cmd) {
449+ case TWL4030_MADC_IOCX_ADC_RAW_READ: {
450+ struct twl4030_madc_request req;
451+ if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
452+ return -EINVAL;
453+
454+ req.channels = (1 << par.channel);
455+ req.do_avg = par.average;
456+ req.method = TWL4030_MADC_SW1;
457+ req.func_cb = NULL;
458+
459+ val = twl4030_madc_conversion(&req);
460+ if (val <= 0) {
461+ par.status = -1;
462+ } else {
463+ par.status = 0;
464+ par.result = (u16)req.rbuf[par.channel];
465+ }
466+ break;
467+ }
468+ default:
469+ return -EINVAL;
470+ }
471+
472+ ret = copy_to_user((void __user *) arg, &par, sizeof(par));
473+ if (ret) {
474+ dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
475+ return -EACCES;
476+ }
477+
478+ return 0;
479+}
480+
481+static struct file_operations twl4030_madc_fileops = {
482+ .owner = THIS_MODULE,
483+ .unlocked_ioctl = twl4030_madc_ioctl
484+};
485+
486+static struct miscdevice twl4030_madc_device = {
487+ .minor = MISC_DYNAMIC_MINOR,
488+ .name = "twl4030-madc",
489+ .fops = &twl4030_madc_fileops
490+};
491+
492+static int __init twl4030_madc_probe(struct platform_device *pdev)
493+{
494+ struct twl4030_madc_data *madc;
495+ struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
496+ int ret;
497+ u8 regval;
498+
499+ madc = kzalloc(sizeof *madc, GFP_KERNEL);
500+ if (!madc)
501+ return -ENOMEM;
502+
503+ if (!pdata) {
504+ dev_dbg(&pdev->dev, "platform_data not available\n");
505+ ret = -EINVAL;
506+ goto err_pdata;
507+ }
508+
509+ madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
510+ madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
511+
512+ ret = misc_register(&twl4030_madc_device);
513+ if (ret) {
514+ dev_dbg(&pdev->dev, "could not register misc_device\n");
515+ goto err_misc;
516+ }
517+ twl4030_madc_set_power(madc, 1);
518+ twl4030_madc_set_current_generator(madc, 0, 1);
519+
520+ /* Enable ADCIN3 through 6 */
521+ ret = twl_i2c_read_u8(TWL4030_MODULE_USB,
522+ &regval, TWL4030_USB_CARKIT_ANA_CTRL);
523+
524+ regval |= TWL4030_USB_SEL_MADC_MCPC;
525+
526+ ret = twl_i2c_write_u8(TWL4030_MODULE_USB,
527+ regval, TWL4030_USB_CARKIT_ANA_CTRL);
528+
529+
530+ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
531+ &regval, TWL4030_BCI_BCICTL1);
532+
533+ regval |= TWL4030_BCI_MESBAT;
534+
535+ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
536+ regval, TWL4030_BCI_BCICTL1);
537+
538+ ret = request_irq(platform_get_irq(pdev, 0), twl4030_madc_irq_handler,
539+ 0, "twl4030_madc", madc);
540+ if (ret) {
541+ dev_dbg(&pdev->dev, "could not request irq\n");
542+ goto err_irq;
543+ }
544+
545+ platform_set_drvdata(pdev, madc);
546+ mutex_init(&madc->lock);
547+ INIT_WORK(&madc->ws, twl4030_madc_work);
548+
549+ the_madc = madc;
550+
551+ return 0;
552+
553+err_irq:
554+ misc_deregister(&twl4030_madc_device);
555+
556+err_misc:
557+err_pdata:
558+ kfree(madc);
559+
560+ return ret;
561+}
562+
563+static int __exit twl4030_madc_remove(struct platform_device *pdev)
564+{
565+ struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
566+
567+ twl4030_madc_set_power(madc, 0);
568+ twl4030_madc_set_current_generator(madc, 0, 0);
569+ free_irq(platform_get_irq(pdev, 0), madc);
570+ cancel_work_sync(&madc->ws);
571+ misc_deregister(&twl4030_madc_device);
572+
573+ return 0;
574+}
575+
576+static struct platform_driver twl4030_madc_driver = {
577+ .probe = twl4030_madc_probe,
578+ .remove = __exit_p(twl4030_madc_remove),
579+ .driver = {
580+ .name = "twl4030_madc",
581+ .owner = THIS_MODULE,
582+ },
583+};
584+
585+static int __init twl4030_madc_init(void)
586+{
587+ return platform_driver_register(&twl4030_madc_driver);
588+}
589+module_init(twl4030_madc_init);
590+
591+static void __exit twl4030_madc_exit(void)
592+{
593+ platform_driver_unregister(&twl4030_madc_driver);
594+}
595+module_exit(twl4030_madc_exit);
596+
597+MODULE_ALIAS("platform:twl4030-madc");
598+MODULE_AUTHOR("Nokia Corporation");
599+MODULE_DESCRIPTION("twl4030 ADC driver");
600+MODULE_LICENSE("GPL");
601+
602diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
603new file mode 100644
604index 0000000..341a665
605--- /dev/null
606+++ b/include/linux/i2c/twl4030-madc.h
607@@ -0,0 +1,130 @@
608+/*
609+ * include/linux/i2c/twl4030-madc.h
610+ *
611+ * TWL4030 MADC module driver header
612+ *
613+ * Copyright (C) 2008 Nokia Corporation
614+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
615+ *
616+ * This program is free software; you can redistribute it and/or
617+ * modify it under the terms of the GNU General Public License
618+ * version 2 as published by the Free Software Foundation.
619+ *
620+ * This program is distributed in the hope that it will be useful, but
621+ * WITHOUT ANY WARRANTY; without even the implied warranty of
622+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
623+ * General Public License for more details.
624+ *
625+ * You should have received a copy of the GNU General Public License
626+ * along with this program; if not, write to the Free Software
627+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
628+ * 02110-1301 USA
629+ *
630+ */
631+
632+#ifndef _TWL4030_MADC_H
633+#define _TWL4030_MADC_H
634+
635+struct twl4030_madc_conversion_method {
636+ u8 sel;
637+ u8 avg;
638+ u8 rbase;
639+ u8 ctrl;
640+};
641+
642+#define TWL4030_MADC_MAX_CHANNELS 16
643+
644+struct twl4030_madc_request {
645+ u16 channels;
646+ u16 do_avg;
647+ u16 method;
648+ u16 type;
649+ int active;
650+ int result_pending;
651+ int rbuf[TWL4030_MADC_MAX_CHANNELS];
652+ void (*func_cb)(int len, int channels, int *buf);
653+};
654+
655+enum conversion_methods {
656+ TWL4030_MADC_RT,
657+ TWL4030_MADC_SW1,
658+ TWL4030_MADC_SW2,
659+ TWL4030_MADC_NUM_METHODS
660+};
661+
662+enum sample_type {
663+ TWL4030_MADC_WAIT,
664+ TWL4030_MADC_IRQ_ONESHOT,
665+ TWL4030_MADC_IRQ_REARM
666+};
667+
668+#define TWL4030_MADC_CTRL1 0x00
669+#define TWL4030_MADC_CTRL2 0x01
670+
671+#define TWL4030_MADC_RTSELECT_LSB 0x02
672+#define TWL4030_MADC_SW1SELECT_LSB 0x06
673+#define TWL4030_MADC_SW2SELECT_LSB 0x0A
674+
675+#define TWL4030_MADC_RTAVERAGE_LSB 0x04
676+#define TWL4030_MADC_SW1AVERAGE_LSB 0x08
677+#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C
678+
679+#define TWL4030_MADC_CTRL_SW1 0x12
680+#define TWL4030_MADC_CTRL_SW2 0x13
681+
682+#define TWL4030_MADC_RTCH0_LSB 0x17
683+#define TWL4030_MADC_GPCH0_LSB 0x37
684+
685+#define TWL4030_MADC_MADCON (1<<0) /* MADC power on */
686+#define TWL4030_MADC_BUSY (1<<0) /* MADC busy */
687+#define TWL4030_MADC_EOC_SW (1<<1) /* MADC conversion completion */
688+#define TWL4030_MADC_SW_START (1<<5) /* MADC SWx start conversion */
689+
690+#define TWL4030_MADC_ADCIN0 (1<<0)
691+#define TWL4030_MADC_ADCIN1 (1<<1)
692+#define TWL4030_MADC_ADCIN2 (1<<2)
693+#define TWL4030_MADC_ADCIN3 (1<<3)
694+#define TWL4030_MADC_ADCIN4 (1<<4)
695+#define TWL4030_MADC_ADCIN5 (1<<5)
696+#define TWL4030_MADC_ADCIN6 (1<<6)
697+#define TWL4030_MADC_ADCIN7 (1<<7)
698+#define TWL4030_MADC_ADCIN8 (1<<8)
699+#define TWL4030_MADC_ADCIN9 (1<<9)
700+#define TWL4030_MADC_ADCIN10 (1<<10)
701+#define TWL4030_MADC_ADCIN11 (1<<11)
702+#define TWL4030_MADC_ADCIN12 (1<<12)
703+#define TWL4030_MADC_ADCIN13 (1<<13)
704+#define TWL4030_MADC_ADCIN14 (1<<14)
705+#define TWL4030_MADC_ADCIN15 (1<<15)
706+
707+/* Fixed channels */
708+#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1
709+#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8
710+#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9
711+#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10
712+#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11
713+#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12
714+
715+/* BCI related - XXX To be moved elsewhere */
716+#define TWL4030_BCI_BCICTL1 0x23
717+#define TWL4030_BCI_MESBAT (1<<1)
718+#define TWL4030_BCI_TYPEN (1<<4)
719+#define TWL4030_BCI_ITHEN (1<<3)
720+
721+/* USB related - XXX To be moved elsewhere */
722+#define TWL4030_USB_CARKIT_ANA_CTRL 0xBB
723+#define TWL4030_USB_SEL_MADC_MCPC (1<<3)
724+
725+#define TWL4030_MADC_IOC_MAGIC '`'
726+#define TWL4030_MADC_IOCX_ADC_RAW_READ _IO(TWL4030_MADC_IOC_MAGIC, 0)
727+
728+struct twl4030_madc_user_parms {
729+ int channel;
730+ int average;
731+ int status;
732+ u16 result;
733+};
734+
735+int twl4030_madc_conversion(struct twl4030_madc_request *conv);
736+
737+#endif
738--
7391.6.6.1
740