]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/i2c/chips/twl4030-madc.c
d3e0a7fd7ef308ca73d10901080764d6e079b961
[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 #ifdef CONFIG_LOCKDEP
152         /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
153          * we don't want and can't tolerate.  Although it might be
154          * friendlier not to borrow this thread context...
155          */
156         local_irq_enable();
157 #endif
158
159         /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
160         isr_val = twl4030_madc_read(madc, madc->isr);
161         imr_val = twl4030_madc_read(madc, madc->imr);
162
163         isr_val &= ~imr_val;
164
165         for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
166
167                 if (!(isr_val & (1<<i)))
168                         continue;
169
170                 twl4030_madc_disable_irq(madc, i);
171                 madc->requests[i].result_pending = 1;
172         }
173
174         schedule_work(&madc->ws);
175
176         return IRQ_HANDLED;
177 }
178
179 static void twl4030_madc_work(struct work_struct *ws)
180 {
181         const struct twl4030_madc_conversion_method *method;
182         struct twl4030_madc_data *madc;
183         struct twl4030_madc_request *r;
184         int len, i;
185
186         madc = container_of(ws, struct twl4030_madc_data, ws);
187         mutex_lock(&madc->lock);
188
189         for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
190
191                 r = &madc->requests[i];
192
193                 /* No pending results for this method, move to next one */
194                 if (!r->result_pending)
195                         continue;
196
197                 method = &twl4030_conversion_methods[r->method];
198
199                 /* Read results */
200                 len = twl4030_madc_read_channels(madc, method->rbase,
201                                                  r->channels, r->rbuf);
202
203                 /* Return results to caller */
204                 if (r->func_cb != NULL) {
205                         r->func_cb(len, r->channels, r->rbuf);
206                         r->func_cb = NULL;
207                 }
208
209                 /* Free request */
210                 r->result_pending = 0;
211                 r->active         = 0;
212         }
213
214         mutex_unlock(&madc->lock);
215 }
216
217 static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
218                 struct twl4030_madc_request *req)
219 {
220         struct twl4030_madc_request *p;
221
222         p = &madc->requests[req->method];
223
224         memcpy(p, req, sizeof *req);
225
226         twl4030_madc_enable_irq(madc, req->method);
227
228         return 0;
229 }
230
231 static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
232                 int conv_method)
233 {
234         const struct twl4030_madc_conversion_method *method;
235
236         method = &twl4030_conversion_methods[conv_method];
237
238         switch (conv_method) {
239         case TWL4030_MADC_SW1:
240         case TWL4030_MADC_SW2:
241                 twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
242                 break;
243         case TWL4030_MADC_RT:
244         default:
245                 break;
246         }
247 }
248
249 static int twl4030_madc_wait_conversion_ready(
250                 struct twl4030_madc_data *madc,
251                 unsigned int timeout_ms, u8 status_reg)
252 {
253         unsigned long timeout;
254
255         timeout = jiffies + msecs_to_jiffies(timeout_ms);
256         do {
257                 u8 reg;
258
259                 reg = twl4030_madc_read(madc, status_reg);
260                 if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
261                         return 0;
262         } while (!time_after(jiffies, timeout));
263
264         return -EAGAIN;
265 }
266
267 int twl4030_madc_conversion(struct twl4030_madc_request *req)
268 {
269         const struct twl4030_madc_conversion_method *method;
270         u8 ch_msb, ch_lsb;
271         int ret;
272
273         if (unlikely(!req))
274                 return -EINVAL;
275
276         mutex_lock(&the_madc->lock);
277
278         /* Do we have a conversion request ongoing */
279         if (the_madc->requests[req->method].active) {
280                 ret = -EBUSY;
281                 goto out;
282         }
283
284         ch_msb = (req->channels >> 8) & 0xff;
285         ch_lsb = req->channels & 0xff;
286
287         method = &twl4030_conversion_methods[req->method];
288
289         /* Select channels to be converted */
290         twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
291         twl4030_madc_write(the_madc, method->sel, ch_lsb);
292
293         /* Select averaging for all channels if do_avg is set */
294         if (req->do_avg) {
295                 twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
296                 twl4030_madc_write(the_madc, method->avg, ch_lsb);
297         }
298
299         if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
300                 twl4030_madc_set_irq(the_madc, req);
301                 twl4030_madc_start_conversion(the_madc, req->method);
302                 the_madc->requests[req->method].active = 1;
303                 ret = 0;
304                 goto out;
305         }
306
307         /* With RT method we should not be here anymore */
308         if (req->method == TWL4030_MADC_RT) {
309                 ret = -EINVAL;
310                 goto out;
311         }
312
313         twl4030_madc_start_conversion(the_madc, req->method);
314         the_madc->requests[req->method].active = 1;
315
316         /* Wait until conversion is ready (ctrl register returns EOC) */
317         ret = twl4030_madc_wait_conversion_ready(the_madc, 5, method->ctrl);
318         if (ret) {
319                 dev_dbg(the_madc->dev, "conversion timeout!\n");
320                 the_madc->requests[req->method].active = 0;
321                 goto out;
322         }
323
324         ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
325                                          req->rbuf);
326
327         the_madc->requests[req->method].active = 0;
328
329 out:
330         mutex_unlock(&the_madc->lock);
331
332         return ret;
333 }
334 EXPORT_SYMBOL(twl4030_madc_conversion);
335
336 static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
337                 int chan, int on)
338 {
339         int ret;
340         u8 regval;
341
342         /* Current generator is only available for ADCIN0 and ADCIN1. NB:
343          * ADCIN1 current generator only works when AC or VBUS is present */
344         if (chan > 1)
345                 return EINVAL;
346
347         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
348                                   &regval, TWL4030_BCI_BCICTL1);
349         if (on)
350                 regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
351         else
352                 regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
353         ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
354                                    regval, TWL4030_BCI_BCICTL1);
355
356         return ret;
357 }
358
359 static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
360 {
361         u8 regval;
362
363         regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
364         if (on)
365                 regval |= TWL4030_MADC_MADCON;
366         else
367                 regval &= ~TWL4030_MADC_MADCON;
368         twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
369
370         return 0;
371 }
372
373 static long twl4030_madc_ioctl(struct file *filp, unsigned int cmd,
374                                unsigned long arg)
375 {
376         struct twl4030_madc_user_parms par;
377         int val, ret;
378
379         ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
380         if (ret) {
381                 dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
382                 return -EACCES;
383         }
384
385         switch (cmd) {
386         case TWL4030_MADC_IOCX_ADC_RAW_READ: {
387                 struct twl4030_madc_request req;
388                 if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
389                         return -EINVAL;
390
391                 req.channels = (1 << par.channel);
392                 req.do_avg      = par.average;
393                 req.method      = TWL4030_MADC_SW1;
394                 req.func_cb     = NULL;
395
396                 val = twl4030_madc_conversion(&req);
397                 if (val <= 0) {
398                         par.status = -1;
399                 } else {
400                         par.status = 0;
401                         par.result = (u16)req.rbuf[par.channel];
402                 }
403                 break;
404                                              }
405         default:
406                 return -EINVAL;
407         }
408
409         ret = copy_to_user((void __user *) arg, &par, sizeof(par));
410         if (ret) {
411                 dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
412                 return -EACCES;
413         }
414
415         return 0;
416 }
417
418 static struct file_operations twl4030_madc_fileops = {
419         .owner = THIS_MODULE,
420         .unlocked_ioctl = twl4030_madc_ioctl
421 };
422
423 static struct miscdevice twl4030_madc_device = {
424         .minor = MISC_DYNAMIC_MINOR,
425         .name = "twl4030-madc",
426         .fops = &twl4030_madc_fileops
427 };
428
429 static int __init twl4030_madc_probe(struct platform_device *pdev)
430 {
431         struct twl4030_madc_data *madc;
432         struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
433         int ret;
434         u8 regval;
435
436         madc = kzalloc(sizeof *madc, GFP_KERNEL);
437         if (!madc)
438                 return -ENOMEM;
439
440         if (!pdata) {
441                 dev_dbg(&pdev->dev, "platform_data not available\n");
442                 ret = -EINVAL;
443                 goto err_pdata;
444         }
445
446         madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
447         madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
448
449         ret = misc_register(&twl4030_madc_device);
450         if (ret) {
451                 dev_dbg(&pdev->dev, "could not register misc_device\n");
452                 goto err_misc;
453         }
454         twl4030_madc_set_power(madc, 1);
455         twl4030_madc_set_current_generator(madc, 0, 1);
456
457         ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
458                                   &regval, TWL4030_BCI_BCICTL1);
459
460         regval |= TWL4030_BCI_MESBAT;
461
462         ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
463                                    regval, TWL4030_BCI_BCICTL1);
464
465         ret = request_irq(platform_get_irq(pdev, 0), twl4030_madc_irq_handler,
466                           0, "twl4030_madc", madc);
467         if (ret) {
468                 dev_dbg(&pdev->dev, "could not request irq\n");
469                 goto err_irq;
470         }
471
472         platform_set_drvdata(pdev, madc);
473         mutex_init(&madc->lock);
474         INIT_WORK(&madc->ws, twl4030_madc_work);
475
476         the_madc = madc;
477
478         return 0;
479
480 err_irq:
481         misc_deregister(&twl4030_madc_device);
482
483 err_misc:
484 err_pdata:
485         kfree(madc);
486
487         return ret;
488 }
489
490 static int __exit twl4030_madc_remove(struct platform_device *pdev)
491 {
492         struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
493
494         twl4030_madc_set_power(madc, 0);
495         twl4030_madc_set_current_generator(madc, 0, 0);
496         free_irq(platform_get_irq(pdev, 0), madc);
497         cancel_work_sync(&madc->ws);
498         misc_deregister(&twl4030_madc_device);
499
500         return 0;
501 }
502
503 static struct platform_driver twl4030_madc_driver = {
504         .probe          = twl4030_madc_probe,
505         .remove         = __exit_p(twl4030_madc_remove),
506         .driver         = {
507                 .name   = "twl4030_madc",
508                 .owner  = THIS_MODULE,
509         },
510 };
511
512 static int __init twl4030_madc_init(void)
513 {
514         return platform_driver_register(&twl4030_madc_driver);
515 }
516 module_init(twl4030_madc_init);
517
518 static void __exit twl4030_madc_exit(void)
519 {
520         platform_driver_unregister(&twl4030_madc_driver);
521 }
522 module_exit(twl4030_madc_exit);
523
524 MODULE_ALIAS("platform:twl4030-madc");
525 MODULE_AUTHOR("Nokia Corporation");
526 MODULE_DESCRIPTION("twl4030 ADC driver");
527 MODULE_LICENSE("GPL");
528