2 * drivers/i2c/chips/twl4030-madc.c
4 * TWL4030 MADC module driver
6 * Copyright (C) 2008 Nokia Corporation
7 * Mikko Ylinen <mikko.k.ylinen@nokia.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25 #include <linux/init.h>
26 #include <linux/interrupt.h>
27 #include <linux/kernel.h>
28 #include <linux/types.h>
29 #include <linux/module.h>
30 #include <linux/delay.h>
32 #include <linux/miscdevice.h>
33 #include <linux/i2c/twl4030.h>
34 #include <linux/i2c/twl4030-madc.h>
36 #include <asm/uaccess.h>
38 #define TWL4030_MADC_PFX "twl4030-madc: "
40 static struct twl4030_madc_data
{
42 struct work_struct ws
;
43 struct twl4030_madc_request requests
[TWL4030_MADC_NUM_METHODS
];
46 static const char irq_pin
= 1; /* XXX Read from platfrom data */
49 const struct twl4030_madc_conversion_method twl4030_conversion_methods
[] = {
51 .sel
= TWL4030_MADC_RTSELECT_LSB
,
52 .avg
= TWL4030_MADC_RTAVERAGE_LSB
,
53 .rbase
= TWL4030_MADC_RTCH0_LSB
,
55 [TWL4030_MADC_SW1
] = {
56 .sel
= TWL4030_MADC_SW1SELECT_LSB
,
57 .avg
= TWL4030_MADC_SW1AVERAGE_LSB
,
58 .rbase
= TWL4030_MADC_GPCH0_LSB
,
59 .ctrl
= TWL4030_MADC_CTRL_SW1
,
61 [TWL4030_MADC_SW2
] = {
62 .sel
= TWL4030_MADC_SW2SELECT_LSB
,
63 .avg
= TWL4030_MADC_SW2AVERAGE_LSB
,
64 .rbase
= TWL4030_MADC_GPCH0_LSB
,
65 .ctrl
= TWL4030_MADC_CTRL_SW2
,
69 static void twl4030_madc_read(u8 reg
, u8
*val
)
71 int ret
= twl4030_i2c_read_u8(TWL4030_MODULE_MADC
, val
, reg
);
73 printk(KERN_ERR TWL4030_MADC_PFX
74 "unable to read register 0x%X\n", reg
);
77 static void twl4030_madc_write(u8 reg
, u8 val
)
79 int ret
= twl4030_i2c_write_u8(TWL4030_MODULE_MADC
, val
, reg
);
81 printk(KERN_ERR TWL4030_MADC_PFX
82 "unable to write register 0x%X\n", reg
);
85 static int twl4030_madc_channel_raw_read(u8 reg
)
89 /* For each ADC channel, we have MSB and LSB register pair. MSB address
90 * is always LSB address+1. reg parameter is the addr of LSB register */
91 twl4030_madc_read(reg
+1, &msb
);
92 twl4030_madc_read(reg
, &lsb
);
94 return (int)(((msb
<< 8) | lsb
) >> 6);
97 static int twl4030_madc_read_channels(u8 reg_base
, u16 channels
, int *buf
)
105 for (i
= 0; i
< TWL4030_MADC_MAX_CHANNELS
; i
++) {
106 if (channels
& (1<<i
)) {
107 reg
= reg_base
+ 2*i
;
108 buf
[i
] = twl4030_madc_channel_raw_read(reg
);
115 static void twl4030_madc_enable_irq(int id
)
119 static u8 imr
= (irq_pin
== 1) ? TWL4030_MADC_IMR1
: TWL4030_MADC_IMR2
;
121 twl4030_madc_read(imr
, &val
);
123 twl4030_madc_write(imr
, val
);
126 static void twl4030_madc_disable_irq(int id
)
130 static u8 imr
= (irq_pin
== 1) ? TWL4030_MADC_IMR1
: TWL4030_MADC_IMR2
;
132 twl4030_madc_read(imr
, &val
);
134 twl4030_madc_write(imr
, val
);
137 static irqreturn_t
twl4030_madc_irq_handler(int irq
, void *madc_dev
)
143 imr
= (irq_pin
== 1) ? TWL4030_MADC_IMR1
: TWL4030_MADC_IMR2
;
144 isr
= (irq_pin
== 1) ? TWL4030_MADC_ISR1
: TWL4030_MADC_ISR2
;
146 /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
147 twl4030_madc_read(isr
, &isr_val
);
148 twl4030_madc_read(imr
, &imr_val
);
152 for (i
= 0; i
< TWL4030_MADC_NUM_METHODS
; i
++) {
154 if (!(isr_val
& (1<<i
)))
157 twl4030_madc_disable_irq(i
);
158 twl4030_madc
.requests
[i
].result_pending
= 1;
161 schedule_work(&twl4030_madc
.ws
);
166 static void twl4030_madc_work(struct work_struct
*ws
)
168 const struct twl4030_madc_conversion_method
*method
;
169 struct twl4030_madc_request
*r
;
172 mutex_lock(&twl4030_madc
.lock
);
174 for (i
= 0; i
< TWL4030_MADC_NUM_METHODS
; i
++) {
176 r
= &twl4030_madc
.requests
[i
];
178 /* No pending results for this method, move to next one */
179 if (!r
->result_pending
)
182 method
= &twl4030_conversion_methods
[r
->method
];
185 len
= twl4030_madc_read_channels(method
->rbase
,
186 r
->channels
, r
->rbuf
);
188 /* Return results to caller */
189 if (r
->func_cb
!= NULL
) {
190 r
->func_cb(len
, r
->channels
, r
->rbuf
);
195 r
->result_pending
= 0;
199 mutex_unlock(&twl4030_madc
.lock
);
202 static int twl4030_madc_set_irq(struct twl4030_madc_request
*req
)
204 struct twl4030_madc_request
*p
;
206 p
= &twl4030_madc
.requests
[req
->method
];
208 memcpy(p
, req
, sizeof *req
);
210 twl4030_madc_enable_irq(req
->method
);
215 static inline void twl4030_madc_start_conversion(int conv_method
)
217 const struct twl4030_madc_conversion_method
*method
;
219 method
= &twl4030_conversion_methods
[conv_method
];
221 switch (conv_method
) {
222 case TWL4030_MADC_SW1
:
223 case TWL4030_MADC_SW2
:
224 twl4030_madc_write(method
->ctrl
, TWL4030_MADC_SW_START
);
226 case TWL4030_MADC_RT
:
232 static void twl4030_madc_wait_conversion_ready_ms(u8
*time
, u8 status_reg
)
239 twl4030_madc_read(status_reg
, ®
);
240 } while (((reg
& TWL4030_MADC_BUSY
) && !(reg
& TWL4030_MADC_EOC_SW
)) &&
244 int twl4030_madc_conversion(struct twl4030_madc_request
*req
)
246 const struct twl4030_madc_conversion_method
*method
;
247 u8 wait_time
, ch_msb
, ch_lsb
;
253 /* Do we have a conversion request ongoing */
254 if (twl4030_madc
.requests
[req
->method
].active
)
257 ch_msb
= (req
->channels
>> 8) & 0xff;
258 ch_lsb
= req
->channels
& 0xff;
260 method
= &twl4030_conversion_methods
[req
->method
];
262 mutex_lock(&twl4030_madc
.lock
);
264 /* Select channels to be converted */
265 twl4030_madc_write(method
->sel
+ 1, ch_msb
);
266 twl4030_madc_write(method
->sel
, ch_lsb
);
268 /* Select averaging for all channels if do_avg is set */
270 twl4030_madc_write(method
->avg
+ 1, ch_msb
);
271 twl4030_madc_write(method
->avg
, ch_lsb
);
274 if ((req
->type
== TWL4030_MADC_IRQ_ONESHOT
) && (req
->func_cb
!= NULL
)) {
275 twl4030_madc_set_irq(req
);
276 twl4030_madc_start_conversion(req
->method
);
277 twl4030_madc
.requests
[req
->method
].active
= 1;
282 /* With RT method we should not be here anymore */
283 if (req
->method
== TWL4030_MADC_RT
) {
288 twl4030_madc_start_conversion(req
->method
);
289 twl4030_madc
.requests
[req
->method
].active
= 1;
291 /* Wait until conversion is ready (ctrl register returns EOC) */
293 twl4030_madc_wait_conversion_ready_ms(&wait_time
, method
->ctrl
);
294 if (wait_time
== 0) {
295 printk(KERN_ERR TWL4030_MADC_PFX
"conversion timeout!\n");
300 ret
= twl4030_madc_read_channels(method
->rbase
, req
->channels
,
303 twl4030_madc
.requests
[req
->method
].active
= 0;
306 mutex_unlock(&twl4030_madc
.lock
);
311 EXPORT_SYMBOL(twl4030_madc_conversion
);
313 static int twl4030_madc_set_current_generator(int chan
, int on
)
318 /* Current generator is only available for ADCIN0 and ADCIN1. NB:
319 * ADCIN1 current generator only works when AC or VBUS is present */
323 ret
= twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE
,
324 ®val
, TWL4030_BCI_BCICTL1
);
326 regval
|= (chan
) ? TWL4030_BCI_ITHEN
: TWL4030_BCI_TYPEN
;
328 regval
&= (chan
) ? ~TWL4030_BCI_ITHEN
: ~TWL4030_BCI_TYPEN
;
329 ret
= twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE
,
330 regval
, TWL4030_BCI_BCICTL1
);
335 static int twl4030_madc_set_power(int on
)
339 twl4030_madc_read(TWL4030_MADC_CTRL1
, ®val
);
341 regval
|= TWL4030_MADC_MADCON
;
343 regval
&= ~TWL4030_MADC_MADCON
;
344 twl4030_madc_write(TWL4030_MADC_CTRL1
, regval
);
349 static int twl4030_madc_ioctl(struct inode
*inode
, struct file
*filp
,
350 unsigned int cmd
, unsigned long arg
)
352 struct twl4030_madc_user_parms par
;
355 ret
= copy_from_user(&par
, (void __user
*) arg
, sizeof(par
));
357 printk(KERN_ERR TWL4030_MADC_PFX
"copy_from_user: %d\n", ret
);
362 case TWL4030_MADC_IOCX_ADC_RAW_READ
: {
363 struct twl4030_madc_request req
;
364 if (par
.channel
>= TWL4030_MADC_MAX_CHANNELS
)
367 req
.channels
= (1<<par
.channel
);
368 req
.do_avg
= par
.average
;
369 req
.method
= TWL4030_MADC_SW1
;
371 val
= twl4030_madc_conversion(&req
);
376 par
.result
= (u16
)req
.rbuf
[par
.channel
];
384 ret
= copy_to_user((void __user
*) arg
, &par
, sizeof(par
));
386 printk(KERN_ERR TWL4030_MADC_PFX
"copy_to_user: %d\n", ret
);
393 static struct file_operations twl4030_madc_fileops
= {
394 .owner
= THIS_MODULE
,
395 .ioctl
= twl4030_madc_ioctl
398 static struct miscdevice twl4030_madc_device
= {
399 .minor
= MISC_DYNAMIC_MINOR
,
400 .name
= "twl4030-adc",
401 .fops
= &twl4030_madc_fileops
404 static int __init
twl4030_madc_init(void)
409 ret
= misc_register(&twl4030_madc_device
);
411 printk(KERN_ERR TWL4030_MADC_PFX
"misc_register() failed!\n");
414 twl4030_madc_set_power(1);
415 twl4030_madc_set_current_generator(0, 1);
417 ret
= twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE
,
418 ®val
, TWL4030_BCI_BCICTL1
);
420 regval
|= TWL4030_BCI_MESBAT
;
422 ret
= twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE
,
423 regval
, TWL4030_BCI_BCICTL1
);
425 ret
= request_irq(TWL4030_MODIRQ_MADC
, twl4030_madc_irq_handler
,
426 IRQF_DISABLED
, "twl4030_madc", &twl4030_madc
);
428 printk(KERN_ERR TWL4030_MADC_PFX
"request_irq: %d\n", ret
);
430 mutex_init(&twl4030_madc
.lock
);
432 INIT_WORK(&twl4030_madc
.ws
, twl4030_madc_work
);
434 printk(KERN_INFO TWL4030_MADC_PFX
"initialised\n");
439 static void __exit
twl4030_madc_exit(void)
441 twl4030_madc_set_power(0);
442 twl4030_madc_set_current_generator(0, 0);
443 free_irq(TWL4030_MODIRQ_MADC
, &twl4030_madc
);
444 cancel_work_sync(&twl4030_madc
.ws
);
445 misc_deregister(&twl4030_madc_device
);
448 module_init(twl4030_madc_init
);
449 module_exit(twl4030_madc_exit
);
451 MODULE_AUTHOR("Nokia Corporation");
452 MODULE_DESCRIPTION("twl4030 ADC driver");
453 MODULE_LICENSE("GPL");