blob: e3cfb91bffc61122d56dc44b2ccd793afcd73800 [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
Keerthyf99c1d42011-03-01 19:12:26 +053032#include <linux/device.h>
33#include <linux/interrupt.h>
34#include <linux/kernel.h>
35#include <linux/delay.h>
36#include <linux/platform_device.h>
37#include <linux/slab.h>
Wolfram Sanga2054252017-08-14 18:34:24 +020038#include <linux/mfd/twl.h>
Keerthyf99c1d42011-03-01 19:12:26 +053039#include <linux/module.h>
40#include <linux/stddef.h>
41#include <linux/mutex.h>
42#include <linux/bitops.h>
43#include <linux/jiffies.h>
44#include <linux/types.h>
45#include <linux/gfp.h>
46#include <linux/err.h>
Adam YH Lee7cc97d72015-08-04 11:15:48 -070047#include <linux/regulator/consumer.h>
Keerthyf99c1d42011-03-01 19:12:26 +053048
Sebastian Reichel2f39b702014-03-16 02:43:26 +010049#include <linux/iio/iio.h>
50
Sebastian Reichel7af1a062017-04-27 17:30:12 +020051#define TWL4030_MADC_MAX_CHANNELS 16
52
53#define TWL4030_MADC_CTRL1 0x00
54#define TWL4030_MADC_CTRL2 0x01
55
56#define TWL4030_MADC_RTSELECT_LSB 0x02
57#define TWL4030_MADC_SW1SELECT_LSB 0x06
58#define TWL4030_MADC_SW2SELECT_LSB 0x0A
59
60#define TWL4030_MADC_RTAVERAGE_LSB 0x04
61#define TWL4030_MADC_SW1AVERAGE_LSB 0x08
62#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C
63
64#define TWL4030_MADC_CTRL_SW1 0x12
65#define TWL4030_MADC_CTRL_SW2 0x13
66
67#define TWL4030_MADC_RTCH0_LSB 0x17
68#define TWL4030_MADC_GPCH0_LSB 0x37
69
70#define TWL4030_MADC_MADCON (1 << 0) /* MADC power on */
71#define TWL4030_MADC_BUSY (1 << 0) /* MADC busy */
72/* MADC conversion completion */
73#define TWL4030_MADC_EOC_SW (1 << 1)
74/* MADC SWx start conversion */
75#define TWL4030_MADC_SW_START (1 << 5)
76#define TWL4030_MADC_ADCIN0 (1 << 0)
77#define TWL4030_MADC_ADCIN1 (1 << 1)
78#define TWL4030_MADC_ADCIN2 (1 << 2)
79#define TWL4030_MADC_ADCIN3 (1 << 3)
80#define TWL4030_MADC_ADCIN4 (1 << 4)
81#define TWL4030_MADC_ADCIN5 (1 << 5)
82#define TWL4030_MADC_ADCIN6 (1 << 6)
83#define TWL4030_MADC_ADCIN7 (1 << 7)
84#define TWL4030_MADC_ADCIN8 (1 << 8)
85#define TWL4030_MADC_ADCIN9 (1 << 9)
86#define TWL4030_MADC_ADCIN10 (1 << 10)
87#define TWL4030_MADC_ADCIN11 (1 << 11)
88#define TWL4030_MADC_ADCIN12 (1 << 12)
89#define TWL4030_MADC_ADCIN13 (1 << 13)
90#define TWL4030_MADC_ADCIN14 (1 << 14)
91#define TWL4030_MADC_ADCIN15 (1 << 15)
92
93/* Fixed channels */
94#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1
95#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8
96#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9
97#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10
98#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11
99#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12
100
101/* Step size and prescaler ratio */
102#define TEMP_STEP_SIZE 147
103#define TEMP_PSR_R 100
104#define CURR_STEP_SIZE 147
105#define CURR_PSR_R1 44
106#define CURR_PSR_R2 88
107
108#define TWL4030_BCI_BCICTL1 0x23
109#define TWL4030_BCI_CGAIN 0x020
110#define TWL4030_BCI_MESBAT (1 << 1)
111#define TWL4030_BCI_TYPEN (1 << 4)
112#define TWL4030_BCI_ITHEN (1 << 3)
113
114#define REG_BCICTL2 0x024
115#define TWL4030_BCI_ITHSENS 0x007
116
117/* Register and bits for GPBR1 register */
118#define TWL4030_REG_GPBR1 0x0c
119#define TWL4030_GPBR1_MADC_HFCLK_EN (1 << 7)
120
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700121#define TWL4030_USB_SEL_MADC_MCPC (1<<3)
122#define TWL4030_USB_CARKIT_ANA_CTRL 0xBB
123
Sebastian Reichel7af1a062017-04-27 17:30:12 +0200124struct twl4030_madc_conversion_method {
125 u8 sel;
126 u8 avg;
127 u8 rbase;
128 u8 ctrl;
129};
130
131/**
132 * struct twl4030_madc_request - madc request packet for channel conversion
133 * @channels: 16 bit bitmap for individual channels
134 * @do_avg: sample the input channel for 4 consecutive cycles
135 * @method: RT, SW1, SW2
136 * @type: Polling or interrupt based method
137 * @active: Flag if request is active
138 * @result_pending: Flag from irq handler, that result is ready
139 * @raw: Return raw value, do not convert it
140 * @rbuf: Result buffer
141 */
142struct twl4030_madc_request {
143 unsigned long channels;
144 bool do_avg;
145 u16 method;
146 u16 type;
147 bool active;
148 bool result_pending;
149 bool raw;
150 int rbuf[TWL4030_MADC_MAX_CHANNELS];
151};
152
153enum conversion_methods {
154 TWL4030_MADC_RT,
155 TWL4030_MADC_SW1,
156 TWL4030_MADC_SW2,
157 TWL4030_MADC_NUM_METHODS
158};
159
160enum sample_type {
161 TWL4030_MADC_WAIT,
162 TWL4030_MADC_IRQ_ONESHOT,
163 TWL4030_MADC_IRQ_REARM
164};
165
Sebastian Reichel99be0242014-03-16 02:43:27 +0100166/**
Keerthyf99c1d42011-03-01 19:12:26 +0530167 * struct twl4030_madc_data - a container for madc info
Sebastian Reichel99be0242014-03-16 02:43:27 +0100168 * @dev: Pointer to device structure for madc
169 * @lock: Mutex protecting this data structure
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700170 * @regulator: Pointer to bias regulator for madc
Sebastian Reichel99be0242014-03-16 02:43:27 +0100171 * @requests: Array of request struct corresponding to SW1, SW2 and RT
172 * @use_second_irq: IRQ selection (main or co-processor)
173 * @imr: Interrupt mask register of MADC
174 * @isr: Interrupt status register of MADC
Keerthyf99c1d42011-03-01 19:12:26 +0530175 */
176struct twl4030_madc_data {
177 struct device *dev;
178 struct mutex lock; /* mutex protecting this data structure */
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700179 struct regulator *usb3v1;
Keerthyf99c1d42011-03-01 19:12:26 +0530180 struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100181 bool use_second_irq;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100182 u8 imr;
183 u8 isr;
Keerthyf99c1d42011-03-01 19:12:26 +0530184};
185
Sebastian Reichel42ab9272017-04-27 17:30:09 +0200186static int twl4030_madc_conversion(struct twl4030_madc_request *req);
187
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100188static int twl4030_madc_read(struct iio_dev *iio_dev,
189 const struct iio_chan_spec *chan,
190 int *val, int *val2, long mask)
191{
192 struct twl4030_madc_data *madc = iio_priv(iio_dev);
193 struct twl4030_madc_request req;
194 int ret;
195
196 req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1;
197
198 req.channels = BIT(chan->channel);
199 req.active = false;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100200 req.type = TWL4030_MADC_WAIT;
201 req.raw = !(mask == IIO_CHAN_INFO_PROCESSED);
202 req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW);
203
204 ret = twl4030_madc_conversion(&req);
205 if (ret < 0)
206 return ret;
207
208 *val = req.rbuf[chan->channel];
209
210 return IIO_VAL_INT;
211}
212
213static const struct iio_info twl4030_madc_iio_info = {
214 .read_raw = &twl4030_madc_read,
215 .driver_module = THIS_MODULE,
216};
217
218#define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \
219 .type = _type, \
220 .channel = _channel, \
221 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
222 BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
223 BIT(IIO_CHAN_INFO_PROCESSED), \
224 .datasheet_name = _name, \
225 .indexed = 1, \
226}
227
228static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
229 TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"),
230 TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"),
231 TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"),
232 TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"),
233 TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"),
234 TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"),
235 TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"),
236 TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"),
237 TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"),
238 TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"),
239 TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"),
240 TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"),
241 TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"),
242 TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"),
243 TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"),
244 TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"),
245};
246
Keerthyf99c1d42011-03-01 19:12:26 +0530247static struct twl4030_madc_data *twl4030_madc;
248
249struct twl4030_prescale_divider_ratios {
250 s16 numerator;
251 s16 denominator;
252};
253
254static const struct twl4030_prescale_divider_ratios
255twl4030_divider_ratios[16] = {
256 {1, 1}, /* CHANNEL 0 No Prescaler */
257 {1, 1}, /* CHANNEL 1 No Prescaler */
258 {6, 10}, /* CHANNEL 2 */
259 {6, 10}, /* CHANNEL 3 */
260 {6, 10}, /* CHANNEL 4 */
261 {6, 10}, /* CHANNEL 5 */
262 {6, 10}, /* CHANNEL 6 */
263 {6, 10}, /* CHANNEL 7 */
264 {3, 14}, /* CHANNEL 8 */
265 {1, 3}, /* CHANNEL 9 */
266 {1, 1}, /* CHANNEL 10 No Prescaler */
267 {15, 100}, /* CHANNEL 11 */
268 {1, 4}, /* CHANNEL 12 */
269 {1, 1}, /* CHANNEL 13 Reserved channels */
270 {1, 1}, /* CHANNEL 14 Reseved channels */
271 {5, 11}, /* CHANNEL 15 */
272};
273
274
Sebastian Reichel99be0242014-03-16 02:43:27 +0100275/* Conversion table from -3 to 55 degrees Celcius */
276static int twl4030_therm_tbl[] = {
277 30800, 29500, 28300, 27100,
278 26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
279 17900, 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100,
280 12600, 12100, 11600, 11200, 10800, 10400, 10000, 9630, 9280,
281 8950, 8620, 8310, 8020, 7730, 7460, 7200, 6950, 6710,
282 6470, 6250, 6040, 5830, 5640, 5450, 5260, 5090, 4920,
283 4760, 4600, 4450, 4310, 4170, 4040, 3910, 3790, 3670,
284 3550
Keerthyf99c1d42011-03-01 19:12:26 +0530285};
286
287/*
288 * Structure containing the registers
289 * of different conversion methods supported by MADC.
290 * Hardware or RT real time conversion request initiated by external host
291 * processor for RT Signal conversions.
292 * External host processors can also request for non RT conversions
293 * SW1 and SW2 software conversions also called asynchronous or GPC request.
294 */
295static
296const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
297 [TWL4030_MADC_RT] = {
298 .sel = TWL4030_MADC_RTSELECT_LSB,
299 .avg = TWL4030_MADC_RTAVERAGE_LSB,
300 .rbase = TWL4030_MADC_RTCH0_LSB,
301 },
302 [TWL4030_MADC_SW1] = {
303 .sel = TWL4030_MADC_SW1SELECT_LSB,
304 .avg = TWL4030_MADC_SW1AVERAGE_LSB,
305 .rbase = TWL4030_MADC_GPCH0_LSB,
306 .ctrl = TWL4030_MADC_CTRL_SW1,
307 },
308 [TWL4030_MADC_SW2] = {
309 .sel = TWL4030_MADC_SW2SELECT_LSB,
310 .avg = TWL4030_MADC_SW2AVERAGE_LSB,
311 .rbase = TWL4030_MADC_GPCH0_LSB,
312 .ctrl = TWL4030_MADC_CTRL_SW2,
313 },
314};
315
Sebastian Reichel99be0242014-03-16 02:43:27 +0100316/**
317 * twl4030_madc_channel_raw_read() - Function to read a particular channel value
318 * @madc: pointer to struct twl4030_madc_data
319 * @reg: lsb of ADC Channel
320 *
321 * Return: 0 on success, an error code otherwise.
Keerthyf99c1d42011-03-01 19:12:26 +0530322 */
323static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
324{
Sebastian Reichel168ae302014-03-16 02:43:29 +0100325 u16 val;
Keerthyf99c1d42011-03-01 19:12:26 +0530326 int ret;
327 /*
328 * For each ADC channel, we have MSB and LSB register pair. MSB address
329 * is always LSB address+1. reg parameter is the address of LSB register
330 */
Sebastian Reichel168ae302014-03-16 02:43:29 +0100331 ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg);
Keerthyf99c1d42011-03-01 19:12:26 +0530332 if (ret) {
Sebastian Reichel168ae302014-03-16 02:43:29 +0100333 dev_err(madc->dev, "unable to read register 0x%X\n", reg);
Keerthyf99c1d42011-03-01 19:12:26 +0530334 return ret;
335 }
336
Sebastian Reichel168ae302014-03-16 02:43:29 +0100337 return (int)(val >> 6);
Keerthyf99c1d42011-03-01 19:12:26 +0530338}
339
340/*
Sebastian Reichel99be0242014-03-16 02:43:27 +0100341 * Return battery temperature in degrees Celsius
Keerthyf99c1d42011-03-01 19:12:26 +0530342 * Or < 0 on failure.
343 */
344static int twl4030battery_temperature(int raw_volt)
345{
346 u8 val;
347 int temp, curr, volt, res, ret;
348
349 volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100350 /* Getting and calculating the supply current in micro amperes */
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100351 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
Keerthyf99c1d42011-03-01 19:12:26 +0530352 REG_BCICTL2);
353 if (ret < 0)
354 return ret;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100355
H. Nikolaus Schaller0cbb39f2015-05-28 21:50:18 +0200356 curr = ((val & TWL4030_BCI_ITHSENS) + 1) * 10;
Keerthyf99c1d42011-03-01 19:12:26 +0530357 /* Getting and calculating the thermistor resistance in ohms */
358 res = volt * 1000 / curr;
359 /* calculating temperature */
360 for (temp = 58; temp >= 0; temp--) {
Sebastian Reichel99be0242014-03-16 02:43:27 +0100361 int actual = twl4030_therm_tbl[temp];
Keerthyf99c1d42011-03-01 19:12:26 +0530362 if ((actual - res) >= 0)
363 break;
364 }
365
366 return temp + 1;
367}
368
369static int twl4030battery_current(int raw_volt)
370{
371 int ret;
372 u8 val;
373
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100374 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
Keerthyf99c1d42011-03-01 19:12:26 +0530375 TWL4030_BCI_BCICTL1);
376 if (ret)
377 return ret;
378 if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
379 return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
380 else /* slope of 0.88 mV/mA */
381 return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
382}
Sebastian Reichel99be0242014-03-16 02:43:27 +0100383
Keerthyf99c1d42011-03-01 19:12:26 +0530384/*
385 * Function to read channel values
386 * @madc - pointer to twl4030_madc_data struct
387 * @reg_base - Base address of the first channel
Sebastian Reichel99be0242014-03-16 02:43:27 +0100388 * @Channels - 16 bit bitmap. If the bit is set, channel's value is read
Keerthyf99c1d42011-03-01 19:12:26 +0530389 * @buf - The channel values are stored here. if read fails error
Pali Rohára5055d52013-02-15 23:56:49 +0100390 * @raw - Return raw values without conversion
Keerthyf99c1d42011-03-01 19:12:26 +0530391 * value is stored
392 * Returns the number of successfully read channels.
393 */
394static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
395 u8 reg_base, unsigned
Pali Rohára5055d52013-02-15 23:56:49 +0100396 long channels, int *buf,
397 bool raw)
Keerthyf99c1d42011-03-01 19:12:26 +0530398{
Sebastian Reichel99be0242014-03-16 02:43:27 +0100399 int count = 0;
400 int i;
Keerthyf99c1d42011-03-01 19:12:26 +0530401 u8 reg;
402
403 for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
Sebastian Reichel99be0242014-03-16 02:43:27 +0100404 reg = reg_base + (2 * i);
Keerthyf99c1d42011-03-01 19:12:26 +0530405 buf[i] = twl4030_madc_channel_raw_read(madc, reg);
406 if (buf[i] < 0) {
Sebastian Reichel99be0242014-03-16 02:43:27 +0100407 dev_err(madc->dev, "Unable to read register 0x%X\n",
408 reg);
409 return buf[i];
Keerthyf99c1d42011-03-01 19:12:26 +0530410 }
Pali Rohára5055d52013-02-15 23:56:49 +0100411 if (raw) {
412 count++;
413 continue;
414 }
Keerthyf99c1d42011-03-01 19:12:26 +0530415 switch (i) {
416 case 10:
417 buf[i] = twl4030battery_current(buf[i]);
418 if (buf[i] < 0) {
419 dev_err(madc->dev, "err reading current\n");
Sebastian Reichel99be0242014-03-16 02:43:27 +0100420 return buf[i];
Keerthyf99c1d42011-03-01 19:12:26 +0530421 } else {
422 count++;
423 buf[i] = buf[i] - 750;
424 }
425 break;
426 case 1:
427 buf[i] = twl4030battery_temperature(buf[i]);
428 if (buf[i] < 0) {
429 dev_err(madc->dev, "err reading temperature\n");
Sebastian Reichel99be0242014-03-16 02:43:27 +0100430 return buf[i];
Keerthyf99c1d42011-03-01 19:12:26 +0530431 } else {
432 buf[i] -= 3;
433 count++;
434 }
435 break;
436 default:
437 count++;
438 /* Analog Input (V) = conv_result * step_size / R
439 * conv_result = decimal value of 10-bit conversion
440 * result
441 * step size = 1.5 / (2 ^ 10 -1)
442 * R = Prescaler ratio for input channels.
443 * Result given in mV hence multiplied by 1000.
444 */
445 buf[i] = (buf[i] * 3 * 1000 *
446 twl4030_divider_ratios[i].denominator)
447 / (2 * 1023 *
448 twl4030_divider_ratios[i].numerator);
449 }
450 }
Keerthyf99c1d42011-03-01 19:12:26 +0530451
452 return count;
453}
454
455/*
Keerthyf99c1d42011-03-01 19:12:26 +0530456 * Disables irq.
457 * @madc - pointer to twl4030_madc_data struct
458 * @id - irq number to be disabled
459 * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
460 * corresponding to RT, SW1, SW2 conversion requests.
461 * Returns error if i2c read/write fails.
462 */
463static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
464{
465 u8 val;
466 int ret;
467
468 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
469 if (ret) {
470 dev_err(madc->dev, "unable to read imr register 0x%X\n",
471 madc->imr);
472 return ret;
473 }
474 val |= (1 << id);
475 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
476 if (ret) {
477 dev_err(madc->dev,
478 "unable to write imr register 0x%X\n", madc->imr);
479 return ret;
480 }
481
482 return 0;
483}
484
485static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
486{
487 struct twl4030_madc_data *madc = _madc;
488 const struct twl4030_madc_conversion_method *method;
489 u8 isr_val, imr_val;
490 int i, len, ret;
491 struct twl4030_madc_request *r;
492
493 mutex_lock(&madc->lock);
494 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
495 if (ret) {
496 dev_err(madc->dev, "unable to read isr register 0x%X\n",
497 madc->isr);
498 goto err_i2c;
499 }
500 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
501 if (ret) {
502 dev_err(madc->dev, "unable to read imr register 0x%X\n",
503 madc->imr);
504 goto err_i2c;
505 }
506 isr_val &= ~imr_val;
507 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
508 if (!(isr_val & (1 << i)))
509 continue;
510 ret = twl4030_madc_disable_irq(madc, i);
511 if (ret < 0)
Sebastian Reichel99be0242014-03-16 02:43:27 +0100512 dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
Keerthyf99c1d42011-03-01 19:12:26 +0530513 madc->requests[i].result_pending = 1;
514 }
515 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
516 r = &madc->requests[i];
517 /* No pending results for this method, move to next one */
518 if (!r->result_pending)
519 continue;
520 method = &twl4030_conversion_methods[r->method];
521 /* Read results */
522 len = twl4030_madc_read_channels(madc, method->rbase,
Pali Rohára5055d52013-02-15 23:56:49 +0100523 r->channels, r->rbuf, r->raw);
Keerthyf99c1d42011-03-01 19:12:26 +0530524 /* Free request */
525 r->result_pending = 0;
526 r->active = 0;
527 }
528 mutex_unlock(&madc->lock);
529
530 return IRQ_HANDLED;
531
532err_i2c:
533 /*
534 * In case of error check whichever request is active
535 * and service the same.
536 */
537 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
538 r = &madc->requests[i];
539 if (r->active == 0)
540 continue;
541 method = &twl4030_conversion_methods[r->method];
542 /* Read results */
543 len = twl4030_madc_read_channels(madc, method->rbase,
Pali Rohára5055d52013-02-15 23:56:49 +0100544 r->channels, r->rbuf, r->raw);
Keerthyf99c1d42011-03-01 19:12:26 +0530545 /* Free request */
546 r->result_pending = 0;
547 r->active = 0;
548 }
549 mutex_unlock(&madc->lock);
550
551 return IRQ_HANDLED;
552}
553
Keerthyf99c1d42011-03-01 19:12:26 +0530554/*
555 * Function which enables the madc conversion
556 * by writing to the control register.
557 * @madc - pointer to twl4030_madc_data struct
558 * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
559 * corresponding to RT SW1 or SW2 conversion methods.
560 * Returns 0 if succeeds else a negative error value
561 */
562static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
563 int conv_method)
564{
565 const struct twl4030_madc_conversion_method *method;
566 int ret = 0;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100567
568 if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2)
569 return -ENOTSUPP;
570
Keerthyf99c1d42011-03-01 19:12:26 +0530571 method = &twl4030_conversion_methods[conv_method];
Sebastian Reichel99be0242014-03-16 02:43:27 +0100572 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START,
573 method->ctrl);
574 if (ret) {
575 dev_err(madc->dev, "unable to write ctrl register 0x%X\n",
576 method->ctrl);
577 return ret;
Keerthyf99c1d42011-03-01 19:12:26 +0530578 }
579
580 return 0;
581}
582
583/*
584 * Function that waits for conversion to be ready
585 * @madc - pointer to twl4030_madc_data struct
586 * @timeout_ms - timeout value in milliseconds
587 * @status_reg - ctrl register
588 * returns 0 if succeeds else a negative error value
589 */
590static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
591 unsigned int timeout_ms,
592 u8 status_reg)
593{
594 unsigned long timeout;
595 int ret;
596
597 timeout = jiffies + msecs_to_jiffies(timeout_ms);
598 do {
599 u8 reg;
600
601 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
602 if (ret) {
603 dev_err(madc->dev,
604 "unable to read status register 0x%X\n",
605 status_reg);
606 return ret;
607 }
608 if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
609 return 0;
610 usleep_range(500, 2000);
611 } while (!time_after(jiffies, timeout));
612 dev_err(madc->dev, "conversion timeout!\n");
613
614 return -EAGAIN;
615}
616
617/*
618 * An exported function which can be called from other kernel drivers.
619 * @req twl4030_madc_request structure
620 * req->rbuf will be filled with read values of channels based on the
621 * channel index. If a particular channel reading fails there will
622 * be a negative error value in the corresponding array element.
623 * returns 0 if succeeds else error value
624 */
Sebastian Reichel42ab9272017-04-27 17:30:09 +0200625static int twl4030_madc_conversion(struct twl4030_madc_request *req)
Keerthyf99c1d42011-03-01 19:12:26 +0530626{
627 const struct twl4030_madc_conversion_method *method;
Keerthyf99c1d42011-03-01 19:12:26 +0530628 int ret;
629
Kyle Mannad0e84ca2011-08-11 22:33:14 -0500630 if (!req || !twl4030_madc)
Keerthyf99c1d42011-03-01 19:12:26 +0530631 return -EINVAL;
Kyle Mannad0e84ca2011-08-11 22:33:14 -0500632
Keerthyf99c1d42011-03-01 19:12:26 +0530633 mutex_lock(&twl4030_madc->lock);
634 if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
635 ret = -EINVAL;
636 goto out;
637 }
638 /* Do we have a conversion request ongoing */
639 if (twl4030_madc->requests[req->method].active) {
640 ret = -EBUSY;
641 goto out;
642 }
Keerthyf99c1d42011-03-01 19:12:26 +0530643 method = &twl4030_conversion_methods[req->method];
644 /* Select channels to be converted */
Sebastian Reichel168ae302014-03-16 02:43:29 +0100645 ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel);
Keerthyf99c1d42011-03-01 19:12:26 +0530646 if (ret) {
647 dev_err(twl4030_madc->dev,
Sebastian Reichel168ae302014-03-16 02:43:29 +0100648 "unable to write sel register 0x%X\n", method->sel);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530649 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530650 }
651 /* Select averaging for all channels if do_avg is set */
652 if (req->do_avg) {
Sebastian Reichel168ae302014-03-16 02:43:29 +0100653 ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels,
654 method->avg);
Keerthyf99c1d42011-03-01 19:12:26 +0530655 if (ret) {
656 dev_err(twl4030_madc->dev,
657 "unable to write avg register 0x%X\n",
Sebastian Reichel99be0242014-03-16 02:43:27 +0100658 method->avg);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530659 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530660 }
661 }
Keerthyf99c1d42011-03-01 19:12:26 +0530662 /* With RT method we should not be here anymore */
663 if (req->method == TWL4030_MADC_RT) {
664 ret = -EINVAL;
665 goto out;
666 }
667 ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
668 if (ret < 0)
669 goto out;
670 twl4030_madc->requests[req->method].active = 1;
671 /* Wait until conversion is ready (ctrl register returns EOC) */
672 ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
673 if (ret) {
674 twl4030_madc->requests[req->method].active = 0;
675 goto out;
676 }
677 ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
Pali Rohára5055d52013-02-15 23:56:49 +0100678 req->channels, req->rbuf, req->raw);
Keerthyf99c1d42011-03-01 19:12:26 +0530679 twl4030_madc->requests[req->method].active = 0;
680
681out:
682 mutex_unlock(&twl4030_madc->lock);
683
684 return ret;
685}
Keerthyf99c1d42011-03-01 19:12:26 +0530686
Sebastian Reichel99be0242014-03-16 02:43:27 +0100687/**
688 * twl4030_madc_set_current_generator() - setup bias current
689 *
690 * @madc: pointer to twl4030_madc_data struct
691 * @chan: can be one of the two values:
H. Nikolaus Schaller994bda82015-05-28 21:50:19 +0200692 * 0 - Enables bias current for main battery type reading
693 * 1 - Enables bias current for main battery temperature sensing
Sebastian Reichel99be0242014-03-16 02:43:27 +0100694 * @on: enable or disable chan.
695 *
Keerthyf99c1d42011-03-01 19:12:26 +0530696 * Function to enable or disable bias current for
697 * main battery type reading or temperature sensing
Keerthyf99c1d42011-03-01 19:12:26 +0530698 */
699static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
700 int chan, int on)
701{
702 int ret;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100703 int regmask;
Keerthyf99c1d42011-03-01 19:12:26 +0530704 u8 regval;
705
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100706 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530707 &regval, TWL4030_BCI_BCICTL1);
708 if (ret) {
709 dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
710 TWL4030_BCI_BCICTL1);
711 return ret;
712 }
Sebastian Reichel99be0242014-03-16 02:43:27 +0100713
714 regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
Keerthyf99c1d42011-03-01 19:12:26 +0530715 if (on)
Sebastian Reichel99be0242014-03-16 02:43:27 +0100716 regval |= regmask;
Keerthyf99c1d42011-03-01 19:12:26 +0530717 else
Sebastian Reichel99be0242014-03-16 02:43:27 +0100718 regval &= ~regmask;
719
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100720 ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530721 regval, TWL4030_BCI_BCICTL1);
722 if (ret) {
723 dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
724 TWL4030_BCI_BCICTL1);
725 return ret;
726 }
727
728 return 0;
729}
730
731/*
732 * Function that sets MADC software power on bit to enable MADC
733 * @madc - pointer to twl4030_madc_data struct
Sebastian Reichel99be0242014-03-16 02:43:27 +0100734 * @on - Enable or disable MADC software power on bit.
Keerthyf99c1d42011-03-01 19:12:26 +0530735 * returns error if i2c read/write fails else 0
736 */
737static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
738{
739 u8 regval;
740 int ret;
741
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100742 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530743 &regval, TWL4030_MADC_CTRL1);
744 if (ret) {
745 dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
746 TWL4030_MADC_CTRL1);
747 return ret;
748 }
749 if (on)
750 regval |= TWL4030_MADC_MADCON;
751 else
752 regval &= ~TWL4030_MADC_MADCON;
753 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
754 if (ret) {
755 dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
756 TWL4030_MADC_CTRL1);
757 return ret;
758 }
759
760 return 0;
761}
762
763/*
764 * Initialize MADC and request for threaded irq
765 */
Bill Pembertonf791be42012-11-19 13:23:04 -0500766static int twl4030_madc_probe(struct platform_device *pdev)
Keerthyf99c1d42011-03-01 19:12:26 +0530767{
768 struct twl4030_madc_data *madc;
Jingoo Han334a41c2013-07-30 17:10:05 +0900769 struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100770 struct device_node *np = pdev->dev.of_node;
Sebastian Reichele7f22b72014-03-16 02:43:25 +0100771 int irq, ret;
Keerthyf99c1d42011-03-01 19:12:26 +0530772 u8 regval;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100773 struct iio_dev *iio_dev = NULL;
Keerthyf99c1d42011-03-01 19:12:26 +0530774
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100775 if (!pdata && !np) {
776 dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n");
Keerthyf99c1d42011-03-01 19:12:26 +0530777 return -EINVAL;
778 }
Keerthyf99c1d42011-03-01 19:12:26 +0530779
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100780 iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc));
781 if (!iio_dev) {
782 dev_err(&pdev->dev, "failed allocating iio device\n");
783 return -ENOMEM;
784 }
785
786 madc = iio_priv(iio_dev);
Kyle Manna66cc5b82011-08-11 22:33:12 -0500787 madc->dev = &pdev->dev;
788
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100789 iio_dev->name = dev_name(&pdev->dev);
790 iio_dev->dev.parent = &pdev->dev;
791 iio_dev->dev.of_node = pdev->dev.of_node;
792 iio_dev->info = &twl4030_madc_iio_info;
793 iio_dev->modes = INDIO_DIRECT_MODE;
794 iio_dev->channels = twl4030_madc_iio_channels;
795 iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels);
796
Keerthyf99c1d42011-03-01 19:12:26 +0530797 /*
798 * Phoenix provides 2 interrupt lines. The first one is connected to
799 * the OMAP. The other one can be connected to the other processor such
800 * as modem. Hence two separate ISR and IMR registers.
801 */
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100802 if (pdata)
803 madc->use_second_irq = (pdata->irq_line != 1);
804 else
805 madc->use_second_irq = of_property_read_bool(np,
806 "ti,system-uses-second-madc-irq");
807
808 madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 :
809 TWL4030_MADC_IMR1;
810 madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 :
811 TWL4030_MADC_ISR1;
812
Keerthyf99c1d42011-03-01 19:12:26 +0530813 ret = twl4030_madc_set_power(madc, 1);
814 if (ret < 0)
Sebastian Reichele7f22b72014-03-16 02:43:25 +0100815 return ret;
Keerthyf99c1d42011-03-01 19:12:26 +0530816 ret = twl4030_madc_set_current_generator(madc, 0, 1);
817 if (ret < 0)
818 goto err_current_generator;
819
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100820 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530821 &regval, TWL4030_BCI_BCICTL1);
822 if (ret) {
823 dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
824 TWL4030_BCI_BCICTL1);
825 goto err_i2c;
826 }
827 regval |= TWL4030_BCI_MESBAT;
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100828 ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530829 regval, TWL4030_BCI_BCICTL1);
830 if (ret) {
831 dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
832 TWL4030_BCI_BCICTL1);
833 goto err_i2c;
834 }
Kyle Manna3d6271f2011-08-11 22:33:13 -0500835
836 /* Check that MADC clock is on */
837 ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
838 if (ret) {
839 dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
840 TWL4030_REG_GPBR1);
841 goto err_i2c;
842 }
843
844 /* If MADC clk is not on, turn it on */
845 if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
846 dev_info(&pdev->dev, "clk disabled, enabling\n");
847 regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
848 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
849 TWL4030_REG_GPBR1);
850 if (ret) {
851 dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
852 TWL4030_REG_GPBR1);
853 goto err_i2c;
854 }
855 }
856
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100857 platform_set_drvdata(pdev, iio_dev);
Keerthyf99c1d42011-03-01 19:12:26 +0530858 mutex_init(&madc->lock);
Sebastian Reichele7f22b72014-03-16 02:43:25 +0100859
860 irq = platform_get_irq(pdev, 0);
861 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
Keerthyf99c1d42011-03-01 19:12:26 +0530862 twl4030_madc_threaded_irq_handler,
Fabio Estevam6c0d48c2015-05-24 17:39:04 -0300863 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
864 "twl4030_madc", madc);
Keerthyf99c1d42011-03-01 19:12:26 +0530865 if (ret) {
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100866 dev_err(&pdev->dev, "could not request irq\n");
Jingoo Hanc3d6a0a2013-05-06 13:08:08 +0900867 goto err_i2c;
Keerthyf99c1d42011-03-01 19:12:26 +0530868 }
869 twl4030_madc = madc;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100870
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700871 /* Configure MADC[3:6] */
872 ret = twl_i2c_read_u8(TWL_MODULE_USB, &regval,
873 TWL4030_USB_CARKIT_ANA_CTRL);
874 if (ret) {
875 dev_err(&pdev->dev, "unable to read reg CARKIT_ANA_CTRL 0x%X\n",
876 TWL4030_USB_CARKIT_ANA_CTRL);
877 goto err_i2c;
878 }
879 regval |= TWL4030_USB_SEL_MADC_MCPC;
880 ret = twl_i2c_write_u8(TWL_MODULE_USB, regval,
881 TWL4030_USB_CARKIT_ANA_CTRL);
882 if (ret) {
883 dev_err(&pdev->dev, "unable to write reg CARKIT_ANA_CTRL 0x%X\n",
884 TWL4030_USB_CARKIT_ANA_CTRL);
885 goto err_i2c;
886 }
887
888 /* Enable 3v1 bias regulator for MADC[3:6] */
889 madc->usb3v1 = devm_regulator_get(madc->dev, "vusb3v1");
Christophe JAILLET245a3962017-09-23 08:06:18 +0200890 if (IS_ERR(madc->usb3v1)) {
891 ret = -ENODEV;
892 goto err_i2c;
893 }
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700894
895 ret = regulator_enable(madc->usb3v1);
Christophe JAILLET53063842017-09-23 08:06:20 +0200896 if (ret) {
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700897 dev_err(madc->dev, "could not enable 3v1 bias regulator\n");
Christophe JAILLET53063842017-09-23 08:06:20 +0200898 goto err_i2c;
899 }
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700900
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100901 ret = iio_device_register(iio_dev);
902 if (ret) {
903 dev_err(&pdev->dev, "could not register iio device\n");
Christophe JAILLET7f70be62017-09-23 08:06:19 +0200904 goto err_usb3v1;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100905 }
906
Keerthyf99c1d42011-03-01 19:12:26 +0530907 return 0;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100908
Christophe JAILLET7f70be62017-09-23 08:06:19 +0200909err_usb3v1:
910 regulator_disable(madc->usb3v1);
Keerthyf99c1d42011-03-01 19:12:26 +0530911err_i2c:
912 twl4030_madc_set_current_generator(madc, 0, 0);
913err_current_generator:
914 twl4030_madc_set_power(madc, 0);
Keerthyf99c1d42011-03-01 19:12:26 +0530915 return ret;
916}
917
Bill Pemberton4740f732012-11-19 13:26:01 -0500918static int twl4030_madc_remove(struct platform_device *pdev)
Keerthyf99c1d42011-03-01 19:12:26 +0530919{
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100920 struct iio_dev *iio_dev = platform_get_drvdata(pdev);
921 struct twl4030_madc_data *madc = iio_priv(iio_dev);
922
923 iio_device_unregister(iio_dev);
Keerthyf99c1d42011-03-01 19:12:26 +0530924
Keerthyf99c1d42011-03-01 19:12:26 +0530925 twl4030_madc_set_current_generator(madc, 0, 0);
926 twl4030_madc_set_power(madc, 0);
Keerthyf99c1d42011-03-01 19:12:26 +0530927
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700928 regulator_disable(madc->usb3v1);
929
Keerthyf99c1d42011-03-01 19:12:26 +0530930 return 0;
931}
932
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100933#ifdef CONFIG_OF
934static const struct of_device_id twl_madc_of_match[] = {
935 { .compatible = "ti,twl4030-madc", },
936 { },
937};
938MODULE_DEVICE_TABLE(of, twl_madc_of_match);
939#endif
940
Keerthyf99c1d42011-03-01 19:12:26 +0530941static struct platform_driver twl4030_madc_driver = {
942 .probe = twl4030_madc_probe,
Arnd Bergmann03715412013-03-14 22:56:38 +0100943 .remove = twl4030_madc_remove,
Keerthyf99c1d42011-03-01 19:12:26 +0530944 .driver = {
945 .name = "twl4030_madc",
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100946 .of_match_table = of_match_ptr(twl_madc_of_match),
Sebastian Reichel99be0242014-03-16 02:43:27 +0100947 },
Keerthyf99c1d42011-03-01 19:12:26 +0530948};
949
Mark Brown65349d62011-11-23 22:58:34 +0000950module_platform_driver(twl4030_madc_driver);
Keerthyf99c1d42011-03-01 19:12:26 +0530951
952MODULE_DESCRIPTION("TWL4030 ADC driver");
953MODULE_LICENSE("GPL");
954MODULE_AUTHOR("J Keerthy");
Axel Lin0ea3e832011-03-07 11:02:29 +0800955MODULE_ALIAS("platform:twl4030_madc");