blob: 456ecb5ac4fe52e1a5515f1793eda270c5407056 [file] [log] [blame]
Keerthyf99c1d42011-03-01 19:12:26 +05301/*
2 *
3 * TWL4030 MADC module driver-This driver monitors the real time
4 * conversion of analog signals like battery temperature,
5 * battery type, battery level etc.
6 *
7 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
8 * J Keerthy <j-keerthy@ti.com>
9 *
10 * Based on twl4030-madc.c
11 * Copyright (C) 2008 Nokia Corporation
12 * Mikko Ylinen <mikko.k.ylinen@nokia.com>
13 *
14 * Amit Kucheria <amit.kucheria@canonical.com>
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * version 2 as published by the Free Software Foundation.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 * 02110-1301 USA
29 *
30 */
31
32#include <linux/init.h>
33#include <linux/device.h>
34#include <linux/interrupt.h>
35#include <linux/kernel.h>
36#include <linux/delay.h>
37#include <linux/platform_device.h>
38#include <linux/slab.h>
39#include <linux/i2c/twl.h>
40#include <linux/i2c/twl4030-madc.h>
41#include <linux/module.h>
42#include <linux/stddef.h>
43#include <linux/mutex.h>
44#include <linux/bitops.h>
45#include <linux/jiffies.h>
46#include <linux/types.h>
47#include <linux/gfp.h>
48#include <linux/err.h>
49
50/*
51 * struct twl4030_madc_data - a container for madc info
52 * @dev - pointer to device structure for madc
53 * @lock - mutex protecting this data structure
54 * @requests - Array of request struct corresponding to SW1, SW2 and RT
55 * @imr - Interrupt mask register of MADC
56 * @isr - Interrupt status register of MADC
57 */
58struct twl4030_madc_data {
59 struct device *dev;
60 struct mutex lock; /* mutex protecting this data structure */
61 struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
62 int imr;
63 int isr;
64};
65
66static struct twl4030_madc_data *twl4030_madc;
67
68struct twl4030_prescale_divider_ratios {
69 s16 numerator;
70 s16 denominator;
71};
72
73static const struct twl4030_prescale_divider_ratios
74twl4030_divider_ratios[16] = {
75 {1, 1}, /* CHANNEL 0 No Prescaler */
76 {1, 1}, /* CHANNEL 1 No Prescaler */
77 {6, 10}, /* CHANNEL 2 */
78 {6, 10}, /* CHANNEL 3 */
79 {6, 10}, /* CHANNEL 4 */
80 {6, 10}, /* CHANNEL 5 */
81 {6, 10}, /* CHANNEL 6 */
82 {6, 10}, /* CHANNEL 7 */
83 {3, 14}, /* CHANNEL 8 */
84 {1, 3}, /* CHANNEL 9 */
85 {1, 1}, /* CHANNEL 10 No Prescaler */
86 {15, 100}, /* CHANNEL 11 */
87 {1, 4}, /* CHANNEL 12 */
88 {1, 1}, /* CHANNEL 13 Reserved channels */
89 {1, 1}, /* CHANNEL 14 Reseved channels */
90 {5, 11}, /* CHANNEL 15 */
91};
92
93
94/*
95 * Conversion table from -3 to 55 degree Celcius
96 */
97static int therm_tbl[] = {
9830800, 29500, 28300, 27100,
9926000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
10017200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
10111600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
1028020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
1035640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
1044040, 3910, 3790, 3670, 3550
105};
106
107/*
108 * Structure containing the registers
109 * of different conversion methods supported by MADC.
110 * Hardware or RT real time conversion request initiated by external host
111 * processor for RT Signal conversions.
112 * External host processors can also request for non RT conversions
113 * SW1 and SW2 software conversions also called asynchronous or GPC request.
114 */
115static
116const 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/*
137 * Function to read a particular channel value.
138 * @madc - pointer to struct twl4030_madc_data
139 * @reg - lsb of ADC Channel
140 * If the i2c read fails it returns an error else returns 0.
141 */
142static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
143{
144 u8 msb, lsb;
145 int ret;
146 /*
147 * For each ADC channel, we have MSB and LSB register pair. MSB address
148 * is always LSB address+1. reg parameter is the address of LSB register
149 */
150 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1);
151 if (ret) {
152 dev_err(madc->dev, "unable to read MSB register 0x%X\n",
153 reg + 1);
154 return ret;
155 }
156 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg);
157 if (ret) {
158 dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg);
159 return ret;
160 }
161
162 return (int)(((msb << 8) | lsb) >> 6);
163}
164
165/*
166 * Return battery temperature
167 * Or < 0 on failure.
168 */
169static int twl4030battery_temperature(int raw_volt)
170{
171 u8 val;
172 int temp, curr, volt, res, ret;
173
174 volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
175 /* Getting and calculating the supply current in micro ampers */
176 ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
177 REG_BCICTL2);
178 if (ret < 0)
179 return ret;
180 curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
181 /* Getting and calculating the thermistor resistance in ohms */
182 res = volt * 1000 / curr;
183 /* calculating temperature */
184 for (temp = 58; temp >= 0; temp--) {
185 int actual = therm_tbl[temp];
186
187 if ((actual - res) >= 0)
188 break;
189 }
190
191 return temp + 1;
192}
193
194static int twl4030battery_current(int raw_volt)
195{
196 int ret;
197 u8 val;
198
199 ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
200 TWL4030_BCI_BCICTL1);
201 if (ret)
202 return ret;
203 if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
204 return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
205 else /* slope of 0.88 mV/mA */
206 return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
207}
208/*
209 * Function to read channel values
210 * @madc - pointer to twl4030_madc_data struct
211 * @reg_base - Base address of the first channel
212 * @Channels - 16 bit bitmap. If the bit is set, channel value is read
213 * @buf - The channel values are stored here. if read fails error
214 * value is stored
215 * Returns the number of successfully read channels.
216 */
217static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
218 u8 reg_base, unsigned
219 long channels, int *buf)
220{
221 int count = 0, count_req = 0, i;
222 u8 reg;
223
224 for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
225 reg = reg_base + 2 * i;
226 buf[i] = twl4030_madc_channel_raw_read(madc, reg);
227 if (buf[i] < 0) {
228 dev_err(madc->dev,
229 "Unable to read register 0x%X\n", reg);
230 count_req++;
231 continue;
232 }
233 switch (i) {
234 case 10:
235 buf[i] = twl4030battery_current(buf[i]);
236 if (buf[i] < 0) {
237 dev_err(madc->dev, "err reading current\n");
238 count_req++;
239 } else {
240 count++;
241 buf[i] = buf[i] - 750;
242 }
243 break;
244 case 1:
245 buf[i] = twl4030battery_temperature(buf[i]);
246 if (buf[i] < 0) {
247 dev_err(madc->dev, "err reading temperature\n");
248 count_req++;
249 } else {
250 buf[i] -= 3;
251 count++;
252 }
253 break;
254 default:
255 count++;
256 /* Analog Input (V) = conv_result * step_size / R
257 * conv_result = decimal value of 10-bit conversion
258 * result
259 * step size = 1.5 / (2 ^ 10 -1)
260 * R = Prescaler ratio for input channels.
261 * Result given in mV hence multiplied by 1000.
262 */
263 buf[i] = (buf[i] * 3 * 1000 *
264 twl4030_divider_ratios[i].denominator)
265 / (2 * 1023 *
266 twl4030_divider_ratios[i].numerator);
267 }
268 }
269 if (count_req)
270 dev_err(madc->dev, "%d channel conversion failed\n", count_req);
271
272 return count;
273}
274
275/*
276 * Enables irq.
277 * @madc - pointer to twl4030_madc_data struct
278 * @id - irq number to be enabled
279 * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
280 * corresponding to RT, SW1, SW2 conversion requests.
281 * If the i2c read fails it returns an error else returns 0.
282 */
283static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
284{
285 u8 val;
286 int ret;
287
288 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
289 if (ret) {
290 dev_err(madc->dev, "unable to read imr register 0x%X\n",
291 madc->imr);
292 return ret;
293 }
294 val &= ~(1 << id);
295 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
296 if (ret) {
297 dev_err(madc->dev,
298 "unable to write imr register 0x%X\n", madc->imr);
299 return ret;
300
301 }
302
303 return 0;
304}
305
306/*
307 * Disables irq.
308 * @madc - pointer to twl4030_madc_data struct
309 * @id - irq number to be disabled
310 * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
311 * corresponding to RT, SW1, SW2 conversion requests.
312 * Returns error if i2c read/write fails.
313 */
314static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
315{
316 u8 val;
317 int ret;
318
319 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
320 if (ret) {
321 dev_err(madc->dev, "unable to read imr register 0x%X\n",
322 madc->imr);
323 return ret;
324 }
325 val |= (1 << id);
326 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
327 if (ret) {
328 dev_err(madc->dev,
329 "unable to write imr register 0x%X\n", madc->imr);
330 return ret;
331 }
332
333 return 0;
334}
335
336static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
337{
338 struct twl4030_madc_data *madc = _madc;
339 const struct twl4030_madc_conversion_method *method;
340 u8 isr_val, imr_val;
341 int i, len, ret;
342 struct twl4030_madc_request *r;
343
344 mutex_lock(&madc->lock);
345 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
346 if (ret) {
347 dev_err(madc->dev, "unable to read isr register 0x%X\n",
348 madc->isr);
349 goto err_i2c;
350 }
351 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
352 if (ret) {
353 dev_err(madc->dev, "unable to read imr register 0x%X\n",
354 madc->imr);
355 goto err_i2c;
356 }
357 isr_val &= ~imr_val;
358 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
359 if (!(isr_val & (1 << i)))
360 continue;
361 ret = twl4030_madc_disable_irq(madc, i);
362 if (ret < 0)
363 dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
364 madc->requests[i].result_pending = 1;
365 }
366 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
367 r = &madc->requests[i];
368 /* No pending results for this method, move to next one */
369 if (!r->result_pending)
370 continue;
371 method = &twl4030_conversion_methods[r->method];
372 /* Read results */
373 len = twl4030_madc_read_channels(madc, method->rbase,
374 r->channels, r->rbuf);
375 /* Return results to caller */
376 if (r->func_cb != NULL) {
377 r->func_cb(len, r->channels, r->rbuf);
378 r->func_cb = NULL;
379 }
380 /* Free request */
381 r->result_pending = 0;
382 r->active = 0;
383 }
384 mutex_unlock(&madc->lock);
385
386 return IRQ_HANDLED;
387
388err_i2c:
389 /*
390 * In case of error check whichever request is active
391 * and service the same.
392 */
393 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
394 r = &madc->requests[i];
395 if (r->active == 0)
396 continue;
397 method = &twl4030_conversion_methods[r->method];
398 /* Read results */
399 len = twl4030_madc_read_channels(madc, method->rbase,
400 r->channels, r->rbuf);
401 /* Return results to caller */
402 if (r->func_cb != NULL) {
403 r->func_cb(len, r->channels, r->rbuf);
404 r->func_cb = NULL;
405 }
406 /* Free request */
407 r->result_pending = 0;
408 r->active = 0;
409 }
410 mutex_unlock(&madc->lock);
411
412 return IRQ_HANDLED;
413}
414
415static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
416 struct twl4030_madc_request *req)
417{
418 struct twl4030_madc_request *p;
419 int ret;
420
421 p = &madc->requests[req->method];
422 memcpy(p, req, sizeof(*req));
423 ret = twl4030_madc_enable_irq(madc, req->method);
424 if (ret < 0) {
425 dev_err(madc->dev, "enable irq failed!!\n");
426 return ret;
427 }
428
429 return 0;
430}
431
432/*
433 * Function which enables the madc conversion
434 * by writing to the control register.
435 * @madc - pointer to twl4030_madc_data struct
436 * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
437 * corresponding to RT SW1 or SW2 conversion methods.
438 * Returns 0 if succeeds else a negative error value
439 */
440static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
441 int conv_method)
442{
443 const struct twl4030_madc_conversion_method *method;
444 int ret = 0;
445 method = &twl4030_conversion_methods[conv_method];
446 switch (conv_method) {
447 case TWL4030_MADC_SW1:
448 case TWL4030_MADC_SW2:
449 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
450 TWL4030_MADC_SW_START, method->ctrl);
451 if (ret) {
452 dev_err(madc->dev,
453 "unable to write ctrl register 0x%X\n",
454 method->ctrl);
455 return ret;
456 }
457 break;
458 default:
459 break;
460 }
461
462 return 0;
463}
464
465/*
466 * Function that waits for conversion to be ready
467 * @madc - pointer to twl4030_madc_data struct
468 * @timeout_ms - timeout value in milliseconds
469 * @status_reg - ctrl register
470 * returns 0 if succeeds else a negative error value
471 */
472static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
473 unsigned int timeout_ms,
474 u8 status_reg)
475{
476 unsigned long timeout;
477 int ret;
478
479 timeout = jiffies + msecs_to_jiffies(timeout_ms);
480 do {
481 u8 reg;
482
483 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
484 if (ret) {
485 dev_err(madc->dev,
486 "unable to read status register 0x%X\n",
487 status_reg);
488 return ret;
489 }
490 if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
491 return 0;
492 usleep_range(500, 2000);
493 } while (!time_after(jiffies, timeout));
494 dev_err(madc->dev, "conversion timeout!\n");
495
496 return -EAGAIN;
497}
498
499/*
500 * An exported function which can be called from other kernel drivers.
501 * @req twl4030_madc_request structure
502 * req->rbuf will be filled with read values of channels based on the
503 * channel index. If a particular channel reading fails there will
504 * be a negative error value in the corresponding array element.
505 * returns 0 if succeeds else error value
506 */
507int twl4030_madc_conversion(struct twl4030_madc_request *req)
508{
509 const struct twl4030_madc_conversion_method *method;
510 u8 ch_msb, ch_lsb;
511 int ret;
512
Kyle Mannad0e84ca2011-08-11 22:33:14 -0500513 if (!req || !twl4030_madc)
Keerthyf99c1d42011-03-01 19:12:26 +0530514 return -EINVAL;
Kyle Mannad0e84ca2011-08-11 22:33:14 -0500515
Keerthyf99c1d42011-03-01 19:12:26 +0530516 mutex_lock(&twl4030_madc->lock);
517 if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
518 ret = -EINVAL;
519 goto out;
520 }
521 /* Do we have a conversion request ongoing */
522 if (twl4030_madc->requests[req->method].active) {
523 ret = -EBUSY;
524 goto out;
525 }
526 ch_msb = (req->channels >> 8) & 0xff;
527 ch_lsb = req->channels & 0xff;
528 method = &twl4030_conversion_methods[req->method];
529 /* Select channels to be converted */
530 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1);
531 if (ret) {
532 dev_err(twl4030_madc->dev,
533 "unable to write sel register 0x%X\n", method->sel + 1);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530534 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530535 }
536 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
537 if (ret) {
538 dev_err(twl4030_madc->dev,
539 "unable to write sel register 0x%X\n", method->sel + 1);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530540 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530541 }
542 /* Select averaging for all channels if do_avg is set */
543 if (req->do_avg) {
544 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
545 ch_msb, method->avg + 1);
546 if (ret) {
547 dev_err(twl4030_madc->dev,
548 "unable to write avg register 0x%X\n",
549 method->avg + 1);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530550 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530551 }
552 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
553 ch_lsb, method->avg);
554 if (ret) {
555 dev_err(twl4030_madc->dev,
556 "unable to write sel reg 0x%X\n",
557 method->sel + 1);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530558 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530559 }
560 }
561 if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
562 ret = twl4030_madc_set_irq(twl4030_madc, req);
563 if (ret < 0)
564 goto out;
565 ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
566 if (ret < 0)
567 goto out;
568 twl4030_madc->requests[req->method].active = 1;
569 ret = 0;
570 goto out;
571 }
572 /* With RT method we should not be here anymore */
573 if (req->method == TWL4030_MADC_RT) {
574 ret = -EINVAL;
575 goto out;
576 }
577 ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
578 if (ret < 0)
579 goto out;
580 twl4030_madc->requests[req->method].active = 1;
581 /* Wait until conversion is ready (ctrl register returns EOC) */
582 ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
583 if (ret) {
584 twl4030_madc->requests[req->method].active = 0;
585 goto out;
586 }
587 ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
588 req->channels, req->rbuf);
589 twl4030_madc->requests[req->method].active = 0;
590
591out:
592 mutex_unlock(&twl4030_madc->lock);
593
594 return ret;
595}
596EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
597
598/*
599 * Return channel value
600 * Or < 0 on failure.
601 */
602int twl4030_get_madc_conversion(int channel_no)
603{
604 struct twl4030_madc_request req;
605 int temp = 0;
606 int ret;
607
608 req.channels = (1 << channel_no);
609 req.method = TWL4030_MADC_SW2;
610 req.active = 0;
611 req.func_cb = NULL;
612 ret = twl4030_madc_conversion(&req);
613 if (ret < 0)
614 return ret;
615 if (req.rbuf[channel_no] > 0)
616 temp = req.rbuf[channel_no];
617
618 return temp;
619}
620EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
621
622/*
623 * Function to enable or disable bias current for
624 * main battery type reading or temperature sensing
625 * @madc - pointer to twl4030_madc_data struct
626 * @chan - can be one of the two values
627 * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
628 * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
629 * sensing
630 * @on - enable or disable chan.
631 */
632static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
633 int chan, int on)
634{
635 int ret;
636 u8 regval;
637
638 ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
639 &regval, TWL4030_BCI_BCICTL1);
640 if (ret) {
641 dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
642 TWL4030_BCI_BCICTL1);
643 return ret;
644 }
645 if (on)
646 regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
647 else
648 regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
649 ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
650 regval, TWL4030_BCI_BCICTL1);
651 if (ret) {
652 dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
653 TWL4030_BCI_BCICTL1);
654 return ret;
655 }
656
657 return 0;
658}
659
660/*
661 * Function that sets MADC software power on bit to enable MADC
662 * @madc - pointer to twl4030_madc_data struct
663 * @on - Enable or disable MADC software powen on bit.
664 * returns error if i2c read/write fails else 0
665 */
666static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
667{
668 u8 regval;
669 int ret;
670
671 ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
672 &regval, TWL4030_MADC_CTRL1);
673 if (ret) {
674 dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
675 TWL4030_MADC_CTRL1);
676 return ret;
677 }
678 if (on)
679 regval |= TWL4030_MADC_MADCON;
680 else
681 regval &= ~TWL4030_MADC_MADCON;
682 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
683 if (ret) {
684 dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
685 TWL4030_MADC_CTRL1);
686 return ret;
687 }
688
689 return 0;
690}
691
692/*
693 * Initialize MADC and request for threaded irq
694 */
695static int __devinit twl4030_madc_probe(struct platform_device *pdev)
696{
697 struct twl4030_madc_data *madc;
698 struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
699 int ret;
700 u8 regval;
701
702 if (!pdata) {
703 dev_err(&pdev->dev, "platform_data not available\n");
704 return -EINVAL;
705 }
706 madc = kzalloc(sizeof(*madc), GFP_KERNEL);
707 if (!madc)
708 return -ENOMEM;
709
Kyle Manna66cc5b82011-08-11 22:33:12 -0500710 madc->dev = &pdev->dev;
711
Keerthyf99c1d42011-03-01 19:12:26 +0530712 /*
713 * Phoenix provides 2 interrupt lines. The first one is connected to
714 * the OMAP. The other one can be connected to the other processor such
715 * as modem. Hence two separate ISR and IMR registers.
716 */
717 madc->imr = (pdata->irq_line == 1) ?
718 TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
719 madc->isr = (pdata->irq_line == 1) ?
720 TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
721 ret = twl4030_madc_set_power(madc, 1);
722 if (ret < 0)
723 goto err_power;
724 ret = twl4030_madc_set_current_generator(madc, 0, 1);
725 if (ret < 0)
726 goto err_current_generator;
727
728 ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
729 &regval, TWL4030_BCI_BCICTL1);
730 if (ret) {
731 dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
732 TWL4030_BCI_BCICTL1);
733 goto err_i2c;
734 }
735 regval |= TWL4030_BCI_MESBAT;
736 ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
737 regval, TWL4030_BCI_BCICTL1);
738 if (ret) {
739 dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
740 TWL4030_BCI_BCICTL1);
741 goto err_i2c;
742 }
Kyle Manna3d6271f2011-08-11 22:33:13 -0500743
744 /* Check that MADC clock is on */
745 ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
746 if (ret) {
747 dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
748 TWL4030_REG_GPBR1);
749 goto err_i2c;
750 }
751
752 /* If MADC clk is not on, turn it on */
753 if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
754 dev_info(&pdev->dev, "clk disabled, enabling\n");
755 regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
756 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
757 TWL4030_REG_GPBR1);
758 if (ret) {
759 dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
760 TWL4030_REG_GPBR1);
761 goto err_i2c;
762 }
763 }
764
Keerthyf99c1d42011-03-01 19:12:26 +0530765 platform_set_drvdata(pdev, madc);
766 mutex_init(&madc->lock);
767 ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
768 twl4030_madc_threaded_irq_handler,
769 IRQF_TRIGGER_RISING, "twl4030_madc", madc);
770 if (ret) {
771 dev_dbg(&pdev->dev, "could not request irq\n");
772 goto err_irq;
773 }
774 twl4030_madc = madc;
775 return 0;
776err_irq:
777 platform_set_drvdata(pdev, NULL);
778err_i2c:
779 twl4030_madc_set_current_generator(madc, 0, 0);
780err_current_generator:
781 twl4030_madc_set_power(madc, 0);
782err_power:
783 kfree(madc);
784
785 return ret;
786}
787
788static int __devexit twl4030_madc_remove(struct platform_device *pdev)
789{
790 struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
791
792 free_irq(platform_get_irq(pdev, 0), madc);
793 platform_set_drvdata(pdev, NULL);
794 twl4030_madc_set_current_generator(madc, 0, 0);
795 twl4030_madc_set_power(madc, 0);
796 kfree(madc);
797
798 return 0;
799}
800
801static struct platform_driver twl4030_madc_driver = {
802 .probe = twl4030_madc_probe,
803 .remove = __exit_p(twl4030_madc_remove),
804 .driver = {
805 .name = "twl4030_madc",
806 .owner = THIS_MODULE,
807 },
808};
809
Mark Brown65349d62011-11-23 22:58:34 +0000810module_platform_driver(twl4030_madc_driver);
Keerthyf99c1d42011-03-01 19:12:26 +0530811
812MODULE_DESCRIPTION("TWL4030 ADC driver");
813MODULE_LICENSE("GPL");
814MODULE_AUTHOR("J Keerthy");
Axel Lin0ea3e832011-03-07 11:02:29 +0800815MODULE_ALIAS("platform:twl4030_madc");