PRCM: OMAP3: Fix to wrongly modified omap2_clk_wait_ready
[linux-ginger.git] / drivers / i2c / chips / twl4030-madc.c
blobf53a3db7fa9e6219f20ea03b00c2583df5e2072c
1 /*
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
21 * 02110-1301 USA
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/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 {
41 struct mutex lock;
42 struct work_struct ws;
43 struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
44 } twl4030_madc;
46 static const char irq_pin = 1; /* XXX Read from platfrom data */
48 static
49 const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
50 [TWL4030_MADC_RT] = {
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);
72 if (ret)
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);
80 if (ret)
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)
87 u8 msb, lsb;
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)
99 int count = 0;
100 u8 reg, i;
102 if (unlikely(!buf))
103 return 0;
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);
109 count++;
112 return count;
115 static void twl4030_madc_enable_irq(int id)
117 u8 val;
119 static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
121 twl4030_madc_read(imr, &val);
122 val &= ~(1 << id);
123 twl4030_madc_write(imr, val);
126 static void twl4030_madc_disable_irq(int id)
128 u8 val;
130 static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
132 twl4030_madc_read(imr, &val);
133 val |= (1 << id);
134 twl4030_madc_write(imr, val);
137 static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev)
139 u8 isr_val, imr_val;
140 static u8 isr, imr;
141 int i;
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);
150 isr_val &= ~imr_val;
152 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
154 if (!(isr_val & (1<<i)))
155 continue;
157 twl4030_madc_disable_irq(i);
158 twl4030_madc.requests[i].result_pending = 1;
161 schedule_work(&twl4030_madc.ws);
163 return IRQ_HANDLED;
166 static void twl4030_madc_work(struct work_struct *ws)
168 const struct twl4030_madc_conversion_method *method;
169 struct twl4030_madc_request *r;
170 int len, i;
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)
180 continue;
182 method = &twl4030_conversion_methods[r->method];
184 /* Read results */
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);
191 r->func_cb = NULL;
194 /* Free request */
195 r->result_pending = 0;
196 r->active = 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);
212 return 0;
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);
225 break;
226 case TWL4030_MADC_RT:
227 default:
228 break;
232 static void twl4030_madc_wait_conversion_ready_ms(u8 *time, u8 status_reg)
234 u8 reg = 0;
236 do {
237 msleep(1);
238 (*time)--;
239 twl4030_madc_read(status_reg, &reg);
240 } while (((reg & TWL4030_MADC_BUSY) && !(reg & TWL4030_MADC_EOC_SW)) &&
241 (*time != 0));
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;
248 int ret;
250 if (unlikely(!req))
251 return -EINVAL;
253 /* Do we have a conversion request ongoing */
254 if (twl4030_madc.requests[req->method].active)
255 return -EBUSY;
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 */
269 if (req->do_avg) {
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;
278 ret = 0;
279 goto out;
282 /* With RT method we should not be here anymore */
283 if (req->method == TWL4030_MADC_RT) {
284 ret = -EINVAL;
285 goto out;
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) */
292 wait_time = 50;
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");
296 ret = -EAGAIN;
297 goto out;
300 ret = twl4030_madc_read_channels(method->rbase, req->channels,
301 req->rbuf);
303 twl4030_madc.requests[req->method].active = 0;
305 out:
306 mutex_unlock(&twl4030_madc.lock);
308 return ret;
311 EXPORT_SYMBOL(twl4030_madc_conversion);
313 static int twl4030_madc_set_current_generator(int chan, int on)
315 int ret;
316 u8 regval;
318 /* Current generator is only available for ADCIN0 and ADCIN1. NB:
319 * ADCIN1 current generator only works when AC or VBUS is present */
320 if (chan > 1)
321 return EINVAL;
323 ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
324 &regval, TWL4030_BCI_BCICTL1);
325 if (on)
326 regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
327 else
328 regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
329 ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
330 regval, TWL4030_BCI_BCICTL1);
332 return ret;
335 static int twl4030_madc_set_power(int on)
337 u8 regval;
339 twl4030_madc_read(TWL4030_MADC_CTRL1, &regval);
340 if (on)
341 regval |= TWL4030_MADC_MADCON;
342 else
343 regval &= ~TWL4030_MADC_MADCON;
344 twl4030_madc_write(TWL4030_MADC_CTRL1, regval);
346 return 0;
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;
353 int val, ret;
355 ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
356 if (ret) {
357 printk(KERN_ERR TWL4030_MADC_PFX "copy_from_user: %d\n", ret);
358 return -EACCES;
361 switch (cmd) {
362 case TWL4030_MADC_IOCX_ADC_RAW_READ: {
363 struct twl4030_madc_request req;
364 if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
365 return -EINVAL;
367 req.channels = (1<<par.channel);
368 req.do_avg = par.average;
369 req.method = TWL4030_MADC_SW1;
371 val = twl4030_madc_conversion(&req);
372 if (val <= 0) {
373 par.status = -1;
374 } else {
375 par.status = 0;
376 par.result = (u16)req.rbuf[par.channel];
378 break;
380 default:
381 return -EINVAL;
384 ret = copy_to_user((void __user *) arg, &par, sizeof(par));
385 if (ret) {
386 printk(KERN_ERR TWL4030_MADC_PFX "copy_to_user: %d\n", ret);
387 return -EACCES;
390 return 0;
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)
406 int ret;
407 u8 regval;
409 ret = misc_register(&twl4030_madc_device);
410 if (ret == -1) {
411 printk(KERN_ERR TWL4030_MADC_PFX "misc_register() failed!\n");
412 return ret;
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 &regval, 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);
427 if (ret)
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");
436 return ret;
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");