Commit | Line | Data |
---|---|---|
5e53a69b PR |
1 | /* |
2 | * TI ADC MFD driver | |
3 | * | |
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License as | |
8 | * published by the Free Software Foundation version 2. | |
9 | * | |
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
11 | * kind, whether express or implied; without even the implied warranty | |
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | */ | |
15 | ||
5e53a69b PR |
16 | #include <linux/kernel.h> |
17 | #include <linux/err.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/slab.h> | |
20 | #include <linux/interrupt.h> | |
21 | #include <linux/platform_device.h> | |
22 | #include <linux/io.h> | |
23 | #include <linux/iio/iio.h> | |
6f39ac4e PR |
24 | #include <linux/of.h> |
25 | #include <linux/of_device.h> | |
c80df483 PA |
26 | #include <linux/iio/machine.h> |
27 | #include <linux/iio/driver.h> | |
5e53a69b PR |
28 | |
29 | #include <linux/mfd/ti_am335x_tscadc.h> | |
ca9a5638 ZL |
30 | #include <linux/iio/buffer.h> |
31 | #include <linux/iio/kfifo_buf.h> | |
5e53a69b PR |
32 | |
33 | struct tiadc_device { | |
34 | struct ti_tscadc_dev *mfd_tscadc; | |
90c43ec6 | 35 | struct mutex fifo1_lock; /* to protect fifo access */ |
5e53a69b | 36 | int channels; |
18926ede SAS |
37 | u8 channel_line[8]; |
38 | u8 channel_step[8]; | |
ca9a5638 | 39 | int buffer_en_ch_steps; |
ca9a5638 | 40 | u16 data[8]; |
5dc11e81 | 41 | u32 open_delay[8], sample_delay[8], step_avg[8]; |
5e53a69b PR |
42 | }; |
43 | ||
44 | static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) | |
45 | { | |
46 | return readl(adc->mfd_tscadc->tscadc_base + reg); | |
47 | } | |
48 | ||
49 | static void tiadc_writel(struct tiadc_device *adc, unsigned int reg, | |
50 | unsigned int val) | |
51 | { | |
52 | writel(val, adc->mfd_tscadc->tscadc_base + reg); | |
53 | } | |
54 | ||
abeccee4 PR |
55 | static u32 get_adc_step_mask(struct tiadc_device *adc_dev) |
56 | { | |
57 | u32 step_en; | |
58 | ||
59 | step_en = ((1 << adc_dev->channels) - 1); | |
60 | step_en <<= TOTAL_STEPS - adc_dev->channels + 1; | |
61 | return step_en; | |
62 | } | |
63 | ||
7ca6740c SAS |
64 | static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev, |
65 | struct iio_chan_spec const *chan) | |
66 | { | |
67 | int i; | |
68 | ||
69 | for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) { | |
70 | if (chan->channel == adc_dev->channel_line[i]) { | |
71 | u32 step; | |
72 | ||
73 | step = adc_dev->channel_step[i]; | |
74 | /* +1 for the charger */ | |
75 | return 1 << (step + 1); | |
76 | } | |
77 | } | |
78 | WARN_ON(1); | |
79 | return 0; | |
80 | } | |
81 | ||
ca9a5638 | 82 | static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) |
5e53a69b | 83 | { |
ca9a5638 ZL |
84 | return 1 << adc_dev->channel_step[chan]; |
85 | } | |
86 | ||
87 | static void tiadc_step_config(struct iio_dev *indio_dev) | |
88 | { | |
89 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
5dc11e81 | 90 | struct device *dev = adc_dev->mfd_tscadc->dev; |
5e53a69b | 91 | unsigned int stepconfig; |
3a59684c | 92 | int i, steps = 0; |
5e53a69b PR |
93 | |
94 | /* | |
95 | * There are 16 configurable steps and 8 analog input | |
96 | * lines available which are shared between Touchscreen and ADC. | |
97 | * | |
3a59684c | 98 | * Steps forwards i.e. from 0 towards 16 are used by ADC |
5e53a69b PR |
99 | * depending on number of input lines needed. |
100 | * Channel would represent which analog input | |
101 | * needs to be given to ADC to digitalize data. | |
102 | */ | |
103 | ||
5e53a69b | 104 | |
18926ede SAS |
105 | for (i = 0; i < adc_dev->channels; i++) { |
106 | int chan; | |
107 | ||
108 | chan = adc_dev->channel_line[i]; | |
5dc11e81 V |
109 | |
110 | if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) { | |
111 | dev_warn(dev, "chan %d step_avg truncating to %d\n", | |
112 | chan, STEPCONFIG_AVG_16); | |
113 | adc_dev->step_avg[i] = STEPCONFIG_AVG_16; | |
114 | } | |
115 | ||
116 | if (adc_dev->step_avg[i]) | |
117 | stepconfig = | |
118 | STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | | |
119 | STEPCONFIG_FIFO1; | |
120 | else | |
121 | stepconfig = STEPCONFIG_FIFO1; | |
122 | ||
123 | if (iio_buffer_enabled(indio_dev)) | |
124 | stepconfig |= STEPCONFIG_MODE_SWCNT; | |
125 | ||
18926ede SAS |
126 | tiadc_writel(adc_dev, REG_STEPCONFIG(steps), |
127 | stepconfig | STEPCONFIG_INP(chan)); | |
5dc11e81 V |
128 | |
129 | if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) { | |
130 | dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n", | |
131 | chan); | |
132 | adc_dev->open_delay[i] = STEPDELAY_OPEN_MASK; | |
133 | } | |
134 | ||
135 | if (adc_dev->sample_delay[i] > 0xFF) { | |
136 | dev_warn(dev, "chan %d sample delay truncating to 0xFF\n", | |
137 | chan); | |
138 | adc_dev->sample_delay[i] = 0xFF; | |
139 | } | |
140 | ||
18926ede | 141 | tiadc_writel(adc_dev, REG_STEPDELAY(steps), |
5dc11e81 V |
142 | STEPDELAY_OPEN(adc_dev->open_delay[i]) | |
143 | STEPDELAY_SAMPLE(adc_dev->sample_delay[i])); | |
144 | ||
18926ede SAS |
145 | adc_dev->channel_step[i] = steps; |
146 | steps++; | |
5e53a69b | 147 | } |
ca9a5638 ZL |
148 | } |
149 | ||
150 | static irqreturn_t tiadc_irq_h(int irq, void *private) | |
151 | { | |
152 | struct iio_dev *indio_dev = private; | |
153 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
154 | unsigned int status, config; | |
155 | status = tiadc_readl(adc_dev, REG_IRQSTATUS); | |
156 | ||
157 | /* | |
158 | * ADC and touchscreen share the IRQ line. | |
159 | * FIFO0 interrupts are used by TSC. Handle FIFO1 IRQs here only | |
160 | */ | |
161 | if (status & IRQENB_FIFO1OVRRUN) { | |
162 | /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */ | |
163 | config = tiadc_readl(adc_dev, REG_CTRL); | |
164 | config &= ~(CNTRLREG_TSCSSENB); | |
165 | tiadc_writel(adc_dev, REG_CTRL, config); | |
166 | tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN | |
167 | | IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES); | |
168 | tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB)); | |
169 | return IRQ_HANDLED; | |
170 | } else if (status & IRQENB_FIFO1THRES) { | |
171 | /* Disable irq and wake worker thread */ | |
172 | tiadc_writel(adc_dev, REG_IRQCLR, IRQENB_FIFO1THRES); | |
173 | return IRQ_WAKE_THREAD; | |
174 | } | |
175 | ||
176 | return IRQ_NONE; | |
177 | } | |
178 | ||
179 | static irqreturn_t tiadc_worker_h(int irq, void *private) | |
180 | { | |
181 | struct iio_dev *indio_dev = private; | |
182 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
183 | int i, k, fifo1count, read; | |
184 | u16 *data = adc_dev->data; | |
185 | ||
186 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | |
187 | for (k = 0; k < fifo1count; k = k + i) { | |
188 | for (i = 0; i < (indio_dev->scan_bytes)/2; i++) { | |
189 | read = tiadc_readl(adc_dev, REG_FIFO1); | |
190 | data[i] = read & FIFOREAD_DATA_MASK; | |
191 | } | |
192 | iio_push_to_buffers(indio_dev, (u8 *) data); | |
193 | } | |
194 | ||
195 | tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES); | |
196 | tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); | |
197 | ||
198 | return IRQ_HANDLED; | |
199 | } | |
200 | ||
201 | static int tiadc_buffer_preenable(struct iio_dev *indio_dev) | |
202 | { | |
203 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
204 | int i, fifo1count, read; | |
205 | ||
206 | tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | | |
207 | IRQENB_FIFO1OVRRUN | | |
208 | IRQENB_FIFO1UNDRFLW)); | |
209 | ||
210 | /* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */ | |
211 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | |
212 | for (i = 0; i < fifo1count; i++) | |
213 | read = tiadc_readl(adc_dev, REG_FIFO1); | |
214 | ||
24adaf79 | 215 | return 0; |
ca9a5638 ZL |
216 | } |
217 | ||
218 | static int tiadc_buffer_postenable(struct iio_dev *indio_dev) | |
219 | { | |
220 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
ca9a5638 ZL |
221 | unsigned int enb = 0; |
222 | u8 bit; | |
223 | ||
224 | tiadc_step_config(indio_dev); | |
70dddeee | 225 | for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels) |
ca9a5638 ZL |
226 | enb |= (get_adc_step_bit(adc_dev, bit) << 1); |
227 | adc_dev->buffer_en_ch_steps = enb; | |
228 | ||
7e170c6e | 229 | am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb); |
ca9a5638 ZL |
230 | |
231 | tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES | |
232 | | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); | |
233 | tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES | |
234 | | IRQENB_FIFO1OVRRUN); | |
235 | ||
236 | return 0; | |
237 | } | |
238 | ||
239 | static int tiadc_buffer_predisable(struct iio_dev *indio_dev) | |
240 | { | |
241 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
242 | int fifo1count, i, read; | |
243 | ||
244 | tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | | |
245 | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW)); | |
246 | am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); | |
3954b7bf | 247 | adc_dev->buffer_en_ch_steps = 0; |
b1451e54 | 248 | |
ca9a5638 ZL |
249 | /* Flush FIFO of leftover data in the time it takes to disable adc */ |
250 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | |
251 | for (i = 0; i < fifo1count; i++) | |
252 | read = tiadc_readl(adc_dev, REG_FIFO1); | |
253 | ||
254 | return 0; | |
5e53a69b PR |
255 | } |
256 | ||
ca9a5638 ZL |
257 | static int tiadc_buffer_postdisable(struct iio_dev *indio_dev) |
258 | { | |
259 | tiadc_step_config(indio_dev); | |
260 | ||
261 | return 0; | |
262 | } | |
263 | ||
264 | static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = { | |
265 | .preenable = &tiadc_buffer_preenable, | |
266 | .postenable = &tiadc_buffer_postenable, | |
267 | .predisable = &tiadc_buffer_predisable, | |
268 | .postdisable = &tiadc_buffer_postdisable, | |
269 | }; | |
270 | ||
98c08cf4 | 271 | static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev, |
ca9a5638 ZL |
272 | irqreturn_t (*pollfunc_bh)(int irq, void *p), |
273 | irqreturn_t (*pollfunc_th)(int irq, void *p), | |
274 | int irq, | |
275 | unsigned long flags, | |
276 | const struct iio_buffer_setup_ops *setup_ops) | |
277 | { | |
fe26980e | 278 | struct iio_buffer *buffer; |
ca9a5638 ZL |
279 | int ret; |
280 | ||
7ab374a0 | 281 | buffer = iio_kfifo_allocate(); |
fe26980e | 282 | if (!buffer) |
ca9a5638 ZL |
283 | return -ENOMEM; |
284 | ||
fe26980e LPC |
285 | iio_device_attach_buffer(indio_dev, buffer); |
286 | ||
ca9a5638 ZL |
287 | ret = request_threaded_irq(irq, pollfunc_th, pollfunc_bh, |
288 | flags, indio_dev->name, indio_dev); | |
289 | if (ret) | |
290 | goto error_kfifo_free; | |
291 | ||
292 | indio_dev->setup_ops = setup_ops; | |
9d0be85d | 293 | indio_dev->modes |= INDIO_BUFFER_SOFTWARE; |
ca9a5638 | 294 | |
ca9a5638 ZL |
295 | return 0; |
296 | ||
ca9a5638 ZL |
297 | error_kfifo_free: |
298 | iio_kfifo_free(indio_dev->buffer); | |
299 | return ret; | |
300 | } | |
301 | ||
302 | static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev) | |
303 | { | |
304 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
305 | ||
306 | free_irq(adc_dev->mfd_tscadc->irq, indio_dev); | |
307 | iio_kfifo_free(indio_dev->buffer); | |
ca9a5638 ZL |
308 | } |
309 | ||
310 | ||
c80df483 PA |
311 | static const char * const chan_name_ain[] = { |
312 | "AIN0", | |
313 | "AIN1", | |
314 | "AIN2", | |
315 | "AIN3", | |
316 | "AIN4", | |
317 | "AIN5", | |
318 | "AIN6", | |
319 | "AIN7", | |
320 | }; | |
321 | ||
5e53a69b PR |
322 | static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) |
323 | { | |
c80df483 | 324 | struct tiadc_device *adc_dev = iio_priv(indio_dev); |
5e53a69b | 325 | struct iio_chan_spec *chan_array; |
c80df483 | 326 | struct iio_chan_spec *chan; |
5e53a69b PR |
327 | int i; |
328 | ||
329 | indio_dev->num_channels = channels; | |
fea89e2d | 330 | chan_array = kcalloc(channels, sizeof(*chan_array), GFP_KERNEL); |
5e53a69b PR |
331 | if (chan_array == NULL) |
332 | return -ENOMEM; | |
333 | ||
c80df483 PA |
334 | chan = chan_array; |
335 | for (i = 0; i < channels; i++, chan++) { | |
336 | ||
5e53a69b PR |
337 | chan->type = IIO_VOLTAGE; |
338 | chan->indexed = 1; | |
18926ede | 339 | chan->channel = adc_dev->channel_line[i]; |
6c572522 | 340 | chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); |
18926ede | 341 | chan->datasheet_name = chan_name_ain[chan->channel]; |
ca9a5638 | 342 | chan->scan_index = i; |
c80df483 PA |
343 | chan->scan_type.sign = 'u'; |
344 | chan->scan_type.realbits = 12; | |
0f6fc7d5 | 345 | chan->scan_type.storagebits = 16; |
5e53a69b PR |
346 | } |
347 | ||
348 | indio_dev->channels = chan_array; | |
349 | ||
c80df483 | 350 | return 0; |
5e53a69b PR |
351 | } |
352 | ||
353 | static void tiadc_channels_remove(struct iio_dev *indio_dev) | |
354 | { | |
355 | kfree(indio_dev->channels); | |
356 | } | |
357 | ||
358 | static int tiadc_read_raw(struct iio_dev *indio_dev, | |
359 | struct iio_chan_spec const *chan, | |
360 | int *val, int *val2, long mask) | |
361 | { | |
362 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
90c43ec6 | 363 | int ret = IIO_VAL_INT; |
b1451e54 PR |
364 | int i, map_val; |
365 | unsigned int fifo1count, read, stepid; | |
1460c152 | 366 | bool found = false; |
b1451e54 | 367 | u32 step_en; |
7ca6740c | 368 | unsigned long timeout; |
ca9a5638 ZL |
369 | |
370 | if (iio_buffer_enabled(indio_dev)) | |
371 | return -EBUSY; | |
372 | ||
7ca6740c SAS |
373 | step_en = get_adc_chan_step_mask(adc_dev, chan); |
374 | if (!step_en) | |
375 | return -EINVAL; | |
376 | ||
90c43ec6 | 377 | mutex_lock(&adc_dev->fifo1_lock); |
7ca6740c SAS |
378 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); |
379 | while (fifo1count--) | |
380 | tiadc_readl(adc_dev, REG_FIFO1); | |
381 | ||
7e170c6e | 382 | am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en); |
b1451e54 | 383 | |
7175cce1 | 384 | timeout = jiffies + msecs_to_jiffies |
7ca6740c SAS |
385 | (IDLE_TIMEOUT * adc_dev->channels); |
386 | /* Wait for Fifo threshold interrupt */ | |
387 | while (1) { | |
388 | fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); | |
389 | if (fifo1count) | |
390 | break; | |
391 | ||
392 | if (time_after(jiffies, timeout)) { | |
393 | am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); | |
90c43ec6 V |
394 | ret = -EAGAIN; |
395 | goto err_unlock; | |
b1451e54 | 396 | } |
fb7f8ce3 | 397 | } |
baa3c652 | 398 | map_val = adc_dev->channel_step[chan->scan_index]; |
5e53a69b PR |
399 | |
400 | /* | |
7ca6740c SAS |
401 | * We check the complete FIFO. We programmed just one entry but in case |
402 | * something went wrong we left empty handed (-EAGAIN previously) and | |
403 | * then the value apeared somehow in the FIFO we would have two entries. | |
404 | * Therefore we read every item and keep only the latest version of the | |
405 | * requested channel. | |
5e53a69b | 406 | */ |
5e53a69b | 407 | for (i = 0; i < fifo1count; i++) { |
18926ede | 408 | read = tiadc_readl(adc_dev, REG_FIFO1); |
b1451e54 PR |
409 | stepid = read & FIFOREAD_CHNLID_MASK; |
410 | stepid = stepid >> 0x10; | |
411 | ||
412 | if (stepid == map_val) { | |
413 | read = read & FIFOREAD_DATA_MASK; | |
1460c152 | 414 | found = true; |
0f6fc7d5 | 415 | *val = (u16) read; |
1460c152 | 416 | } |
5e53a69b | 417 | } |
7ca6740c | 418 | am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); |
b1451e54 | 419 | |
1460c152 | 420 | if (found == false) |
90c43ec6 V |
421 | ret = -EBUSY; |
422 | ||
423 | err_unlock: | |
424 | mutex_unlock(&adc_dev->fifo1_lock); | |
425 | return ret; | |
5e53a69b PR |
426 | } |
427 | ||
428 | static const struct iio_info tiadc_info = { | |
429 | .read_raw = &tiadc_read_raw, | |
bc93aa76 | 430 | .driver_module = THIS_MODULE, |
5e53a69b PR |
431 | }; |
432 | ||
dee1f550 V |
433 | static int tiadc_parse_dt(struct platform_device *pdev, |
434 | struct tiadc_device *adc_dev) | |
435 | { | |
436 | struct device_node *node = pdev->dev.of_node; | |
437 | struct property *prop; | |
438 | const __be32 *cur; | |
439 | int channels = 0; | |
440 | u32 val; | |
441 | ||
442 | of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { | |
443 | adc_dev->channel_line[channels] = val; | |
5dc11e81 V |
444 | |
445 | /* Set Default values for optional DT parameters */ | |
446 | adc_dev->open_delay[channels] = STEPCONFIG_OPENDLY; | |
447 | adc_dev->sample_delay[channels] = STEPCONFIG_SAMPLEDLY; | |
448 | adc_dev->step_avg[channels] = 16; | |
449 | ||
dee1f550 V |
450 | channels++; |
451 | } | |
452 | ||
5dc11e81 V |
453 | of_property_read_u32_array(node, "ti,chan-step-avg", |
454 | adc_dev->step_avg, channels); | |
455 | of_property_read_u32_array(node, "ti,chan-step-opendelay", | |
456 | adc_dev->open_delay, channels); | |
457 | of_property_read_u32_array(node, "ti,chan-step-sampledelay", | |
458 | adc_dev->sample_delay, channels); | |
459 | ||
dee1f550 V |
460 | adc_dev->channels = channels; |
461 | return 0; | |
462 | } | |
463 | ||
fc52692c | 464 | static int tiadc_probe(struct platform_device *pdev) |
5e53a69b PR |
465 | { |
466 | struct iio_dev *indio_dev; | |
467 | struct tiadc_device *adc_dev; | |
6f39ac4e | 468 | struct device_node *node = pdev->dev.of_node; |
5e53a69b PR |
469 | int err; |
470 | ||
0ead4fb2 SAS |
471 | if (!node) { |
472 | dev_err(&pdev->dev, "Could not find valid DT data.\n"); | |
5e53a69b PR |
473 | return -EINVAL; |
474 | } | |
475 | ||
fea89e2d | 476 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*indio_dev)); |
5e53a69b PR |
477 | if (indio_dev == NULL) { |
478 | dev_err(&pdev->dev, "failed to allocate iio device\n"); | |
a0648130 | 479 | return -ENOMEM; |
5e53a69b PR |
480 | } |
481 | adc_dev = iio_priv(indio_dev); | |
482 | ||
6f39ac4e | 483 | adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev); |
dee1f550 | 484 | tiadc_parse_dt(pdev, adc_dev); |
5e53a69b PR |
485 | |
486 | indio_dev->dev.parent = &pdev->dev; | |
487 | indio_dev->name = dev_name(&pdev->dev); | |
488 | indio_dev->modes = INDIO_DIRECT_MODE; | |
489 | indio_dev->info = &tiadc_info; | |
490 | ||
ca9a5638 ZL |
491 | tiadc_step_config(indio_dev); |
492 | tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD); | |
90c43ec6 | 493 | mutex_init(&adc_dev->fifo1_lock); |
5e53a69b PR |
494 | |
495 | err = tiadc_channel_init(indio_dev, adc_dev->channels); | |
496 | if (err < 0) | |
a0648130 | 497 | return err; |
5e53a69b | 498 | |
ca9a5638 ZL |
499 | err = tiadc_iio_buffered_hardware_setup(indio_dev, |
500 | &tiadc_worker_h, | |
501 | &tiadc_irq_h, | |
502 | adc_dev->mfd_tscadc->irq, | |
503 | IRQF_SHARED, | |
504 | &tiadc_buffer_setup_ops); | |
505 | ||
5e53a69b PR |
506 | if (err) |
507 | goto err_free_channels; | |
508 | ||
ca9a5638 ZL |
509 | err = iio_device_register(indio_dev); |
510 | if (err) | |
511 | goto err_buffer_unregister; | |
512 | ||
5e53a69b PR |
513 | platform_set_drvdata(pdev, indio_dev); |
514 | ||
515 | return 0; | |
516 | ||
ca9a5638 ZL |
517 | err_buffer_unregister: |
518 | tiadc_iio_buffered_hardware_remove(indio_dev); | |
5e53a69b PR |
519 | err_free_channels: |
520 | tiadc_channels_remove(indio_dev); | |
5e53a69b PR |
521 | return err; |
522 | } | |
523 | ||
fc52692c | 524 | static int tiadc_remove(struct platform_device *pdev) |
5e53a69b PR |
525 | { |
526 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | |
abeccee4 PR |
527 | struct tiadc_device *adc_dev = iio_priv(indio_dev); |
528 | u32 step_en; | |
5e53a69b PR |
529 | |
530 | iio_device_unregister(indio_dev); | |
ca9a5638 | 531 | tiadc_iio_buffered_hardware_remove(indio_dev); |
5e53a69b PR |
532 | tiadc_channels_remove(indio_dev); |
533 | ||
abeccee4 PR |
534 | step_en = get_adc_step_mask(adc_dev); |
535 | am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en); | |
536 | ||
5e53a69b PR |
537 | return 0; |
538 | } | |
539 | ||
27aa832d | 540 | static int __maybe_unused tiadc_suspend(struct device *dev) |
5e53a69b PR |
541 | { |
542 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
543 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
a9bce1b0 | 544 | struct ti_tscadc_dev *tscadc_dev; |
5e53a69b PR |
545 | unsigned int idle; |
546 | ||
a9bce1b0 | 547 | tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); |
5e53a69b PR |
548 | if (!device_may_wakeup(tscadc_dev->dev)) { |
549 | idle = tiadc_readl(adc_dev, REG_CTRL); | |
550 | idle &= ~(CNTRLREG_TSCSSENB); | |
551 | tiadc_writel(adc_dev, REG_CTRL, (idle | | |
552 | CNTRLREG_POWERDOWN)); | |
553 | } | |
554 | ||
555 | return 0; | |
556 | } | |
557 | ||
27aa832d | 558 | static int __maybe_unused tiadc_resume(struct device *dev) |
5e53a69b PR |
559 | { |
560 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
561 | struct tiadc_device *adc_dev = iio_priv(indio_dev); | |
562 | unsigned int restore; | |
563 | ||
564 | /* Make sure ADC is powered up */ | |
565 | restore = tiadc_readl(adc_dev, REG_CTRL); | |
566 | restore &= ~(CNTRLREG_POWERDOWN); | |
567 | tiadc_writel(adc_dev, REG_CTRL, restore); | |
568 | ||
ca9a5638 | 569 | tiadc_step_config(indio_dev); |
7ca6740c SAS |
570 | am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, |
571 | adc_dev->buffer_en_ch_steps); | |
5e53a69b PR |
572 | return 0; |
573 | } | |
574 | ||
27aa832d | 575 | static SIMPLE_DEV_PM_OPS(tiadc_pm_ops, tiadc_suspend, tiadc_resume); |
5e53a69b | 576 | |
6f39ac4e PR |
577 | static const struct of_device_id ti_adc_dt_ids[] = { |
578 | { .compatible = "ti,am3359-adc", }, | |
579 | { } | |
580 | }; | |
581 | MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); | |
582 | ||
5e53a69b PR |
583 | static struct platform_driver tiadc_driver = { |
584 | .driver = { | |
9f99928f | 585 | .name = "TI-am335x-adc", |
27aa832d | 586 | .pm = &tiadc_pm_ops, |
de06b344 | 587 | .of_match_table = ti_adc_dt_ids, |
5e53a69b PR |
588 | }, |
589 | .probe = tiadc_probe, | |
fc52692c | 590 | .remove = tiadc_remove, |
5e53a69b | 591 | }; |
5e53a69b PR |
592 | module_platform_driver(tiadc_driver); |
593 | ||
594 | MODULE_DESCRIPTION("TI ADC controller driver"); | |
595 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | |
596 | MODULE_LICENSE("GPL"); |