]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/i2c/chips/twl4030-madc.c
bff2554ed2fb965934a30f1092a0a393c5f45fbc
[linux-2.6-omap-h63xx.git] / drivers / i2c / chips / twl4030-madc.c
1 /*
2  * drivers/i2c/chips/twl4030-madc.c
3  *
4  * TWL4030 MADC module driver
5  *
6  * Copyright (C) 2008 Nokia Corporation
7  * Mikko Ylinen <mikko.k.ylinen@nokia.com>
8  *
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.
12  *
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.
17  *
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
21  * 02110-1301 USA
22  *
23  */
24
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>
31 #include <linux/fs.h>
32 #include <linux/platform_device.h>
33 #include <linux/miscdevice.h>
34 #include <linux/i2c/twl4030.h>
35 #include <linux/i2c/twl4030-madc.h>
36
37 #include <asm/uaccess.h>
38
39 #define TWL4030_MADC_PFX        "twl4030-madc: "
40
41 struct twl4030_madc_data {
42         struct device           *dev;
43         struct mutex            lock;
44         struct work_struct      ws;
45         struct twl4030_madc_request     requests[TWL4030_MADC_NUM_METHODS];
46         int imr;
47         int isr;
48 };
49
50 static struct twl4030_madc_data *the_madc;
51
52 static
53 const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
54         [TWL4030_MADC_RT] = {
55                 .sel    = TWL4030_MADC_RTSELECT_LSB,
56                 .avg    = TWL4030_MADC_RTAVERAGE_LSB,
57                 .rbase  = TWL4030_MADC_RTCH0_LSB,
58         },
59         [TWL4030_MADC_SW1] = {
60                 .sel    = TWL4030_MADC_SW1SELECT_LSB,
61                 .avg    = TWL4030_MADC_SW1AVERAGE_LSB,
62                 .rbase  = TWL4030_MADC_GPCH0_LSB,
63                 .ctrl   = TWL4030_MADC_CTRL_SW1,
64         },
65         [TWL4030_MADC_SW2] = {
66                 .sel    = TWL4030_MADC_SW2SELECT_LSB,
67                 .avg    = TWL4030_MADC_SW2AVERAGE_LSB,
68                 .rbase  = TWL4030_MADC_GPCH0_LSB,
69                 .ctrl   = TWL4030_MADC_CTRL_SW2,
70         },
71 };
72
73 static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
74 {
75         int ret;
76         u8 val;
77
78         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
79         if (ret) {
80                 dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
81                 return ret;
82         }
83
84         return val;
85 }
86
87 static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
88 {
89         int ret;
90
91         ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
92         if (ret)
93                 dev_err(madc->dev, "unable to write register 0x%X\n", reg);
94 }
95
96 static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
97 {
98         u8 msb, lsb;
99
100         /* For each ADC channel, we have MSB and LSB register pair. MSB address
101          * is always LSB address+1. reg parameter is the addr of LSB register */
102         msb = twl4030_madc_read(madc, reg + 1);
103         lsb = twl4030_madc_read(madc, reg);
104
105         return (int)(((msb << 8) | lsb) >> 6);
106 }
107
108 static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
109                 u8 reg_base, u16 channels, int *buf)
110 {
111         int count = 0;
112         u8 reg, i;
113
114         if (unlikely(!buf))
115                 return 0;
116
117         for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
118                 if (channels & (1<<i)) {
119                         reg = reg_base + 2*i;
120                         buf[i] = twl4030_madc_channel_raw_read(madc, reg);
121                         count++;
122                 }
123         }
124         return count;
125 }
126
127 static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
128 {
129         u8 val;
130
131         val = twl4030_madc_read(madc, madc->imr);
132         val &= ~(1 << id);
133         twl4030_madc_write(madc, madc->imr, val);
134 }
135
136 static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
137 {
138         u8 val;
139
140         val = twl4030_madc_read(madc, madc->imr);
141         val |= (1 << id);
142         twl4030_madc_write(madc, madc->imr, val);
143 }
144
145 static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
146 {
147         struct twl4030_madc_data *madc = _madc;
148         u8 isr_val, imr_val;
149         int i;
150
151         /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
152         isr_val = twl4030_madc_read(madc, madc->isr);
153         imr_val = twl4030_madc_read(madc, madc->imr);
154
155         isr_val &= ~imr_val;
156
157         for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
158
159                 if (!(isr_val & (1<<i)))
160                         continue;
161
162                 twl4030_madc_disable_irq(madc, i);
163                 madc->requests[i].result_pending = 1;
164         }
165
166         schedule_work(&madc->ws);
167
168         return IRQ_HANDLED;
169 }
170
171 static void twl4030_madc_work(struct work_struct *ws)
172 {
173         const struct twl4030_madc_conversion_method *method;
174         struct twl4030_madc_data *madc;
175         struct twl4030_madc_request *r;
176         int len, i;
177
178         madc = container_of(ws, struct twl4030_madc_data, ws);
179         mutex_lock(&madc->lock);
180
181         for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
182
183                 r = &madc->requests[i];
184
185                 /* No pending results for this method, move to next one */
186                 if (!r->result_pending)
187                         continue;
188
189                 method = &twl4030_conversion_methods[r->method];
190
191                 /* Read results */
192                 len = twl4030_madc_read_channels(madc, method->rbase,
193                                                  r->channels, r->rbuf);
194
195                 /* Return results to caller */
196                 if (r->func_cb != NULL) {
197                         r->func_cb(len, r->channels, r->rbuf);
198                         r->func_cb = NULL;
199                 }
200
201                 /* Free request */
202                 r->result_pending = 0;
203                 r->active         = 0;
204         }
205
206         mutex_unlock(&madc->lock);
207 }
208
209 static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
210                 struct twl4030_madc_request *req)
211 {
212         struct twl4030_madc_request *p;
213
214         p = &madc->requests[req->method];
215
216         memcpy(p, req, sizeof *req);
217
218         twl4030_madc_enable_irq(madc, req->method);
219
220         return 0;
221 }
222
223 static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
224                 int conv_method)
225 {
226         const struct twl4030_madc_conversion_method *method;
227
228         method = &twl4030_conversion_methods[conv_method];
229
230         switch (conv_method) {
231         case TWL4030_MADC_SW1:
232         case TWL4030_MADC_SW2:
233                 twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
234                 break;
235         case TWL4030_MADC_RT:
236         default:
237                 break;
238         }
239 }
240
241 static void twl4030_madc_wait_conversion_ready_ms(
242                 struct twl4030_madc_data *madc,
243                 u8 *time, u8 status_reg)
244 {
245         u8 reg = 0;
246
247         do {
248                 msleep(1);
249                 (*time)--;
250                 reg = twl4030_madc_read(madc, status_reg);
251         } while (((reg & TWL4030_MADC_BUSY) && !(reg & TWL4030_MADC_EOC_SW)) &&
252                   (*time != 0));
253 }
254
255 int twl4030_madc_conversion(struct twl4030_madc_request *req)
256 {
257         const struct twl4030_madc_conversion_method *method;
258         u8 wait_time, ch_msb, ch_lsb;
259         int ret;
260
261         if (unlikely(!req))
262                 return -EINVAL;
263
264         /* Do we have a conversion request ongoing */
265         if (the_madc->requests[req->method].active)
266                 return -EBUSY;
267
268         ch_msb = (req->channels >> 8) & 0xff;
269         ch_lsb = req->channels & 0xff;
270
271         method = &twl4030_conversion_methods[req->method];
272
273         mutex_lock(&the_madc->lock);
274
275         /* Select channels to be converted */
276         twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
277         twl4030_madc_write(the_madc, method->sel, ch_lsb);
278
279         /* Select averaging for all channels if do_avg is set */
280         if (req->do_avg) {
281                 twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
282                 twl4030_madc_write(the_madc, method->avg, ch_lsb);
283         }
284
285         if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
286                 twl4030_madc_set_irq(the_madc, req);
287                 twl4030_madc_start_conversion(the_madc, req->method);
288                 the_madc->requests[req->method].active = 1;
289                 ret = 0;
290                 goto out;
291         }
292
293         /* With RT method we should not be here anymore */
294         if (req->method == TWL4030_MADC_RT) {
295                 ret = -EINVAL;
296                 goto out;
297         }
298
299         twl4030_madc_start_conversion(the_madc, req->method);
300         the_madc->requests[req->method].active = 1;
301
302         /* Wait until conversion is ready (ctrl register returns EOC) */
303         wait_time = 50;
304         twl4030_madc_wait_conversion_ready_ms(the_madc,
305                         &wait_time, method->ctrl);
306         if (wait_time == 0) {
307                 dev_dbg(the_madc->dev, "conversion timeout!\n");
308                 ret = -EAGAIN;
309                 goto out;
310         }
311
312         ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
313                                          req->rbuf);
314
315         the_madc->requests[req->method].active = 0;
316
317 out:
318         mutex_unlock(&the_madc->lock);
319
320         return ret;
321 }
322 EXPORT_SYMBOL(twl4030_madc_conversion);
323
324 static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
325                 int chan, int on)
326 {
327         int ret;
328         u8 regval;
329
330         /* Current generator is only available for ADCIN0 and ADCIN1. NB:
331          * ADCIN1 current generator only works when AC or VBUS is present */
332         if (chan > 1)
333                 return EINVAL;
334
335         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
336                                   &regval, TWL4030_BCI_BCICTL1);
337         if (on)
338                 regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
339         else
340                 regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
341         ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
342                                    regval, TWL4030_BCI_BCICTL1);
343
344         return ret;
345 }
346
347 static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
348 {
349         u8 regval;
350
351         regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
352         if (on)
353                 regval |= TWL4030_MADC_MADCON;
354         else
355                 regval &= ~TWL4030_MADC_MADCON;
356         twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
357
358         return 0;
359 }
360
361 static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
362                               unsigned int cmd, unsigned long arg)
363 {
364         struct twl4030_madc_user_parms par;
365         int val, ret;
366
367         ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
368         if (ret) {
369                 dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
370                 return -EACCES;
371         }
372
373         switch (cmd) {
374         case TWL4030_MADC_IOCX_ADC_RAW_READ: {
375                 struct twl4030_madc_request req;
376                 if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
377                         return -EINVAL;
378
379                 req.channels = (1 << par.channel);
380                 req.do_avg      = par.average;
381                 req.method      = TWL4030_MADC_SW1;
382                 req.func_cb     = NULL;
383
384                 val = twl4030_madc_conversion(&req);
385                 if (val <= 0) {
386                         par.status = -1;
387                 } else {
388                         par.status = 0;
389                         par.result = (u16)req.rbuf[par.channel];
390                 }
391                 break;
392                                              }
393         default:
394                 return -EINVAL;
395         }
396
397         ret = copy_to_user((void __user *) arg, &par, sizeof(par));
398         if (ret) {
399                 dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
400                 return -EACCES;
401         }
402
403         return 0;
404 }
405
406 static struct file_operations twl4030_madc_fileops = {
407         .owner = THIS_MODULE,
408         .ioctl = twl4030_madc_ioctl
409 };
410
411 static struct miscdevice twl4030_madc_device = {
412         .minor = MISC_DYNAMIC_MINOR,
413         .name = "twl4030-madc",
414         .fops = &twl4030_madc_fileops
415 };
416
417 static int __init twl4030_madc_probe(struct platform_device *pdev)
418 {
419         struct twl4030_madc_data *madc;
420         struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
421         int ret;
422         u8 regval;
423
424         madc = kzalloc(sizeof *madc, GFP_KERNEL);
425         if (!madc)
426                 return -ENOMEM;
427
428         if (!pdata) {
429                 dev_dbg(&pdev->dev, "platform_data not available\n");
430                 ret = -EINVAL;
431                 goto err_pdata;
432         }
433
434         madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
435         madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
436
437         ret = misc_register(&twl4030_madc_device);
438         if (ret) {
439                 dev_dbg(&pdev->dev, "could not register misc_device\n");
440                 goto err_misc;
441         }
442         twl4030_madc_set_power(madc, 1);
443         twl4030_madc_set_current_generator(madc, 0, 1);
444
445         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
446                                   &regval, TWL4030_BCI_BCICTL1);
447
448         regval |= TWL4030_BCI_MESBAT;
449
450         ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
451                                    regval, TWL4030_BCI_BCICTL1);
452
453         ret = request_irq(TWL4030_MODIRQ_MADC, twl4030_madc_irq_handler,
454                           IRQF_DISABLED, "twl4030_madc", madc);
455         if (ret) {
456                 dev_dbg(&pdev->dev, "could not request irq\n");
457                 goto err_irq;
458         }
459
460         platform_set_drvdata(pdev, madc);
461         mutex_init(&madc->lock);
462         INIT_WORK(&madc->ws, twl4030_madc_work);
463
464         the_madc = madc;
465
466         return 0;
467
468 err_irq:
469         misc_deregister(&twl4030_madc_device);
470
471 err_misc:
472 err_pdata:
473         kfree(madc);
474
475         return ret;
476 }
477
478 static int __exit twl4030_madc_remove(struct platform_device *pdev)
479 {
480         struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
481
482         twl4030_madc_set_power(madc, 0);
483         twl4030_madc_set_current_generator(madc, 0, 0);
484         free_irq(TWL4030_MODIRQ_MADC, madc);
485         cancel_work_sync(&madc->ws);
486         misc_deregister(&twl4030_madc_device);
487
488         return 0;
489 }
490
491 static struct platform_driver twl4030_madc_driver = {
492         .probe          = twl4030_madc_probe,
493         .remove         = __exit_p(twl4030_madc_remove),
494         .driver         = {
495                 .name   = "twl4030_madc",
496                 .owner  = THIS_MODULE,
497         },
498 };
499
500 static int __init twl4030_madc_init(void)
501 {
502         return platform_driver_register(&twl4030_madc_driver);
503 }
504 module_init(twl4030_madc_init);
505
506 static void __exit twl4030_madc_exit(void)
507 {
508         platform_driver_unregister(&twl4030_madc_driver);
509 }
510 module_exit(twl4030_madc_exit);
511
512 MODULE_ALIAS("platform:twl4030-madc");
513 MODULE_AUTHOR("Nokia Corporation");
514 MODULE_DESCRIPTION("twl4030 ADC driver");
515 MODULE_LICENSE("GPL");
516