blob: 8c019bb6625fcf1a6b066e545539b52e811e4132 [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,
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100215};
216
217#define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \
218 .type = _type, \
219 .channel = _channel, \
220 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
221 BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
222 BIT(IIO_CHAN_INFO_PROCESSED), \
223 .datasheet_name = _name, \
224 .indexed = 1, \
225}
226
227static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
228 TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"),
229 TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"),
230 TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"),
231 TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"),
232 TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"),
233 TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"),
234 TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"),
235 TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"),
236 TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"),
237 TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"),
238 TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"),
239 TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"),
240 TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"),
241 TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"),
242 TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"),
243 TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"),
244};
245
Keerthyf99c1d42011-03-01 19:12:26 +0530246static struct twl4030_madc_data *twl4030_madc;
247
248struct twl4030_prescale_divider_ratios {
249 s16 numerator;
250 s16 denominator;
251};
252
253static const struct twl4030_prescale_divider_ratios
254twl4030_divider_ratios[16] = {
255 {1, 1}, /* CHANNEL 0 No Prescaler */
256 {1, 1}, /* CHANNEL 1 No Prescaler */
257 {6, 10}, /* CHANNEL 2 */
258 {6, 10}, /* CHANNEL 3 */
259 {6, 10}, /* CHANNEL 4 */
260 {6, 10}, /* CHANNEL 5 */
261 {6, 10}, /* CHANNEL 6 */
262 {6, 10}, /* CHANNEL 7 */
263 {3, 14}, /* CHANNEL 8 */
264 {1, 3}, /* CHANNEL 9 */
265 {1, 1}, /* CHANNEL 10 No Prescaler */
266 {15, 100}, /* CHANNEL 11 */
267 {1, 4}, /* CHANNEL 12 */
268 {1, 1}, /* CHANNEL 13 Reserved channels */
269 {1, 1}, /* CHANNEL 14 Reseved channels */
270 {5, 11}, /* CHANNEL 15 */
271};
272
273
Sebastian Reichel99be0242014-03-16 02:43:27 +0100274/* Conversion table from -3 to 55 degrees Celcius */
275static int twl4030_therm_tbl[] = {
276 30800, 29500, 28300, 27100,
277 26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
278 17900, 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100,
279 12600, 12100, 11600, 11200, 10800, 10400, 10000, 9630, 9280,
280 8950, 8620, 8310, 8020, 7730, 7460, 7200, 6950, 6710,
281 6470, 6250, 6040, 5830, 5640, 5450, 5260, 5090, 4920,
282 4760, 4600, 4450, 4310, 4170, 4040, 3910, 3790, 3670,
283 3550
Keerthyf99c1d42011-03-01 19:12:26 +0530284};
285
286/*
287 * Structure containing the registers
288 * of different conversion methods supported by MADC.
289 * Hardware or RT real time conversion request initiated by external host
290 * processor for RT Signal conversions.
291 * External host processors can also request for non RT conversions
292 * SW1 and SW2 software conversions also called asynchronous or GPC request.
293 */
294static
295const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
296 [TWL4030_MADC_RT] = {
297 .sel = TWL4030_MADC_RTSELECT_LSB,
298 .avg = TWL4030_MADC_RTAVERAGE_LSB,
299 .rbase = TWL4030_MADC_RTCH0_LSB,
300 },
301 [TWL4030_MADC_SW1] = {
302 .sel = TWL4030_MADC_SW1SELECT_LSB,
303 .avg = TWL4030_MADC_SW1AVERAGE_LSB,
304 .rbase = TWL4030_MADC_GPCH0_LSB,
305 .ctrl = TWL4030_MADC_CTRL_SW1,
306 },
307 [TWL4030_MADC_SW2] = {
308 .sel = TWL4030_MADC_SW2SELECT_LSB,
309 .avg = TWL4030_MADC_SW2AVERAGE_LSB,
310 .rbase = TWL4030_MADC_GPCH0_LSB,
311 .ctrl = TWL4030_MADC_CTRL_SW2,
312 },
313};
314
Sebastian Reichel99be0242014-03-16 02:43:27 +0100315/**
316 * twl4030_madc_channel_raw_read() - Function to read a particular channel value
317 * @madc: pointer to struct twl4030_madc_data
318 * @reg: lsb of ADC Channel
319 *
320 * Return: 0 on success, an error code otherwise.
Keerthyf99c1d42011-03-01 19:12:26 +0530321 */
322static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
323{
Sebastian Reichel168ae302014-03-16 02:43:29 +0100324 u16 val;
Keerthyf99c1d42011-03-01 19:12:26 +0530325 int ret;
326 /*
327 * For each ADC channel, we have MSB and LSB register pair. MSB address
328 * is always LSB address+1. reg parameter is the address of LSB register
329 */
Sebastian Reichel168ae302014-03-16 02:43:29 +0100330 ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg);
Keerthyf99c1d42011-03-01 19:12:26 +0530331 if (ret) {
Sebastian Reichel168ae302014-03-16 02:43:29 +0100332 dev_err(madc->dev, "unable to read register 0x%X\n", reg);
Keerthyf99c1d42011-03-01 19:12:26 +0530333 return ret;
334 }
335
Sebastian Reichel168ae302014-03-16 02:43:29 +0100336 return (int)(val >> 6);
Keerthyf99c1d42011-03-01 19:12:26 +0530337}
338
339/*
Sebastian Reichel99be0242014-03-16 02:43:27 +0100340 * Return battery temperature in degrees Celsius
Keerthyf99c1d42011-03-01 19:12:26 +0530341 * Or < 0 on failure.
342 */
343static int twl4030battery_temperature(int raw_volt)
344{
345 u8 val;
346 int temp, curr, volt, res, ret;
347
348 volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100349 /* Getting and calculating the supply current in micro amperes */
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100350 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
Keerthyf99c1d42011-03-01 19:12:26 +0530351 REG_BCICTL2);
352 if (ret < 0)
353 return ret;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100354
H. Nikolaus Schaller0cbb39f2015-05-28 21:50:18 +0200355 curr = ((val & TWL4030_BCI_ITHSENS) + 1) * 10;
Keerthyf99c1d42011-03-01 19:12:26 +0530356 /* Getting and calculating the thermistor resistance in ohms */
357 res = volt * 1000 / curr;
358 /* calculating temperature */
359 for (temp = 58; temp >= 0; temp--) {
Sebastian Reichel99be0242014-03-16 02:43:27 +0100360 int actual = twl4030_therm_tbl[temp];
Keerthyf99c1d42011-03-01 19:12:26 +0530361 if ((actual - res) >= 0)
362 break;
363 }
364
365 return temp + 1;
366}
367
368static int twl4030battery_current(int raw_volt)
369{
370 int ret;
371 u8 val;
372
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100373 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
Keerthyf99c1d42011-03-01 19:12:26 +0530374 TWL4030_BCI_BCICTL1);
375 if (ret)
376 return ret;
377 if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
378 return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
379 else /* slope of 0.88 mV/mA */
380 return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
381}
Sebastian Reichel99be0242014-03-16 02:43:27 +0100382
Keerthyf99c1d42011-03-01 19:12:26 +0530383/*
384 * Function to read channel values
385 * @madc - pointer to twl4030_madc_data struct
386 * @reg_base - Base address of the first channel
Sebastian Reichel99be0242014-03-16 02:43:27 +0100387 * @Channels - 16 bit bitmap. If the bit is set, channel's value is read
Keerthyf99c1d42011-03-01 19:12:26 +0530388 * @buf - The channel values are stored here. if read fails error
Pali Rohára5055d52013-02-15 23:56:49 +0100389 * @raw - Return raw values without conversion
Keerthyf99c1d42011-03-01 19:12:26 +0530390 * value is stored
391 * Returns the number of successfully read channels.
392 */
393static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
394 u8 reg_base, unsigned
Pali Rohára5055d52013-02-15 23:56:49 +0100395 long channels, int *buf,
396 bool raw)
Keerthyf99c1d42011-03-01 19:12:26 +0530397{
Sebastian Reichel99be0242014-03-16 02:43:27 +0100398 int count = 0;
399 int i;
Keerthyf99c1d42011-03-01 19:12:26 +0530400 u8 reg;
401
402 for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
Sebastian Reichel99be0242014-03-16 02:43:27 +0100403 reg = reg_base + (2 * i);
Keerthyf99c1d42011-03-01 19:12:26 +0530404 buf[i] = twl4030_madc_channel_raw_read(madc, reg);
405 if (buf[i] < 0) {
Sebastian Reichel99be0242014-03-16 02:43:27 +0100406 dev_err(madc->dev, "Unable to read register 0x%X\n",
407 reg);
408 return buf[i];
Keerthyf99c1d42011-03-01 19:12:26 +0530409 }
Pali Rohára5055d52013-02-15 23:56:49 +0100410 if (raw) {
411 count++;
412 continue;
413 }
Keerthyf99c1d42011-03-01 19:12:26 +0530414 switch (i) {
415 case 10:
416 buf[i] = twl4030battery_current(buf[i]);
417 if (buf[i] < 0) {
418 dev_err(madc->dev, "err reading current\n");
Sebastian Reichel99be0242014-03-16 02:43:27 +0100419 return buf[i];
Keerthyf99c1d42011-03-01 19:12:26 +0530420 } else {
421 count++;
422 buf[i] = buf[i] - 750;
423 }
424 break;
425 case 1:
426 buf[i] = twl4030battery_temperature(buf[i]);
427 if (buf[i] < 0) {
428 dev_err(madc->dev, "err reading temperature\n");
Sebastian Reichel99be0242014-03-16 02:43:27 +0100429 return buf[i];
Keerthyf99c1d42011-03-01 19:12:26 +0530430 } else {
431 buf[i] -= 3;
432 count++;
433 }
434 break;
435 default:
436 count++;
437 /* Analog Input (V) = conv_result * step_size / R
438 * conv_result = decimal value of 10-bit conversion
439 * result
440 * step size = 1.5 / (2 ^ 10 -1)
441 * R = Prescaler ratio for input channels.
442 * Result given in mV hence multiplied by 1000.
443 */
444 buf[i] = (buf[i] * 3 * 1000 *
445 twl4030_divider_ratios[i].denominator)
446 / (2 * 1023 *
447 twl4030_divider_ratios[i].numerator);
448 }
449 }
Keerthyf99c1d42011-03-01 19:12:26 +0530450
451 return count;
452}
453
454/*
Keerthyf99c1d42011-03-01 19:12:26 +0530455 * Disables irq.
456 * @madc - pointer to twl4030_madc_data struct
457 * @id - irq number to be disabled
458 * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
459 * corresponding to RT, SW1, SW2 conversion requests.
460 * Returns error if i2c read/write fails.
461 */
462static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
463{
464 u8 val;
465 int ret;
466
467 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
468 if (ret) {
469 dev_err(madc->dev, "unable to read imr register 0x%X\n",
470 madc->imr);
471 return ret;
472 }
473 val |= (1 << id);
474 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
475 if (ret) {
476 dev_err(madc->dev,
477 "unable to write imr register 0x%X\n", madc->imr);
478 return ret;
479 }
480
481 return 0;
482}
483
484static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
485{
486 struct twl4030_madc_data *madc = _madc;
487 const struct twl4030_madc_conversion_method *method;
488 u8 isr_val, imr_val;
489 int i, len, ret;
490 struct twl4030_madc_request *r;
491
492 mutex_lock(&madc->lock);
493 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
494 if (ret) {
495 dev_err(madc->dev, "unable to read isr register 0x%X\n",
496 madc->isr);
497 goto err_i2c;
498 }
499 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
500 if (ret) {
501 dev_err(madc->dev, "unable to read imr register 0x%X\n",
502 madc->imr);
503 goto err_i2c;
504 }
505 isr_val &= ~imr_val;
506 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
507 if (!(isr_val & (1 << i)))
508 continue;
509 ret = twl4030_madc_disable_irq(madc, i);
510 if (ret < 0)
Sebastian Reichel99be0242014-03-16 02:43:27 +0100511 dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
Keerthyf99c1d42011-03-01 19:12:26 +0530512 madc->requests[i].result_pending = 1;
513 }
514 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
515 r = &madc->requests[i];
516 /* No pending results for this method, move to next one */
517 if (!r->result_pending)
518 continue;
519 method = &twl4030_conversion_methods[r->method];
520 /* Read results */
521 len = twl4030_madc_read_channels(madc, method->rbase,
Pali Rohára5055d52013-02-15 23:56:49 +0100522 r->channels, r->rbuf, r->raw);
Keerthyf99c1d42011-03-01 19:12:26 +0530523 /* Free request */
524 r->result_pending = 0;
525 r->active = 0;
526 }
527 mutex_unlock(&madc->lock);
528
529 return IRQ_HANDLED;
530
531err_i2c:
532 /*
533 * In case of error check whichever request is active
534 * and service the same.
535 */
536 for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
537 r = &madc->requests[i];
538 if (r->active == 0)
539 continue;
540 method = &twl4030_conversion_methods[r->method];
541 /* Read results */
542 len = twl4030_madc_read_channels(madc, method->rbase,
Pali Rohára5055d52013-02-15 23:56:49 +0100543 r->channels, r->rbuf, r->raw);
Keerthyf99c1d42011-03-01 19:12:26 +0530544 /* Free request */
545 r->result_pending = 0;
546 r->active = 0;
547 }
548 mutex_unlock(&madc->lock);
549
550 return IRQ_HANDLED;
551}
552
Keerthyf99c1d42011-03-01 19:12:26 +0530553/*
554 * Function which enables the madc conversion
555 * by writing to the control register.
556 * @madc - pointer to twl4030_madc_data struct
557 * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
558 * corresponding to RT SW1 or SW2 conversion methods.
559 * Returns 0 if succeeds else a negative error value
560 */
561static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
562 int conv_method)
563{
564 const struct twl4030_madc_conversion_method *method;
565 int ret = 0;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100566
567 if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2)
568 return -ENOTSUPP;
569
Keerthyf99c1d42011-03-01 19:12:26 +0530570 method = &twl4030_conversion_methods[conv_method];
Sebastian Reichel99be0242014-03-16 02:43:27 +0100571 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START,
572 method->ctrl);
573 if (ret) {
574 dev_err(madc->dev, "unable to write ctrl register 0x%X\n",
575 method->ctrl);
576 return ret;
Keerthyf99c1d42011-03-01 19:12:26 +0530577 }
578
579 return 0;
580}
581
582/*
583 * Function that waits for conversion to be ready
584 * @madc - pointer to twl4030_madc_data struct
585 * @timeout_ms - timeout value in milliseconds
586 * @status_reg - ctrl register
587 * returns 0 if succeeds else a negative error value
588 */
589static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
590 unsigned int timeout_ms,
591 u8 status_reg)
592{
593 unsigned long timeout;
594 int ret;
595
596 timeout = jiffies + msecs_to_jiffies(timeout_ms);
597 do {
598 u8 reg;
599
600 ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
601 if (ret) {
602 dev_err(madc->dev,
603 "unable to read status register 0x%X\n",
604 status_reg);
605 return ret;
606 }
607 if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
608 return 0;
609 usleep_range(500, 2000);
610 } while (!time_after(jiffies, timeout));
611 dev_err(madc->dev, "conversion timeout!\n");
612
613 return -EAGAIN;
614}
615
616/*
617 * An exported function which can be called from other kernel drivers.
618 * @req twl4030_madc_request structure
619 * req->rbuf will be filled with read values of channels based on the
620 * channel index. If a particular channel reading fails there will
621 * be a negative error value in the corresponding array element.
622 * returns 0 if succeeds else error value
623 */
Sebastian Reichel42ab9272017-04-27 17:30:09 +0200624static int twl4030_madc_conversion(struct twl4030_madc_request *req)
Keerthyf99c1d42011-03-01 19:12:26 +0530625{
626 const struct twl4030_madc_conversion_method *method;
Keerthyf99c1d42011-03-01 19:12:26 +0530627 int ret;
628
Kyle Mannad0e84ca2011-08-11 22:33:14 -0500629 if (!req || !twl4030_madc)
Keerthyf99c1d42011-03-01 19:12:26 +0530630 return -EINVAL;
Kyle Mannad0e84ca2011-08-11 22:33:14 -0500631
Keerthyf99c1d42011-03-01 19:12:26 +0530632 mutex_lock(&twl4030_madc->lock);
633 if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
634 ret = -EINVAL;
635 goto out;
636 }
637 /* Do we have a conversion request ongoing */
638 if (twl4030_madc->requests[req->method].active) {
639 ret = -EBUSY;
640 goto out;
641 }
Keerthyf99c1d42011-03-01 19:12:26 +0530642 method = &twl4030_conversion_methods[req->method];
643 /* Select channels to be converted */
Sebastian Reichel168ae302014-03-16 02:43:29 +0100644 ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel);
Keerthyf99c1d42011-03-01 19:12:26 +0530645 if (ret) {
646 dev_err(twl4030_madc->dev,
Sebastian Reichel168ae302014-03-16 02:43:29 +0100647 "unable to write sel register 0x%X\n", method->sel);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530648 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530649 }
650 /* Select averaging for all channels if do_avg is set */
651 if (req->do_avg) {
Sebastian Reichel168ae302014-03-16 02:43:29 +0100652 ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels,
653 method->avg);
Keerthyf99c1d42011-03-01 19:12:26 +0530654 if (ret) {
655 dev_err(twl4030_madc->dev,
656 "unable to write avg register 0x%X\n",
Sebastian Reichel99be0242014-03-16 02:43:27 +0100657 method->avg);
Sanjeev Premie178ccb2011-07-11 20:50:31 +0530658 goto out;
Keerthyf99c1d42011-03-01 19:12:26 +0530659 }
660 }
Keerthyf99c1d42011-03-01 19:12:26 +0530661 /* With RT method we should not be here anymore */
662 if (req->method == TWL4030_MADC_RT) {
663 ret = -EINVAL;
664 goto out;
665 }
666 ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
667 if (ret < 0)
668 goto out;
669 twl4030_madc->requests[req->method].active = 1;
670 /* Wait until conversion is ready (ctrl register returns EOC) */
671 ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
672 if (ret) {
673 twl4030_madc->requests[req->method].active = 0;
674 goto out;
675 }
676 ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
Pali Rohára5055d52013-02-15 23:56:49 +0100677 req->channels, req->rbuf, req->raw);
Keerthyf99c1d42011-03-01 19:12:26 +0530678 twl4030_madc->requests[req->method].active = 0;
679
680out:
681 mutex_unlock(&twl4030_madc->lock);
682
683 return ret;
684}
Keerthyf99c1d42011-03-01 19:12:26 +0530685
Sebastian Reichel99be0242014-03-16 02:43:27 +0100686/**
687 * twl4030_madc_set_current_generator() - setup bias current
688 *
689 * @madc: pointer to twl4030_madc_data struct
690 * @chan: can be one of the two values:
H. Nikolaus Schaller994bda82015-05-28 21:50:19 +0200691 * 0 - Enables bias current for main battery type reading
692 * 1 - Enables bias current for main battery temperature sensing
Sebastian Reichel99be0242014-03-16 02:43:27 +0100693 * @on: enable or disable chan.
694 *
Keerthyf99c1d42011-03-01 19:12:26 +0530695 * Function to enable or disable bias current for
696 * main battery type reading or temperature sensing
Keerthyf99c1d42011-03-01 19:12:26 +0530697 */
698static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
699 int chan, int on)
700{
701 int ret;
Sebastian Reichel99be0242014-03-16 02:43:27 +0100702 int regmask;
Keerthyf99c1d42011-03-01 19:12:26 +0530703 u8 regval;
704
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100705 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530706 &regval, TWL4030_BCI_BCICTL1);
707 if (ret) {
708 dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
709 TWL4030_BCI_BCICTL1);
710 return ret;
711 }
Sebastian Reichel99be0242014-03-16 02:43:27 +0100712
713 regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
Keerthyf99c1d42011-03-01 19:12:26 +0530714 if (on)
Sebastian Reichel99be0242014-03-16 02:43:27 +0100715 regval |= regmask;
Keerthyf99c1d42011-03-01 19:12:26 +0530716 else
Sebastian Reichel99be0242014-03-16 02:43:27 +0100717 regval &= ~regmask;
718
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100719 ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530720 regval, TWL4030_BCI_BCICTL1);
721 if (ret) {
722 dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
723 TWL4030_BCI_BCICTL1);
724 return ret;
725 }
726
727 return 0;
728}
729
730/*
731 * Function that sets MADC software power on bit to enable MADC
732 * @madc - pointer to twl4030_madc_data struct
Sebastian Reichel99be0242014-03-16 02:43:27 +0100733 * @on - Enable or disable MADC software power on bit.
Keerthyf99c1d42011-03-01 19:12:26 +0530734 * returns error if i2c read/write fails else 0
735 */
736static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
737{
738 u8 regval;
739 int ret;
740
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100741 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530742 &regval, TWL4030_MADC_CTRL1);
743 if (ret) {
744 dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
745 TWL4030_MADC_CTRL1);
746 return ret;
747 }
748 if (on)
749 regval |= TWL4030_MADC_MADCON;
750 else
751 regval &= ~TWL4030_MADC_MADCON;
752 ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
753 if (ret) {
754 dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
755 TWL4030_MADC_CTRL1);
756 return ret;
757 }
758
759 return 0;
760}
761
762/*
763 * Initialize MADC and request for threaded irq
764 */
Bill Pembertonf791be42012-11-19 13:23:04 -0500765static int twl4030_madc_probe(struct platform_device *pdev)
Keerthyf99c1d42011-03-01 19:12:26 +0530766{
767 struct twl4030_madc_data *madc;
Jingoo Han334a41ce2013-07-30 17:10:05 +0900768 struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100769 struct device_node *np = pdev->dev.of_node;
Sebastian Reichele7f22b72014-03-16 02:43:25 +0100770 int irq, ret;
Keerthyf99c1d42011-03-01 19:12:26 +0530771 u8 regval;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100772 struct iio_dev *iio_dev = NULL;
Keerthyf99c1d42011-03-01 19:12:26 +0530773
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100774 if (!pdata && !np) {
775 dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n");
Keerthyf99c1d42011-03-01 19:12:26 +0530776 return -EINVAL;
777 }
Keerthyf99c1d42011-03-01 19:12:26 +0530778
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100779 iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc));
780 if (!iio_dev) {
781 dev_err(&pdev->dev, "failed allocating iio device\n");
782 return -ENOMEM;
783 }
784
785 madc = iio_priv(iio_dev);
Kyle Manna66cc5b82011-08-11 22:33:12 -0500786 madc->dev = &pdev->dev;
787
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100788 iio_dev->name = dev_name(&pdev->dev);
789 iio_dev->dev.parent = &pdev->dev;
790 iio_dev->dev.of_node = pdev->dev.of_node;
791 iio_dev->info = &twl4030_madc_iio_info;
792 iio_dev->modes = INDIO_DIRECT_MODE;
793 iio_dev->channels = twl4030_madc_iio_channels;
794 iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels);
795
Keerthyf99c1d42011-03-01 19:12:26 +0530796 /*
797 * Phoenix provides 2 interrupt lines. The first one is connected to
798 * the OMAP. The other one can be connected to the other processor such
799 * as modem. Hence two separate ISR and IMR registers.
800 */
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100801 if (pdata)
802 madc->use_second_irq = (pdata->irq_line != 1);
803 else
804 madc->use_second_irq = of_property_read_bool(np,
805 "ti,system-uses-second-madc-irq");
806
807 madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 :
808 TWL4030_MADC_IMR1;
809 madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 :
810 TWL4030_MADC_ISR1;
811
Keerthyf99c1d42011-03-01 19:12:26 +0530812 ret = twl4030_madc_set_power(madc, 1);
813 if (ret < 0)
Sebastian Reichele7f22b72014-03-16 02:43:25 +0100814 return ret;
Keerthyf99c1d42011-03-01 19:12:26 +0530815 ret = twl4030_madc_set_current_generator(madc, 0, 1);
816 if (ret < 0)
817 goto err_current_generator;
818
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100819 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530820 &regval, TWL4030_BCI_BCICTL1);
821 if (ret) {
822 dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
823 TWL4030_BCI_BCICTL1);
824 goto err_i2c;
825 }
826 regval |= TWL4030_BCI_MESBAT;
Peter Ujfalusie45342f2012-11-13 09:28:51 +0100827 ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
Keerthyf99c1d42011-03-01 19:12:26 +0530828 regval, TWL4030_BCI_BCICTL1);
829 if (ret) {
830 dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
831 TWL4030_BCI_BCICTL1);
832 goto err_i2c;
833 }
Kyle Manna3d6271f2011-08-11 22:33:13 -0500834
835 /* Check that MADC clock is on */
836 ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
837 if (ret) {
838 dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
839 TWL4030_REG_GPBR1);
840 goto err_i2c;
841 }
842
843 /* If MADC clk is not on, turn it on */
844 if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
845 dev_info(&pdev->dev, "clk disabled, enabling\n");
846 regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
847 ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
848 TWL4030_REG_GPBR1);
849 if (ret) {
850 dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
851 TWL4030_REG_GPBR1);
852 goto err_i2c;
853 }
854 }
855
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100856 platform_set_drvdata(pdev, iio_dev);
Keerthyf99c1d42011-03-01 19:12:26 +0530857 mutex_init(&madc->lock);
Sebastian Reichele7f22b72014-03-16 02:43:25 +0100858
859 irq = platform_get_irq(pdev, 0);
860 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
Keerthyf99c1d42011-03-01 19:12:26 +0530861 twl4030_madc_threaded_irq_handler,
Fabio Estevam6c0d48c2015-05-24 17:39:04 -0300862 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
863 "twl4030_madc", madc);
Keerthyf99c1d42011-03-01 19:12:26 +0530864 if (ret) {
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100865 dev_err(&pdev->dev, "could not request irq\n");
Jingoo Hanc3d6a0a2013-05-06 13:08:08 +0900866 goto err_i2c;
Keerthyf99c1d42011-03-01 19:12:26 +0530867 }
868 twl4030_madc = madc;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100869
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700870 /* Configure MADC[3:6] */
871 ret = twl_i2c_read_u8(TWL_MODULE_USB, &regval,
872 TWL4030_USB_CARKIT_ANA_CTRL);
873 if (ret) {
874 dev_err(&pdev->dev, "unable to read reg CARKIT_ANA_CTRL 0x%X\n",
875 TWL4030_USB_CARKIT_ANA_CTRL);
876 goto err_i2c;
877 }
878 regval |= TWL4030_USB_SEL_MADC_MCPC;
879 ret = twl_i2c_write_u8(TWL_MODULE_USB, regval,
880 TWL4030_USB_CARKIT_ANA_CTRL);
881 if (ret) {
882 dev_err(&pdev->dev, "unable to write reg CARKIT_ANA_CTRL 0x%X\n",
883 TWL4030_USB_CARKIT_ANA_CTRL);
884 goto err_i2c;
885 }
886
887 /* Enable 3v1 bias regulator for MADC[3:6] */
888 madc->usb3v1 = devm_regulator_get(madc->dev, "vusb3v1");
Christophe JAILLET245a3962017-09-23 08:06:18 +0200889 if (IS_ERR(madc->usb3v1)) {
890 ret = -ENODEV;
891 goto err_i2c;
892 }
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700893
894 ret = regulator_enable(madc->usb3v1);
Christophe JAILLET53063842017-09-23 08:06:20 +0200895 if (ret) {
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700896 dev_err(madc->dev, "could not enable 3v1 bias regulator\n");
Christophe JAILLET53063842017-09-23 08:06:20 +0200897 goto err_i2c;
898 }
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700899
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100900 ret = iio_device_register(iio_dev);
901 if (ret) {
902 dev_err(&pdev->dev, "could not register iio device\n");
Christophe JAILLET7f70be6e2017-09-23 08:06:19 +0200903 goto err_usb3v1;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100904 }
905
Keerthyf99c1d42011-03-01 19:12:26 +0530906 return 0;
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100907
Christophe JAILLET7f70be6e2017-09-23 08:06:19 +0200908err_usb3v1:
909 regulator_disable(madc->usb3v1);
Keerthyf99c1d42011-03-01 19:12:26 +0530910err_i2c:
911 twl4030_madc_set_current_generator(madc, 0, 0);
912err_current_generator:
913 twl4030_madc_set_power(madc, 0);
Keerthyf99c1d42011-03-01 19:12:26 +0530914 return ret;
915}
916
Bill Pemberton4740f732012-11-19 13:26:01 -0500917static int twl4030_madc_remove(struct platform_device *pdev)
Keerthyf99c1d42011-03-01 19:12:26 +0530918{
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100919 struct iio_dev *iio_dev = platform_get_drvdata(pdev);
920 struct twl4030_madc_data *madc = iio_priv(iio_dev);
921
922 iio_device_unregister(iio_dev);
Keerthyf99c1d42011-03-01 19:12:26 +0530923
Keerthyf99c1d42011-03-01 19:12:26 +0530924 twl4030_madc_set_current_generator(madc, 0, 0);
925 twl4030_madc_set_power(madc, 0);
Keerthyf99c1d42011-03-01 19:12:26 +0530926
Adam YH Lee7cc97d72015-08-04 11:15:48 -0700927 regulator_disable(madc->usb3v1);
928
Keerthyf99c1d42011-03-01 19:12:26 +0530929 return 0;
930}
931
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100932#ifdef CONFIG_OF
933static const struct of_device_id twl_madc_of_match[] = {
934 { .compatible = "ti,twl4030-madc", },
935 { },
936};
937MODULE_DEVICE_TABLE(of, twl_madc_of_match);
938#endif
939
Keerthyf99c1d42011-03-01 19:12:26 +0530940static struct platform_driver twl4030_madc_driver = {
941 .probe = twl4030_madc_probe,
Arnd Bergmann03715412013-03-14 22:56:38 +0100942 .remove = twl4030_madc_remove,
Keerthyf99c1d42011-03-01 19:12:26 +0530943 .driver = {
944 .name = "twl4030_madc",
Sebastian Reichel2f39b702014-03-16 02:43:26 +0100945 .of_match_table = of_match_ptr(twl_madc_of_match),
Sebastian Reichel99be0242014-03-16 02:43:27 +0100946 },
Keerthyf99c1d42011-03-01 19:12:26 +0530947};
948
Mark Brown65349d62011-11-23 22:58:34 +0000949module_platform_driver(twl4030_madc_driver);
Keerthyf99c1d42011-03-01 19:12:26 +0530950
951MODULE_DESCRIPTION("TWL4030 ADC driver");
952MODULE_LICENSE("GPL");
953MODULE_AUTHOR("J Keerthy");
Axel Lin0ea3e832011-03-07 11:02:29 +0800954MODULE_ALIAS("platform:twl4030_madc");