1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * palmas-adc.c -- TI PALMAS GPADC. |
4 | * |
5 | * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. |
6 | * |
7 | * Author: Pradeep Goudagunta <pgoudagunta@nvidia.com> |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/err.h> |
12 | #include <linux/irq.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/delay.h> |
17 | #include <linux/pm.h> |
18 | #include <linux/mfd/palmas.h> |
19 | #include <linux/completion.h> |
20 | #include <linux/of.h> |
21 | #include <linux/iio/events.h> |
22 | #include <linux/iio/iio.h> |
23 | #include <linux/iio/machine.h> |
24 | #include <linux/iio/driver.h> |
25 | |
26 | #define MOD_NAME "palmas-gpadc" |
27 | #define PALMAS_ADC_CONVERSION_TIMEOUT (msecs_to_jiffies(5000)) |
28 | #define PALMAS_TO_BE_CALCULATED 0 |
29 | #define PALMAS_GPADC_TRIMINVALID -1 |
30 | |
31 | struct palmas_gpadc_info { |
32 | /* calibration codes and regs */ |
33 | int x1; /* lower ideal code */ |
34 | int x2; /* higher ideal code */ |
35 | int v1; /* expected lower volt reading */ |
36 | int v2; /* expected higher volt reading */ |
37 | u8 trim1_reg; /* register number for lower trim */ |
38 | u8 trim2_reg; /* register number for upper trim */ |
39 | int gain; /* calculated from above (after reading trim regs) */ |
40 | int offset; /* calculated from above (after reading trim regs) */ |
41 | int gain_error; /* calculated from above (after reading trim regs) */ |
42 | bool is_uncalibrated; /* if channel has calibration data */ |
43 | }; |
44 | |
45 | #define PALMAS_ADC_INFO(_chan, _x1, _x2, _v1, _v2, _t1, _t2, _is_uncalibrated) \ |
46 | [PALMAS_ADC_CH_##_chan] = { \ |
47 | .x1 = _x1, \ |
48 | .x2 = _x2, \ |
49 | .v1 = _v1, \ |
50 | .v2 = _v2, \ |
51 | .gain = PALMAS_TO_BE_CALCULATED, \ |
52 | .offset = PALMAS_TO_BE_CALCULATED, \ |
53 | .gain_error = PALMAS_TO_BE_CALCULATED, \ |
54 | .trim1_reg = PALMAS_GPADC_TRIM##_t1, \ |
55 | .trim2_reg = PALMAS_GPADC_TRIM##_t2, \ |
56 | .is_uncalibrated = _is_uncalibrated \ |
57 | } |
58 | |
59 | static struct palmas_gpadc_info palmas_gpadc_info[] = { |
60 | PALMAS_ADC_INFO(IN0, 2064, 3112, 630, 950, 1, 2, false), |
61 | PALMAS_ADC_INFO(IN1, 2064, 3112, 630, 950, 1, 2, false), |
62 | PALMAS_ADC_INFO(IN2, 2064, 3112, 1260, 1900, 3, 4, false), |
63 | PALMAS_ADC_INFO(IN3, 2064, 3112, 630, 950, 1, 2, false), |
64 | PALMAS_ADC_INFO(IN4, 2064, 3112, 630, 950, 1, 2, false), |
65 | PALMAS_ADC_INFO(IN5, 2064, 3112, 630, 950, 1, 2, false), |
66 | PALMAS_ADC_INFO(IN6, 2064, 3112, 2520, 3800, 5, 6, false), |
67 | PALMAS_ADC_INFO(IN7, 2064, 3112, 2520, 3800, 7, 8, false), |
68 | PALMAS_ADC_INFO(IN8, 2064, 3112, 3150, 4750, 9, 10, false), |
69 | PALMAS_ADC_INFO(IN9, 2064, 3112, 5670, 8550, 11, 12, false), |
70 | PALMAS_ADC_INFO(IN10, 2064, 3112, 3465, 5225, 13, 14, false), |
71 | PALMAS_ADC_INFO(IN11, 0, 0, 0, 0, INVALID, INVALID, true), |
72 | PALMAS_ADC_INFO(IN12, 0, 0, 0, 0, INVALID, INVALID, true), |
73 | PALMAS_ADC_INFO(IN13, 0, 0, 0, 0, INVALID, INVALID, true), |
74 | PALMAS_ADC_INFO(IN14, 2064, 3112, 3645, 5225, 15, 16, false), |
75 | PALMAS_ADC_INFO(IN15, 0, 0, 0, 0, INVALID, INVALID, true), |
76 | }; |
77 | |
78 | struct palmas_adc_event { |
79 | bool enabled; |
80 | int channel; |
81 | enum iio_event_direction direction; |
82 | }; |
83 | |
84 | struct palmas_gpadc_thresholds { |
85 | int high; |
86 | int low; |
87 | }; |
88 | |
89 | /* |
90 | * struct palmas_gpadc - the palmas_gpadc structure |
91 | * @ch0_current: channel 0 current source setting |
92 | * 0: 0 uA |
93 | * 1: 5 uA |
94 | * 2: 15 uA |
95 | * 3: 20 uA |
96 | * @ch3_current: channel 0 current source setting |
97 | * 0: 0 uA |
98 | * 1: 10 uA |
99 | * 2: 400 uA |
100 | * 3: 800 uA |
101 | * @extended_delay: enable the gpadc extended delay mode |
102 | * @auto_conversion_period: define the auto_conversion_period |
103 | * @lock: Lock to protect the device state during a potential concurrent |
104 | * read access from userspace. Reading a raw value requires a sequence |
105 | * of register writes, then a wait for a completion callback, |
106 | * and finally a register read, during which userspace could issue |
107 | * another read request. This lock protects a read access from |
108 | * ocurring before another one has finished. |
109 | * |
110 | * This is the palmas_gpadc structure to store run-time information |
111 | * and pointers for this driver instance. |
112 | */ |
113 | struct palmas_gpadc { |
114 | struct device *dev; |
115 | struct palmas *palmas; |
116 | u8 ch0_current; |
117 | u8 ch3_current; |
118 | bool extended_delay; |
119 | int irq; |
120 | int irq_auto_0; |
121 | int irq_auto_1; |
122 | struct palmas_gpadc_info *adc_info; |
123 | struct completion conv_completion; |
124 | struct palmas_adc_event event0; |
125 | struct palmas_adc_event event1; |
126 | struct palmas_gpadc_thresholds thresholds[PALMAS_ADC_CH_MAX]; |
127 | int auto_conversion_period; |
128 | struct mutex lock; |
129 | }; |
130 | |
131 | static struct palmas_adc_event *palmas_gpadc_get_event(struct palmas_gpadc *adc, |
132 | int adc_chan, |
133 | enum iio_event_direction dir) |
134 | { |
135 | if (adc_chan == adc->event0.channel && dir == adc->event0.direction) |
136 | return &adc->event0; |
137 | |
138 | if (adc_chan == adc->event1.channel && dir == adc->event1.direction) |
139 | return &adc->event1; |
140 | |
141 | return NULL; |
142 | } |
143 | |
144 | static bool palmas_gpadc_channel_is_freerunning(struct palmas_gpadc *adc, |
145 | int adc_chan) |
146 | { |
147 | return palmas_gpadc_get_event(adc, adc_chan, dir: IIO_EV_DIR_RISING) || |
148 | palmas_gpadc_get_event(adc, adc_chan, dir: IIO_EV_DIR_FALLING); |
149 | } |
150 | |
151 | /* |
152 | * GPADC lock issue in AUTO mode. |
153 | * Impact: In AUTO mode, GPADC conversion can be locked after disabling AUTO |
154 | * mode feature. |
155 | * Details: |
156 | * When the AUTO mode is the only conversion mode enabled, if the AUTO |
157 | * mode feature is disabled with bit GPADC_AUTO_CTRL. AUTO_CONV1_EN = 0 |
158 | * or bit GPADC_AUTO_CTRL. AUTO_CONV0_EN = 0 during a conversion, the |
159 | * conversion mechanism can be seen as locked meaning that all following |
160 | * conversion will give 0 as a result. Bit GPADC_STATUS.GPADC_AVAILABLE |
161 | * will stay at 0 meaning that GPADC is busy. An RT conversion can unlock |
162 | * the GPADC. |
163 | * |
164 | * Workaround(s): |
165 | * To avoid the lock mechanism, the workaround to follow before any stop |
166 | * conversion request is: |
167 | * Force the GPADC state machine to be ON by using the GPADC_CTRL1. |
168 | * GPADC_FORCE bit = 1 |
169 | * Shutdown the GPADC AUTO conversion using |
170 | * GPADC_AUTO_CTRL.SHUTDOWN_CONV[01] = 0. |
171 | * After 100us, force the GPADC state machine to be OFF by using the |
172 | * GPADC_CTRL1. GPADC_FORCE bit = 0 |
173 | */ |
174 | |
175 | static int palmas_disable_auto_conversion(struct palmas_gpadc *adc) |
176 | { |
177 | int ret; |
178 | |
179 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
180 | PALMAS_GPADC_CTRL1, |
181 | PALMAS_GPADC_CTRL1_GPADC_FORCE, |
182 | PALMAS_GPADC_CTRL1_GPADC_FORCE); |
183 | if (ret < 0) { |
184 | dev_err(adc->dev, "GPADC_CTRL1 update failed: %d\n" , ret); |
185 | return ret; |
186 | } |
187 | |
188 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
189 | PALMAS_GPADC_AUTO_CTRL, |
190 | PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1 | |
191 | PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0, |
192 | val: 0); |
193 | if (ret < 0) { |
194 | dev_err(adc->dev, "AUTO_CTRL update failed: %d\n" , ret); |
195 | return ret; |
196 | } |
197 | |
198 | udelay(100); |
199 | |
200 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
201 | PALMAS_GPADC_CTRL1, |
202 | PALMAS_GPADC_CTRL1_GPADC_FORCE, val: 0); |
203 | if (ret < 0) |
204 | dev_err(adc->dev, "GPADC_CTRL1 update failed: %d\n" , ret); |
205 | |
206 | return ret; |
207 | } |
208 | |
209 | static irqreturn_t palmas_gpadc_irq(int irq, void *data) |
210 | { |
211 | struct palmas_gpadc *adc = data; |
212 | |
213 | complete(&adc->conv_completion); |
214 | |
215 | return IRQ_HANDLED; |
216 | } |
217 | |
218 | static irqreturn_t palmas_gpadc_irq_auto(int irq, void *data) |
219 | { |
220 | struct iio_dev *indio_dev = data; |
221 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
222 | struct palmas_adc_event *ev; |
223 | |
224 | dev_dbg(adc->dev, "Threshold interrupt %d occurs\n" , irq); |
225 | palmas_disable_auto_conversion(adc); |
226 | |
227 | ev = (irq == adc->irq_auto_0) ? &adc->event0 : &adc->event1; |
228 | if (ev->channel != -1) { |
229 | enum iio_event_direction dir; |
230 | u64 code; |
231 | |
232 | dir = ev->direction; |
233 | code = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, ev->channel, |
234 | IIO_EV_TYPE_THRESH, dir); |
235 | iio_push_event(indio_dev, ev_code: code, timestamp: iio_get_time_ns(indio_dev)); |
236 | } |
237 | |
238 | return IRQ_HANDLED; |
239 | } |
240 | |
241 | static int palmas_gpadc_start_mask_interrupt(struct palmas_gpadc *adc, |
242 | bool mask) |
243 | { |
244 | int ret; |
245 | |
246 | if (!mask) |
247 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_INTERRUPT_BASE, |
248 | PALMAS_INT3_MASK, |
249 | PALMAS_INT3_MASK_GPADC_EOC_SW, val: 0); |
250 | else |
251 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_INTERRUPT_BASE, |
252 | PALMAS_INT3_MASK, |
253 | PALMAS_INT3_MASK_GPADC_EOC_SW, |
254 | PALMAS_INT3_MASK_GPADC_EOC_SW); |
255 | if (ret < 0) |
256 | dev_err(adc->dev, "GPADC INT MASK update failed: %d\n" , ret); |
257 | |
258 | return ret; |
259 | } |
260 | |
261 | static int palmas_gpadc_enable(struct palmas_gpadc *adc, int adc_chan, |
262 | int enable) |
263 | { |
264 | unsigned int mask, val; |
265 | int ret; |
266 | |
267 | if (enable) { |
268 | val = (adc->extended_delay |
269 | << PALMAS_GPADC_RT_CTRL_EXTEND_DELAY_SHIFT); |
270 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
271 | PALMAS_GPADC_RT_CTRL, |
272 | PALMAS_GPADC_RT_CTRL_EXTEND_DELAY, val); |
273 | if (ret < 0) { |
274 | dev_err(adc->dev, "RT_CTRL update failed: %d\n" , ret); |
275 | return ret; |
276 | } |
277 | |
278 | mask = (PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_MASK | |
279 | PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK | |
280 | PALMAS_GPADC_CTRL1_GPADC_FORCE); |
281 | val = (adc->ch0_current |
282 | << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT); |
283 | val |= (adc->ch3_current |
284 | << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT); |
285 | val |= PALMAS_GPADC_CTRL1_GPADC_FORCE; |
286 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
287 | PALMAS_GPADC_CTRL1, mask, val); |
288 | if (ret < 0) { |
289 | dev_err(adc->dev, |
290 | "Failed to update current setting: %d\n" , ret); |
291 | return ret; |
292 | } |
293 | |
294 | mask = (PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_MASK | |
295 | PALMAS_GPADC_SW_SELECT_SW_CONV_EN); |
296 | val = (adc_chan | PALMAS_GPADC_SW_SELECT_SW_CONV_EN); |
297 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
298 | PALMAS_GPADC_SW_SELECT, mask, val); |
299 | if (ret < 0) { |
300 | dev_err(adc->dev, "SW_SELECT update failed: %d\n" , ret); |
301 | return ret; |
302 | } |
303 | } else { |
304 | ret = palmas_write(palmas: adc->palmas, PALMAS_GPADC_BASE, |
305 | PALMAS_GPADC_SW_SELECT, value: 0); |
306 | if (ret < 0) |
307 | dev_err(adc->dev, "SW_SELECT write failed: %d\n" , ret); |
308 | |
309 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
310 | PALMAS_GPADC_CTRL1, |
311 | PALMAS_GPADC_CTRL1_GPADC_FORCE, val: 0); |
312 | if (ret < 0) { |
313 | dev_err(adc->dev, "CTRL1 update failed: %d\n" , ret); |
314 | return ret; |
315 | } |
316 | } |
317 | |
318 | return ret; |
319 | } |
320 | |
321 | static int palmas_gpadc_read_prepare(struct palmas_gpadc *adc, int adc_chan) |
322 | { |
323 | int ret; |
324 | |
325 | if (palmas_gpadc_channel_is_freerunning(adc, adc_chan)) |
326 | return 0; /* ADC already running */ |
327 | |
328 | ret = palmas_gpadc_enable(adc, adc_chan, enable: true); |
329 | if (ret < 0) |
330 | return ret; |
331 | |
332 | return palmas_gpadc_start_mask_interrupt(adc, mask: 0); |
333 | } |
334 | |
335 | static void palmas_gpadc_read_done(struct palmas_gpadc *adc, int adc_chan) |
336 | { |
337 | palmas_gpadc_start_mask_interrupt(adc, mask: 1); |
338 | palmas_gpadc_enable(adc, adc_chan, enable: false); |
339 | } |
340 | |
341 | static int palmas_gpadc_calibrate(struct palmas_gpadc *adc, int adc_chan) |
342 | { |
343 | int k; |
344 | int d1; |
345 | int d2; |
346 | int ret; |
347 | int gain; |
348 | int x1 = adc->adc_info[adc_chan].x1; |
349 | int x2 = adc->adc_info[adc_chan].x2; |
350 | int v1 = adc->adc_info[adc_chan].v1; |
351 | int v2 = adc->adc_info[adc_chan].v2; |
352 | |
353 | ret = palmas_read(palmas: adc->palmas, PALMAS_TRIM_GPADC_BASE, |
354 | reg: adc->adc_info[adc_chan].trim1_reg, val: &d1); |
355 | if (ret < 0) { |
356 | dev_err(adc->dev, "TRIM read failed: %d\n" , ret); |
357 | goto scrub; |
358 | } |
359 | |
360 | ret = palmas_read(palmas: adc->palmas, PALMAS_TRIM_GPADC_BASE, |
361 | reg: adc->adc_info[adc_chan].trim2_reg, val: &d2); |
362 | if (ret < 0) { |
363 | dev_err(adc->dev, "TRIM read failed: %d\n" , ret); |
364 | goto scrub; |
365 | } |
366 | |
367 | /* gain error calculation */ |
368 | k = (1000 + (1000 * (d2 - d1)) / (x2 - x1)); |
369 | |
370 | /* gain calculation */ |
371 | gain = ((v2 - v1) * 1000) / (x2 - x1); |
372 | |
373 | adc->adc_info[adc_chan].gain_error = k; |
374 | adc->adc_info[adc_chan].gain = gain; |
375 | /* offset Calculation */ |
376 | adc->adc_info[adc_chan].offset = (d1 * 1000) - ((k - 1000) * x1); |
377 | |
378 | scrub: |
379 | return ret; |
380 | } |
381 | |
382 | static int palmas_gpadc_start_conversion(struct palmas_gpadc *adc, int adc_chan) |
383 | { |
384 | unsigned int val; |
385 | int ret; |
386 | |
387 | if (palmas_gpadc_channel_is_freerunning(adc, adc_chan)) { |
388 | int event = (adc_chan == adc->event0.channel) ? 0 : 1; |
389 | unsigned int reg = (event == 0) ? |
390 | PALMAS_GPADC_AUTO_CONV0_LSB : |
391 | PALMAS_GPADC_AUTO_CONV1_LSB; |
392 | |
393 | ret = palmas_bulk_read(palmas: adc->palmas, PALMAS_GPADC_BASE, |
394 | reg, val: &val, val_count: 2); |
395 | if (ret < 0) { |
396 | dev_err(adc->dev, "AUTO_CONV%x_LSB read failed: %d\n" , |
397 | event, ret); |
398 | return ret; |
399 | } |
400 | } else { |
401 | init_completion(x: &adc->conv_completion); |
402 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
403 | PALMAS_GPADC_SW_SELECT, |
404 | PALMAS_GPADC_SW_SELECT_SW_START_CONV0, |
405 | PALMAS_GPADC_SW_SELECT_SW_START_CONV0); |
406 | if (ret < 0) { |
407 | dev_err(adc->dev, "SELECT_SW_START write failed: %d\n" , ret); |
408 | return ret; |
409 | } |
410 | |
411 | ret = wait_for_completion_timeout(x: &adc->conv_completion, |
412 | PALMAS_ADC_CONVERSION_TIMEOUT); |
413 | if (ret == 0) { |
414 | dev_err(adc->dev, "conversion not completed\n" ); |
415 | return -ETIMEDOUT; |
416 | } |
417 | |
418 | ret = palmas_bulk_read(palmas: adc->palmas, PALMAS_GPADC_BASE, |
419 | PALMAS_GPADC_SW_CONV0_LSB, val: &val, val_count: 2); |
420 | if (ret < 0) { |
421 | dev_err(adc->dev, "SW_CONV0_LSB read failed: %d\n" , ret); |
422 | return ret; |
423 | } |
424 | } |
425 | |
426 | ret = val & 0xFFF; |
427 | |
428 | return ret; |
429 | } |
430 | |
431 | static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, |
432 | int adc_chan, int val) |
433 | { |
434 | if (!adc->adc_info[adc_chan].is_uncalibrated) |
435 | val = (val*1000 - adc->adc_info[adc_chan].offset) / |
436 | adc->adc_info[adc_chan].gain_error; |
437 | |
438 | if (val < 0) { |
439 | if (val < -10) |
440 | dev_err(adc->dev, "Mismatch with calibration var = %d\n" , val); |
441 | return 0; |
442 | } |
443 | |
444 | val = (val * adc->adc_info[adc_chan].gain) / 1000; |
445 | |
446 | return val; |
447 | } |
448 | |
449 | /* |
450 | * The high and low threshold values are calculated based on the advice given |
451 | * in TI Application Report SLIA087A, "Guide to Using the GPADC in PS65903x, |
452 | * TPS65917-Q1, TPS65919-Q1, and TPS65916 Devices". This document recommend |
453 | * taking ADC tolerances into account and is based on the device integral non- |
454 | * linearity (INL), offset error and gain error: |
455 | * |
456 | * raw high threshold = (ideal threshold + INL) * gain error + offset error |
457 | * |
458 | * The gain error include both gain error, as specified in the datasheet, and |
459 | * the gain error drift. These paramenters vary depending on device and whether |
460 | * the channel is calibrated (trimmed) or not. |
461 | */ |
462 | static int palmas_gpadc_threshold_with_tolerance(int val, const int INL, |
463 | const int gain_error, |
464 | const int offset_error) |
465 | { |
466 | val = ((val + INL) * (1000 + gain_error)) / 1000 + offset_error; |
467 | |
468 | return clamp(val, 0, 0xFFF); |
469 | } |
470 | |
471 | /* |
472 | * The values below are taken from the datasheet of TWL6035, TWL6037. |
473 | * todo: get max INL, gain error, and offset error from OF. |
474 | */ |
475 | static int palmas_gpadc_get_high_threshold_raw(struct palmas_gpadc *adc, |
476 | struct palmas_adc_event *ev) |
477 | { |
478 | const int adc_chan = ev->channel; |
479 | int val = adc->thresholds[adc_chan].high; |
480 | /* integral nonlinearity, measured in LSB */ |
481 | const int max_INL = 2; |
482 | /* measured in LSB */ |
483 | int max_offset_error; |
484 | /* 0.2% when calibrated */ |
485 | int max_gain_error = 2; |
486 | |
487 | val = (val * 1000) / adc->adc_info[adc_chan].gain; |
488 | |
489 | if (adc->adc_info[adc_chan].is_uncalibrated) { |
490 | /* 2% worse */ |
491 | max_gain_error += 20; |
492 | max_offset_error = 36; |
493 | } else { |
494 | val = (val * adc->adc_info[adc_chan].gain_error + |
495 | adc->adc_info[adc_chan].offset) / |
496 | 1000; |
497 | max_offset_error = 2; |
498 | } |
499 | |
500 | return palmas_gpadc_threshold_with_tolerance(val, |
501 | INL: max_INL, |
502 | gain_error: max_gain_error, |
503 | offset_error: max_offset_error); |
504 | } |
505 | |
506 | /* |
507 | * The values below are taken from the datasheet of TWL6035, TWL6037. |
508 | * todo: get min INL, gain error, and offset error from OF. |
509 | */ |
510 | static int palmas_gpadc_get_low_threshold_raw(struct palmas_gpadc *adc, |
511 | struct palmas_adc_event *ev) |
512 | { |
513 | const int adc_chan = ev->channel; |
514 | int val = adc->thresholds[adc_chan].low; |
515 | /* integral nonlinearity, measured in LSB */ |
516 | const int min_INL = -2; |
517 | /* measured in LSB */ |
518 | int min_offset_error; |
519 | /* -0.6% when calibrated */ |
520 | int min_gain_error = -6; |
521 | |
522 | val = (val * 1000) / adc->adc_info[adc_chan].gain; |
523 | |
524 | if (adc->adc_info[adc_chan].is_uncalibrated) { |
525 | /* 2% worse */ |
526 | min_gain_error -= 20; |
527 | min_offset_error = -36; |
528 | } else { |
529 | val = (val * adc->adc_info[adc_chan].gain_error - |
530 | adc->adc_info[adc_chan].offset) / |
531 | 1000; |
532 | min_offset_error = -2; |
533 | } |
534 | |
535 | return palmas_gpadc_threshold_with_tolerance(val, |
536 | INL: min_INL, |
537 | gain_error: min_gain_error, |
538 | offset_error: min_offset_error); |
539 | } |
540 | |
541 | static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, |
542 | struct iio_chan_spec const *chan, int *val, int *val2, long mask) |
543 | { |
544 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
545 | int adc_chan = chan->channel; |
546 | int ret = 0; |
547 | |
548 | if (adc_chan >= PALMAS_ADC_CH_MAX) |
549 | return -EINVAL; |
550 | |
551 | mutex_lock(&adc->lock); |
552 | |
553 | switch (mask) { |
554 | case IIO_CHAN_INFO_RAW: |
555 | case IIO_CHAN_INFO_PROCESSED: |
556 | ret = palmas_gpadc_read_prepare(adc, adc_chan); |
557 | if (ret < 0) |
558 | goto out; |
559 | |
560 | ret = palmas_gpadc_start_conversion(adc, adc_chan); |
561 | if (ret < 0) { |
562 | dev_err(adc->dev, |
563 | "ADC start conversion failed\n" ); |
564 | goto out; |
565 | } |
566 | |
567 | if (mask == IIO_CHAN_INFO_PROCESSED) |
568 | ret = palmas_gpadc_get_calibrated_code( |
569 | adc, adc_chan, val: ret); |
570 | |
571 | *val = ret; |
572 | |
573 | ret = IIO_VAL_INT; |
574 | goto out; |
575 | } |
576 | |
577 | mutex_unlock(lock: &adc->lock); |
578 | return ret; |
579 | |
580 | out: |
581 | palmas_gpadc_read_done(adc, adc_chan); |
582 | mutex_unlock(lock: &adc->lock); |
583 | |
584 | return ret; |
585 | } |
586 | |
587 | static int palmas_gpadc_read_event_config(struct iio_dev *indio_dev, |
588 | const struct iio_chan_spec *chan, |
589 | enum iio_event_type type, |
590 | enum iio_event_direction dir) |
591 | { |
592 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
593 | int adc_chan = chan->channel; |
594 | int ret = 0; |
595 | |
596 | if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) |
597 | return -EINVAL; |
598 | |
599 | mutex_lock(&adc->lock); |
600 | |
601 | if (palmas_gpadc_get_event(adc, adc_chan, dir)) |
602 | ret = 1; |
603 | |
604 | mutex_unlock(lock: &adc->lock); |
605 | |
606 | return ret; |
607 | } |
608 | |
609 | static int palmas_adc_configure_events(struct palmas_gpadc *adc); |
610 | static int palmas_adc_reset_events(struct palmas_gpadc *adc); |
611 | |
612 | static int palmas_gpadc_reconfigure_event_channels(struct palmas_gpadc *adc) |
613 | { |
614 | return (adc->event0.enabled || adc->event1.enabled) ? |
615 | palmas_adc_configure_events(adc) : |
616 | palmas_adc_reset_events(adc); |
617 | } |
618 | |
619 | static int palmas_gpadc_enable_event_config(struct palmas_gpadc *adc, |
620 | const struct iio_chan_spec *chan, |
621 | enum iio_event_direction dir) |
622 | { |
623 | struct palmas_adc_event *ev; |
624 | int adc_chan = chan->channel; |
625 | |
626 | if (palmas_gpadc_get_event(adc, adc_chan, dir)) |
627 | /* already enabled */ |
628 | return 0; |
629 | |
630 | if (adc->event0.channel == -1) { |
631 | ev = &adc->event0; |
632 | } else if (adc->event1.channel == -1) { |
633 | /* event0 has to be the lowest channel */ |
634 | if (adc_chan < adc->event0.channel) { |
635 | adc->event1 = adc->event0; |
636 | ev = &adc->event0; |
637 | } else { |
638 | ev = &adc->event1; |
639 | } |
640 | } else { /* both AUTO channels already in use */ |
641 | dev_warn(adc->dev, "event0 - %d, event1 - %d\n" , |
642 | adc->event0.channel, adc->event1.channel); |
643 | return -EBUSY; |
644 | } |
645 | |
646 | ev->enabled = true; |
647 | ev->channel = adc_chan; |
648 | ev->direction = dir; |
649 | |
650 | return palmas_gpadc_reconfigure_event_channels(adc); |
651 | } |
652 | |
653 | static int palmas_gpadc_disable_event_config(struct palmas_gpadc *adc, |
654 | const struct iio_chan_spec *chan, |
655 | enum iio_event_direction dir) |
656 | { |
657 | int adc_chan = chan->channel; |
658 | struct palmas_adc_event *ev = palmas_gpadc_get_event(adc, adc_chan, dir); |
659 | |
660 | if (!ev) |
661 | return 0; |
662 | |
663 | if (ev == &adc->event0) { |
664 | adc->event0 = adc->event1; |
665 | ev = &adc->event1; |
666 | } |
667 | |
668 | ev->enabled = false; |
669 | ev->channel = -1; |
670 | ev->direction = IIO_EV_DIR_NONE; |
671 | |
672 | return palmas_gpadc_reconfigure_event_channels(adc); |
673 | } |
674 | |
675 | static int palmas_gpadc_write_event_config(struct iio_dev *indio_dev, |
676 | const struct iio_chan_spec *chan, |
677 | enum iio_event_type type, |
678 | enum iio_event_direction dir, |
679 | int state) |
680 | { |
681 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
682 | int adc_chan = chan->channel; |
683 | int ret; |
684 | |
685 | if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) |
686 | return -EINVAL; |
687 | |
688 | mutex_lock(&adc->lock); |
689 | |
690 | if (state) |
691 | ret = palmas_gpadc_enable_event_config(adc, chan, dir); |
692 | else |
693 | ret = palmas_gpadc_disable_event_config(adc, chan, dir); |
694 | |
695 | mutex_unlock(lock: &adc->lock); |
696 | |
697 | return ret; |
698 | } |
699 | |
700 | static int palmas_gpadc_read_event_value(struct iio_dev *indio_dev, |
701 | const struct iio_chan_spec *chan, |
702 | enum iio_event_type type, |
703 | enum iio_event_direction dir, |
704 | enum iio_event_info info, |
705 | int *val, int *val2) |
706 | { |
707 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
708 | int adc_chan = chan->channel; |
709 | int ret; |
710 | |
711 | if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) |
712 | return -EINVAL; |
713 | |
714 | mutex_lock(&adc->lock); |
715 | |
716 | switch (info) { |
717 | case IIO_EV_INFO_VALUE: |
718 | *val = (dir == IIO_EV_DIR_RISING) ? |
719 | adc->thresholds[adc_chan].high : |
720 | adc->thresholds[adc_chan].low; |
721 | ret = IIO_VAL_INT; |
722 | break; |
723 | default: |
724 | ret = -EINVAL; |
725 | break; |
726 | } |
727 | |
728 | mutex_unlock(lock: &adc->lock); |
729 | |
730 | return ret; |
731 | } |
732 | |
733 | static int palmas_gpadc_write_event_value(struct iio_dev *indio_dev, |
734 | const struct iio_chan_spec *chan, |
735 | enum iio_event_type type, |
736 | enum iio_event_direction dir, |
737 | enum iio_event_info info, |
738 | int val, int val2) |
739 | { |
740 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
741 | int adc_chan = chan->channel; |
742 | int old; |
743 | int ret; |
744 | |
745 | if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) |
746 | return -EINVAL; |
747 | |
748 | mutex_lock(&adc->lock); |
749 | switch (info) { |
750 | case IIO_EV_INFO_VALUE: |
751 | if (val < 0 || val > 0xFFF) { |
752 | ret = -EINVAL; |
753 | goto out_unlock; |
754 | } |
755 | if (dir == IIO_EV_DIR_RISING) { |
756 | old = adc->thresholds[adc_chan].high; |
757 | adc->thresholds[adc_chan].high = val; |
758 | } else { |
759 | old = adc->thresholds[adc_chan].low; |
760 | adc->thresholds[adc_chan].low = val; |
761 | } |
762 | ret = 0; |
763 | break; |
764 | default: |
765 | ret = -EINVAL; |
766 | goto out_unlock; |
767 | } |
768 | |
769 | if (val != old && palmas_gpadc_get_event(adc, adc_chan, dir)) |
770 | ret = palmas_gpadc_reconfigure_event_channels(adc); |
771 | |
772 | out_unlock: |
773 | mutex_unlock(lock: &adc->lock); |
774 | |
775 | return ret; |
776 | } |
777 | |
778 | static const struct iio_info palmas_gpadc_iio_info = { |
779 | .read_raw = palmas_gpadc_read_raw, |
780 | .read_event_config = palmas_gpadc_read_event_config, |
781 | .write_event_config = palmas_gpadc_write_event_config, |
782 | .read_event_value = palmas_gpadc_read_event_value, |
783 | .write_event_value = palmas_gpadc_write_event_value, |
784 | }; |
785 | |
786 | static const struct iio_event_spec palmas_gpadc_events[] = { |
787 | { |
788 | .type = IIO_EV_TYPE_THRESH, |
789 | .dir = IIO_EV_DIR_RISING, |
790 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | |
791 | BIT(IIO_EV_INFO_ENABLE), |
792 | }, { |
793 | .type = IIO_EV_TYPE_THRESH, |
794 | .dir = IIO_EV_DIR_FALLING, |
795 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | |
796 | BIT(IIO_EV_INFO_ENABLE), |
797 | }, |
798 | }; |
799 | |
800 | #define PALMAS_ADC_CHAN_IIO(chan, _type, chan_info) \ |
801 | { \ |
802 | .datasheet_name = PALMAS_DATASHEET_NAME(chan), \ |
803 | .type = _type, \ |
804 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
805 | BIT(chan_info), \ |
806 | .indexed = 1, \ |
807 | .channel = PALMAS_ADC_CH_##chan, \ |
808 | .event_spec = palmas_gpadc_events, \ |
809 | .num_event_specs = ARRAY_SIZE(palmas_gpadc_events) \ |
810 | } |
811 | |
812 | static const struct iio_chan_spec palmas_gpadc_iio_channel[] = { |
813 | PALMAS_ADC_CHAN_IIO(IN0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
814 | PALMAS_ADC_CHAN_IIO(IN1, IIO_TEMP, IIO_CHAN_INFO_RAW), |
815 | PALMAS_ADC_CHAN_IIO(IN2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
816 | PALMAS_ADC_CHAN_IIO(IN3, IIO_TEMP, IIO_CHAN_INFO_RAW), |
817 | PALMAS_ADC_CHAN_IIO(IN4, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
818 | PALMAS_ADC_CHAN_IIO(IN5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
819 | PALMAS_ADC_CHAN_IIO(IN6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
820 | PALMAS_ADC_CHAN_IIO(IN7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
821 | PALMAS_ADC_CHAN_IIO(IN8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
822 | PALMAS_ADC_CHAN_IIO(IN9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
823 | PALMAS_ADC_CHAN_IIO(IN10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
824 | PALMAS_ADC_CHAN_IIO(IN11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
825 | PALMAS_ADC_CHAN_IIO(IN12, IIO_TEMP, IIO_CHAN_INFO_RAW), |
826 | PALMAS_ADC_CHAN_IIO(IN13, IIO_TEMP, IIO_CHAN_INFO_RAW), |
827 | PALMAS_ADC_CHAN_IIO(IN14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
828 | PALMAS_ADC_CHAN_IIO(IN15, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), |
829 | }; |
830 | |
831 | static int palmas_gpadc_get_adc_dt_data(struct platform_device *pdev, |
832 | struct palmas_gpadc_platform_data **gpadc_pdata) |
833 | { |
834 | struct device_node *np = pdev->dev.of_node; |
835 | struct palmas_gpadc_platform_data *gp_data; |
836 | int ret; |
837 | u32 pval; |
838 | |
839 | gp_data = devm_kzalloc(dev: &pdev->dev, size: sizeof(*gp_data), GFP_KERNEL); |
840 | if (!gp_data) |
841 | return -ENOMEM; |
842 | |
843 | ret = of_property_read_u32(np, propname: "ti,channel0-current-microamp" , out_value: &pval); |
844 | if (!ret) |
845 | gp_data->ch0_current = pval; |
846 | |
847 | ret = of_property_read_u32(np, propname: "ti,channel3-current-microamp" , out_value: &pval); |
848 | if (!ret) |
849 | gp_data->ch3_current = pval; |
850 | |
851 | gp_data->extended_delay = of_property_read_bool(np, |
852 | propname: "ti,enable-extended-delay" ); |
853 | |
854 | *gpadc_pdata = gp_data; |
855 | |
856 | return 0; |
857 | } |
858 | |
859 | static void palmas_gpadc_reset(void *data) |
860 | { |
861 | struct palmas_gpadc *adc = data; |
862 | if (adc->event0.enabled || adc->event1.enabled) |
863 | palmas_adc_reset_events(adc); |
864 | } |
865 | |
866 | static int palmas_gpadc_probe(struct platform_device *pdev) |
867 | { |
868 | struct palmas_gpadc *adc; |
869 | struct palmas_platform_data *pdata; |
870 | struct palmas_gpadc_platform_data *gpadc_pdata = NULL; |
871 | struct iio_dev *indio_dev; |
872 | int ret, i; |
873 | |
874 | pdata = dev_get_platdata(dev: pdev->dev.parent); |
875 | |
876 | if (pdata && pdata->gpadc_pdata) |
877 | gpadc_pdata = pdata->gpadc_pdata; |
878 | |
879 | if (!gpadc_pdata && pdev->dev.of_node) { |
880 | ret = palmas_gpadc_get_adc_dt_data(pdev, gpadc_pdata: &gpadc_pdata); |
881 | if (ret < 0) |
882 | return ret; |
883 | } |
884 | if (!gpadc_pdata) |
885 | return -EINVAL; |
886 | |
887 | indio_dev = devm_iio_device_alloc(parent: &pdev->dev, sizeof_priv: sizeof(*adc)); |
888 | if (!indio_dev) { |
889 | dev_err(&pdev->dev, "iio_device_alloc failed\n" ); |
890 | return -ENOMEM; |
891 | } |
892 | |
893 | adc = iio_priv(indio_dev); |
894 | adc->dev = &pdev->dev; |
895 | adc->palmas = dev_get_drvdata(dev: pdev->dev.parent); |
896 | adc->adc_info = palmas_gpadc_info; |
897 | |
898 | mutex_init(&adc->lock); |
899 | |
900 | init_completion(x: &adc->conv_completion); |
901 | platform_set_drvdata(pdev, data: indio_dev); |
902 | |
903 | adc->auto_conversion_period = gpadc_pdata->auto_conversion_period_ms; |
904 | adc->irq = palmas_irq_get_virq(palmas: adc->palmas, irq: PALMAS_GPADC_EOC_SW_IRQ); |
905 | if (adc->irq < 0) |
906 | return dev_err_probe(dev: adc->dev, err: adc->irq, fmt: "get virq failed\n" ); |
907 | |
908 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq: adc->irq, NULL, |
909 | thread_fn: palmas_gpadc_irq, |
910 | IRQF_ONESHOT, devname: dev_name(dev: adc->dev), |
911 | dev_id: adc); |
912 | if (ret < 0) |
913 | return dev_err_probe(dev: adc->dev, err: ret, |
914 | fmt: "request irq %d failed\n" , adc->irq); |
915 | |
916 | adc->irq_auto_0 = platform_get_irq(pdev, 1); |
917 | if (adc->irq_auto_0 < 0) |
918 | return adc->irq_auto_0; |
919 | |
920 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq: adc->irq_auto_0, NULL, |
921 | thread_fn: palmas_gpadc_irq_auto, IRQF_ONESHOT, |
922 | devname: "palmas-adc-auto-0" , dev_id: indio_dev); |
923 | if (ret < 0) |
924 | return dev_err_probe(dev: adc->dev, err: ret, |
925 | fmt: "request auto0 irq %d failed\n" , |
926 | adc->irq_auto_0); |
927 | |
928 | adc->irq_auto_1 = platform_get_irq(pdev, 2); |
929 | if (adc->irq_auto_1 < 0) |
930 | return adc->irq_auto_1; |
931 | |
932 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq: adc->irq_auto_1, NULL, |
933 | thread_fn: palmas_gpadc_irq_auto, IRQF_ONESHOT, |
934 | devname: "palmas-adc-auto-1" , dev_id: indio_dev); |
935 | if (ret < 0) |
936 | return dev_err_probe(dev: adc->dev, err: ret, |
937 | fmt: "request auto1 irq %d failed\n" , |
938 | adc->irq_auto_1); |
939 | |
940 | adc->event0.enabled = false; |
941 | adc->event0.channel = -1; |
942 | adc->event0.direction = IIO_EV_DIR_NONE; |
943 | adc->event1.enabled = false; |
944 | adc->event1.channel = -1; |
945 | adc->event1.direction = IIO_EV_DIR_NONE; |
946 | |
947 | /* set the current source 0 (value 0/5/15/20 uA => 0..3) */ |
948 | if (gpadc_pdata->ch0_current <= 1) |
949 | adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_0; |
950 | else if (gpadc_pdata->ch0_current <= 5) |
951 | adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_5; |
952 | else if (gpadc_pdata->ch0_current <= 15) |
953 | adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_15; |
954 | else |
955 | adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_20; |
956 | |
957 | /* set the current source 3 (value 0/10/400/800 uA => 0..3) */ |
958 | if (gpadc_pdata->ch3_current <= 1) |
959 | adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_0; |
960 | else if (gpadc_pdata->ch3_current <= 10) |
961 | adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_10; |
962 | else if (gpadc_pdata->ch3_current <= 400) |
963 | adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_400; |
964 | else |
965 | adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_800; |
966 | |
967 | adc->extended_delay = gpadc_pdata->extended_delay; |
968 | |
969 | indio_dev->name = MOD_NAME; |
970 | indio_dev->info = &palmas_gpadc_iio_info; |
971 | indio_dev->modes = INDIO_DIRECT_MODE; |
972 | indio_dev->channels = palmas_gpadc_iio_channel; |
973 | indio_dev->num_channels = ARRAY_SIZE(palmas_gpadc_iio_channel); |
974 | |
975 | ret = devm_iio_device_register(&pdev->dev, indio_dev); |
976 | if (ret < 0) |
977 | return dev_err_probe(dev: adc->dev, err: ret, |
978 | fmt: "iio_device_register() failed\n" ); |
979 | |
980 | device_set_wakeup_capable(dev: &pdev->dev, capable: 1); |
981 | for (i = 0; i < PALMAS_ADC_CH_MAX; i++) { |
982 | if (!(adc->adc_info[i].is_uncalibrated)) |
983 | palmas_gpadc_calibrate(adc, adc_chan: i); |
984 | } |
985 | |
986 | ret = devm_add_action(&pdev->dev, palmas_gpadc_reset, adc); |
987 | if (ret) |
988 | return ret; |
989 | |
990 | return 0; |
991 | } |
992 | |
993 | static int palmas_adc_configure_events(struct palmas_gpadc *adc) |
994 | { |
995 | int adc_period, conv; |
996 | int i; |
997 | int ch0 = 0, ch1 = 0; |
998 | int thres; |
999 | int ret; |
1000 | |
1001 | adc_period = adc->auto_conversion_period; |
1002 | for (i = 0; i < 16; ++i) { |
1003 | if (((1000 * (1 << i)) / 32) >= adc_period) |
1004 | break; |
1005 | } |
1006 | if (i > 0) |
1007 | i--; |
1008 | adc_period = i; |
1009 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1010 | PALMAS_GPADC_AUTO_CTRL, |
1011 | PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK, |
1012 | val: adc_period); |
1013 | if (ret < 0) { |
1014 | dev_err(adc->dev, "AUTO_CTRL write failed: %d\n" , ret); |
1015 | return ret; |
1016 | } |
1017 | |
1018 | conv = 0; |
1019 | if (adc->event0.enabled) { |
1020 | struct palmas_adc_event *ev = &adc->event0; |
1021 | int polarity; |
1022 | |
1023 | ch0 = ev->channel; |
1024 | conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN; |
1025 | switch (ev->direction) { |
1026 | case IIO_EV_DIR_RISING: |
1027 | thres = palmas_gpadc_get_high_threshold_raw(adc, ev); |
1028 | polarity = 0; |
1029 | break; |
1030 | case IIO_EV_DIR_FALLING: |
1031 | thres = palmas_gpadc_get_low_threshold_raw(adc, ev); |
1032 | polarity = PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL; |
1033 | break; |
1034 | default: |
1035 | return -EINVAL; |
1036 | } |
1037 | |
1038 | ret = palmas_write(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1039 | PALMAS_GPADC_THRES_CONV0_LSB, value: thres & 0xFF); |
1040 | if (ret < 0) { |
1041 | dev_err(adc->dev, |
1042 | "THRES_CONV0_LSB write failed: %d\n" , ret); |
1043 | return ret; |
1044 | } |
1045 | |
1046 | ret = palmas_write(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1047 | PALMAS_GPADC_THRES_CONV0_MSB, |
1048 | value: ((thres >> 8) & 0xF) | polarity); |
1049 | if (ret < 0) { |
1050 | dev_err(adc->dev, |
1051 | "THRES_CONV0_MSB write failed: %d\n" , ret); |
1052 | return ret; |
1053 | } |
1054 | } |
1055 | |
1056 | if (adc->event1.enabled) { |
1057 | struct palmas_adc_event *ev = &adc->event1; |
1058 | int polarity; |
1059 | |
1060 | ch1 = ev->channel; |
1061 | conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN; |
1062 | switch (ev->direction) { |
1063 | case IIO_EV_DIR_RISING: |
1064 | thres = palmas_gpadc_get_high_threshold_raw(adc, ev); |
1065 | polarity = 0; |
1066 | break; |
1067 | case IIO_EV_DIR_FALLING: |
1068 | thres = palmas_gpadc_get_low_threshold_raw(adc, ev); |
1069 | polarity = PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL; |
1070 | break; |
1071 | default: |
1072 | return -EINVAL; |
1073 | } |
1074 | |
1075 | ret = palmas_write(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1076 | PALMAS_GPADC_THRES_CONV1_LSB, value: thres & 0xFF); |
1077 | if (ret < 0) { |
1078 | dev_err(adc->dev, |
1079 | "THRES_CONV1_LSB write failed: %d\n" , ret); |
1080 | return ret; |
1081 | } |
1082 | |
1083 | ret = palmas_write(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1084 | PALMAS_GPADC_THRES_CONV1_MSB, |
1085 | value: ((thres >> 8) & 0xF) | polarity); |
1086 | if (ret < 0) { |
1087 | dev_err(adc->dev, |
1088 | "THRES_CONV1_MSB write failed: %d\n" , ret); |
1089 | return ret; |
1090 | } |
1091 | } |
1092 | |
1093 | ret = palmas_write(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1094 | PALMAS_GPADC_AUTO_SELECT, value: (ch1 << 4) | ch0); |
1095 | if (ret < 0) { |
1096 | dev_err(adc->dev, "AUTO_SELECT write failed: %d\n" , ret); |
1097 | return ret; |
1098 | } |
1099 | |
1100 | ret = palmas_update_bits(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1101 | PALMAS_GPADC_AUTO_CTRL, |
1102 | PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN | |
1103 | PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN, val: conv); |
1104 | if (ret < 0) |
1105 | dev_err(adc->dev, "AUTO_CTRL write failed: %d\n" , ret); |
1106 | |
1107 | return ret; |
1108 | } |
1109 | |
1110 | static int palmas_adc_reset_events(struct palmas_gpadc *adc) |
1111 | { |
1112 | int ret; |
1113 | |
1114 | ret = palmas_write(palmas: adc->palmas, PALMAS_GPADC_BASE, |
1115 | PALMAS_GPADC_AUTO_SELECT, value: 0); |
1116 | if (ret < 0) { |
1117 | dev_err(adc->dev, "AUTO_SELECT write failed: %d\n" , ret); |
1118 | return ret; |
1119 | } |
1120 | |
1121 | ret = palmas_disable_auto_conversion(adc); |
1122 | if (ret < 0) |
1123 | dev_err(adc->dev, "Disable auto conversion failed: %d\n" , ret); |
1124 | |
1125 | return ret; |
1126 | } |
1127 | |
1128 | static int palmas_gpadc_suspend(struct device *dev) |
1129 | { |
1130 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
1131 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
1132 | |
1133 | if (!device_may_wakeup(dev)) |
1134 | return 0; |
1135 | |
1136 | if (adc->event0.enabled) |
1137 | enable_irq_wake(irq: adc->irq_auto_0); |
1138 | |
1139 | if (adc->event1.enabled) |
1140 | enable_irq_wake(irq: adc->irq_auto_1); |
1141 | |
1142 | return 0; |
1143 | } |
1144 | |
1145 | static int palmas_gpadc_resume(struct device *dev) |
1146 | { |
1147 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
1148 | struct palmas_gpadc *adc = iio_priv(indio_dev); |
1149 | |
1150 | if (!device_may_wakeup(dev)) |
1151 | return 0; |
1152 | |
1153 | if (adc->event0.enabled) |
1154 | disable_irq_wake(irq: adc->irq_auto_0); |
1155 | |
1156 | if (adc->event1.enabled) |
1157 | disable_irq_wake(irq: adc->irq_auto_1); |
1158 | |
1159 | return 0; |
1160 | }; |
1161 | |
1162 | static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_gpadc_suspend, |
1163 | palmas_gpadc_resume); |
1164 | |
1165 | static const struct of_device_id of_palmas_gpadc_match_tbl[] = { |
1166 | { .compatible = "ti,palmas-gpadc" , }, |
1167 | { /* end */ } |
1168 | }; |
1169 | MODULE_DEVICE_TABLE(of, of_palmas_gpadc_match_tbl); |
1170 | |
1171 | static struct platform_driver palmas_gpadc_driver = { |
1172 | .probe = palmas_gpadc_probe, |
1173 | .driver = { |
1174 | .name = MOD_NAME, |
1175 | .pm = pm_sleep_ptr(&palmas_pm_ops), |
1176 | .of_match_table = of_palmas_gpadc_match_tbl, |
1177 | }, |
1178 | }; |
1179 | module_platform_driver(palmas_gpadc_driver); |
1180 | |
1181 | MODULE_DESCRIPTION("palmas GPADC driver" ); |
1182 | MODULE_AUTHOR("Pradeep Goudagunta<pgoudagunta@nvidia.com>" ); |
1183 | MODULE_ALIAS("platform:palmas-gpadc" ); |
1184 | MODULE_LICENSE("GPL v2" ); |
1185 | |