1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* ADC driver for sunxi platforms' (A10, A13 and A31) GPADC |
3 | * |
4 | * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com> |
5 | * |
6 | * The Allwinner SoCs all have an ADC that can also act as a touchscreen |
7 | * controller and a thermal sensor. |
8 | * The thermal sensor works only when the ADC acts as a touchscreen controller |
9 | * and is configured to throw an interrupt every fixed periods of time (let say |
10 | * every X seconds). |
11 | * One would be tempted to disable the IP on the hardware side rather than |
12 | * disabling interrupts to save some power but that resets the internal clock of |
13 | * the IP, resulting in having to wait X seconds every time we want to read the |
14 | * value of the thermal sensor. |
15 | * This is also the reason of using autosuspend in pm_runtime. If there was no |
16 | * autosuspend, the thermal sensor would need X seconds after every |
17 | * pm_runtime_get_sync to get a value from the ADC. The autosuspend allows the |
18 | * thermal sensor to be requested again in a certain time span before it gets |
19 | * shutdown for not being used. |
20 | */ |
21 | |
22 | #include <linux/completion.h> |
23 | #include <linux/interrupt.h> |
24 | #include <linux/io.h> |
25 | #include <linux/module.h> |
26 | #include <linux/of.h> |
27 | #include <linux/platform_device.h> |
28 | #include <linux/pm_runtime.h> |
29 | #include <linux/regmap.h> |
30 | #include <linux/thermal.h> |
31 | #include <linux/delay.h> |
32 | |
33 | #include <linux/iio/iio.h> |
34 | #include <linux/iio/driver.h> |
35 | #include <linux/iio/machine.h> |
36 | #include <linux/mfd/sun4i-gpadc.h> |
37 | |
38 | static unsigned int sun4i_gpadc_chan_select(unsigned int chan) |
39 | { |
40 | return SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(chan); |
41 | } |
42 | |
43 | static unsigned int sun6i_gpadc_chan_select(unsigned int chan) |
44 | { |
45 | return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan); |
46 | } |
47 | |
48 | struct gpadc_data { |
49 | int temp_offset; |
50 | int temp_scale; |
51 | unsigned int tp_mode_en; |
52 | unsigned int tp_adc_select; |
53 | unsigned int (*adc_chan_select)(unsigned int chan); |
54 | unsigned int adc_chan_mask; |
55 | }; |
56 | |
57 | static const struct gpadc_data sun4i_gpadc_data = { |
58 | .temp_offset = -1932, |
59 | .temp_scale = 133, |
60 | .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN, |
61 | .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT, |
62 | .adc_chan_select = &sun4i_gpadc_chan_select, |
63 | .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK, |
64 | }; |
65 | |
66 | static const struct gpadc_data sun5i_gpadc_data = { |
67 | .temp_offset = -1447, |
68 | .temp_scale = 100, |
69 | .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN, |
70 | .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT, |
71 | .adc_chan_select = &sun4i_gpadc_chan_select, |
72 | .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK, |
73 | }; |
74 | |
75 | static const struct gpadc_data sun6i_gpadc_data = { |
76 | .temp_offset = -1623, |
77 | .temp_scale = 167, |
78 | .tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN, |
79 | .tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT, |
80 | .adc_chan_select = &sun6i_gpadc_chan_select, |
81 | .adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK, |
82 | }; |
83 | |
84 | static const struct gpadc_data sun8i_a33_gpadc_data = { |
85 | .temp_offset = -1662, |
86 | .temp_scale = 162, |
87 | .tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN, |
88 | }; |
89 | |
90 | struct sun4i_gpadc_iio { |
91 | struct iio_dev *indio_dev; |
92 | struct completion completion; |
93 | int temp_data; |
94 | u32 adc_data; |
95 | struct regmap *regmap; |
96 | unsigned int fifo_data_irq; |
97 | atomic_t ignore_fifo_data_irq; |
98 | unsigned int temp_data_irq; |
99 | atomic_t ignore_temp_data_irq; |
100 | const struct gpadc_data *data; |
101 | bool no_irq; |
102 | /* prevents concurrent reads of temperature and ADC */ |
103 | struct mutex mutex; |
104 | struct thermal_zone_device *tzd; |
105 | struct device *sensor_device; |
106 | }; |
107 | |
108 | #define SUN4I_GPADC_ADC_CHANNEL(_channel, _name) { \ |
109 | .type = IIO_VOLTAGE, \ |
110 | .indexed = 1, \ |
111 | .channel = _channel, \ |
112 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
113 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
114 | .datasheet_name = _name, \ |
115 | } |
116 | |
117 | static struct iio_map sun4i_gpadc_hwmon_maps[] = { |
118 | { |
119 | .adc_channel_label = "temp_adc" , |
120 | .consumer_dev_name = "iio_hwmon.0" , |
121 | }, |
122 | { /* sentinel */ }, |
123 | }; |
124 | |
125 | static const struct iio_chan_spec sun4i_gpadc_channels[] = { |
126 | SUN4I_GPADC_ADC_CHANNEL(0, "adc_chan0" ), |
127 | SUN4I_GPADC_ADC_CHANNEL(1, "adc_chan1" ), |
128 | SUN4I_GPADC_ADC_CHANNEL(2, "adc_chan2" ), |
129 | SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3" ), |
130 | { |
131 | .type = IIO_TEMP, |
132 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
133 | BIT(IIO_CHAN_INFO_SCALE) | |
134 | BIT(IIO_CHAN_INFO_OFFSET), |
135 | .datasheet_name = "temp_adc" , |
136 | }, |
137 | }; |
138 | |
139 | static const struct iio_chan_spec sun4i_gpadc_channels_no_temp[] = { |
140 | SUN4I_GPADC_ADC_CHANNEL(0, "adc_chan0" ), |
141 | SUN4I_GPADC_ADC_CHANNEL(1, "adc_chan1" ), |
142 | SUN4I_GPADC_ADC_CHANNEL(2, "adc_chan2" ), |
143 | SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3" ), |
144 | }; |
145 | |
146 | static const struct iio_chan_spec sun8i_a33_gpadc_channels[] = { |
147 | { |
148 | .type = IIO_TEMP, |
149 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
150 | BIT(IIO_CHAN_INFO_SCALE) | |
151 | BIT(IIO_CHAN_INFO_OFFSET), |
152 | .datasheet_name = "temp_adc" , |
153 | }, |
154 | }; |
155 | |
156 | static const struct regmap_config sun4i_gpadc_regmap_config = { |
157 | .reg_bits = 32, |
158 | .val_bits = 32, |
159 | .reg_stride = 4, |
160 | .fast_io = true, |
161 | }; |
162 | |
163 | static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel, |
164 | unsigned int irq) |
165 | { |
166 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
167 | int ret; |
168 | u32 reg; |
169 | |
170 | pm_runtime_get_sync(dev: indio_dev->dev.parent); |
171 | |
172 | reinit_completion(x: &info->completion); |
173 | |
174 | ret = regmap_write(map: info->regmap, SUN4I_GPADC_INT_FIFOC, |
175 | SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(1) | |
176 | SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH); |
177 | if (ret) |
178 | return ret; |
179 | |
180 | ret = regmap_read(map: info->regmap, SUN4I_GPADC_CTRL1, val: ®); |
181 | if (ret) |
182 | return ret; |
183 | |
184 | if (irq == info->fifo_data_irq) { |
185 | ret = regmap_write(map: info->regmap, SUN4I_GPADC_CTRL1, |
186 | val: info->data->tp_mode_en | |
187 | info->data->tp_adc_select | |
188 | info->data->adc_chan_select(channel)); |
189 | /* |
190 | * When the IP changes channel, it needs a bit of time to get |
191 | * correct values. |
192 | */ |
193 | if ((reg & info->data->adc_chan_mask) != |
194 | info->data->adc_chan_select(channel)) |
195 | mdelay(10); |
196 | |
197 | } else { |
198 | /* |
199 | * The temperature sensor returns valid data only when the ADC |
200 | * operates in touchscreen mode. |
201 | */ |
202 | ret = regmap_write(map: info->regmap, SUN4I_GPADC_CTRL1, |
203 | val: info->data->tp_mode_en); |
204 | } |
205 | |
206 | if (ret) |
207 | return ret; |
208 | |
209 | /* |
210 | * When the IP changes mode between ADC or touchscreen, it |
211 | * needs a bit of time to get correct values. |
212 | */ |
213 | if ((reg & info->data->tp_adc_select) != info->data->tp_adc_select) |
214 | mdelay(100); |
215 | |
216 | return 0; |
217 | } |
218 | |
219 | static int sun4i_gpadc_read(struct iio_dev *indio_dev, int channel, int *val, |
220 | unsigned int irq) |
221 | { |
222 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
223 | int ret; |
224 | |
225 | mutex_lock(&info->mutex); |
226 | |
227 | ret = sun4i_prepare_for_irq(indio_dev, channel, irq); |
228 | if (ret) |
229 | goto err; |
230 | |
231 | enable_irq(irq); |
232 | |
233 | /* |
234 | * The temperature sensor throws an interruption periodically (currently |
235 | * set at periods of ~0.6s in sun4i_gpadc_runtime_resume). A 1s delay |
236 | * makes sure an interruption occurs in normal conditions. If it doesn't |
237 | * occur, then there is a timeout. |
238 | */ |
239 | if (!wait_for_completion_timeout(x: &info->completion, |
240 | timeout: msecs_to_jiffies(m: 1000))) { |
241 | ret = -ETIMEDOUT; |
242 | goto err; |
243 | } |
244 | |
245 | if (irq == info->fifo_data_irq) |
246 | *val = info->adc_data; |
247 | else |
248 | *val = info->temp_data; |
249 | |
250 | ret = 0; |
251 | pm_runtime_mark_last_busy(dev: indio_dev->dev.parent); |
252 | |
253 | err: |
254 | pm_runtime_put_autosuspend(dev: indio_dev->dev.parent); |
255 | disable_irq(irq); |
256 | mutex_unlock(lock: &info->mutex); |
257 | |
258 | return ret; |
259 | } |
260 | |
261 | static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel, |
262 | int *val) |
263 | { |
264 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
265 | |
266 | return sun4i_gpadc_read(indio_dev, channel, val, irq: info->fifo_data_irq); |
267 | } |
268 | |
269 | static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val) |
270 | { |
271 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
272 | |
273 | if (info->no_irq) { |
274 | pm_runtime_get_sync(dev: indio_dev->dev.parent); |
275 | |
276 | regmap_read(map: info->regmap, SUN4I_GPADC_TEMP_DATA, val); |
277 | |
278 | pm_runtime_mark_last_busy(dev: indio_dev->dev.parent); |
279 | pm_runtime_put_autosuspend(dev: indio_dev->dev.parent); |
280 | |
281 | return 0; |
282 | } |
283 | |
284 | return sun4i_gpadc_read(indio_dev, channel: 0, val, irq: info->temp_data_irq); |
285 | } |
286 | |
287 | static int sun4i_gpadc_temp_offset(struct iio_dev *indio_dev, int *val) |
288 | { |
289 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
290 | |
291 | *val = info->data->temp_offset; |
292 | |
293 | return 0; |
294 | } |
295 | |
296 | static int sun4i_gpadc_temp_scale(struct iio_dev *indio_dev, int *val) |
297 | { |
298 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
299 | |
300 | *val = info->data->temp_scale; |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev, |
306 | struct iio_chan_spec const *chan, int *val, |
307 | int *val2, long mask) |
308 | { |
309 | int ret; |
310 | |
311 | switch (mask) { |
312 | case IIO_CHAN_INFO_OFFSET: |
313 | ret = sun4i_gpadc_temp_offset(indio_dev, val); |
314 | if (ret) |
315 | return ret; |
316 | |
317 | return IIO_VAL_INT; |
318 | case IIO_CHAN_INFO_RAW: |
319 | if (chan->type == IIO_VOLTAGE) |
320 | ret = sun4i_gpadc_adc_read(indio_dev, channel: chan->channel, |
321 | val); |
322 | else |
323 | ret = sun4i_gpadc_temp_read(indio_dev, val); |
324 | |
325 | if (ret) |
326 | return ret; |
327 | |
328 | return IIO_VAL_INT; |
329 | case IIO_CHAN_INFO_SCALE: |
330 | if (chan->type == IIO_VOLTAGE) { |
331 | /* 3000mV / 4096 * raw */ |
332 | *val = 0; |
333 | *val2 = 732421875; |
334 | return IIO_VAL_INT_PLUS_NANO; |
335 | } |
336 | |
337 | ret = sun4i_gpadc_temp_scale(indio_dev, val); |
338 | if (ret) |
339 | return ret; |
340 | |
341 | return IIO_VAL_INT; |
342 | default: |
343 | return -EINVAL; |
344 | } |
345 | |
346 | return -EINVAL; |
347 | } |
348 | |
349 | static const struct iio_info sun4i_gpadc_iio_info = { |
350 | .read_raw = sun4i_gpadc_read_raw, |
351 | }; |
352 | |
353 | static irqreturn_t sun4i_gpadc_temp_data_irq_handler(int irq, void *dev_id) |
354 | { |
355 | struct sun4i_gpadc_iio *info = dev_id; |
356 | |
357 | if (atomic_read(v: &info->ignore_temp_data_irq)) |
358 | goto out; |
359 | |
360 | if (!regmap_read(map: info->regmap, SUN4I_GPADC_TEMP_DATA, val: &info->temp_data)) |
361 | complete(&info->completion); |
362 | |
363 | out: |
364 | return IRQ_HANDLED; |
365 | } |
366 | |
367 | static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id) |
368 | { |
369 | struct sun4i_gpadc_iio *info = dev_id; |
370 | |
371 | if (atomic_read(v: &info->ignore_fifo_data_irq)) |
372 | goto out; |
373 | |
374 | if (!regmap_read(map: info->regmap, SUN4I_GPADC_DATA, val: &info->adc_data)) |
375 | complete(&info->completion); |
376 | |
377 | out: |
378 | return IRQ_HANDLED; |
379 | } |
380 | |
381 | static int sun4i_gpadc_runtime_suspend(struct device *dev) |
382 | { |
383 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev: dev_get_drvdata(dev)); |
384 | |
385 | /* Disable the ADC on IP */ |
386 | regmap_write(map: info->regmap, SUN4I_GPADC_CTRL1, val: 0); |
387 | /* Disable temperature sensor on IP */ |
388 | regmap_write(map: info->regmap, SUN4I_GPADC_TPR, val: 0); |
389 | |
390 | return 0; |
391 | } |
392 | |
393 | static int sun4i_gpadc_runtime_resume(struct device *dev) |
394 | { |
395 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev: dev_get_drvdata(dev)); |
396 | |
397 | /* clkin = 6MHz */ |
398 | regmap_write(map: info->regmap, SUN4I_GPADC_CTRL0, |
399 | SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) | |
400 | SUN4I_GPADC_CTRL0_FS_DIV(7) | |
401 | SUN4I_GPADC_CTRL0_T_ACQ(63)); |
402 | regmap_write(map: info->regmap, SUN4I_GPADC_CTRL1, val: info->data->tp_mode_en); |
403 | regmap_write(map: info->regmap, SUN4I_GPADC_CTRL3, |
404 | SUN4I_GPADC_CTRL3_FILTER_EN | |
405 | SUN4I_GPADC_CTRL3_FILTER_TYPE(1)); |
406 | /* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~0.6s */ |
407 | regmap_write(map: info->regmap, SUN4I_GPADC_TPR, |
408 | SUN4I_GPADC_TPR_TEMP_ENABLE | |
409 | SUN4I_GPADC_TPR_TEMP_PERIOD(800)); |
410 | |
411 | return 0; |
412 | } |
413 | |
414 | static int sun4i_gpadc_get_temp(struct thermal_zone_device *tz, int *temp) |
415 | { |
416 | struct sun4i_gpadc_iio *info = thermal_zone_device_priv(tzd: tz); |
417 | int val, scale, offset; |
418 | |
419 | if (sun4i_gpadc_temp_read(indio_dev: info->indio_dev, val: &val)) |
420 | return -ETIMEDOUT; |
421 | |
422 | sun4i_gpadc_temp_scale(indio_dev: info->indio_dev, val: &scale); |
423 | sun4i_gpadc_temp_offset(indio_dev: info->indio_dev, val: &offset); |
424 | |
425 | *temp = (val + offset) * scale; |
426 | |
427 | return 0; |
428 | } |
429 | |
430 | static const struct thermal_zone_device_ops sun4i_ts_tz_ops = { |
431 | .get_temp = &sun4i_gpadc_get_temp, |
432 | }; |
433 | |
434 | static const struct dev_pm_ops sun4i_gpadc_pm_ops = { |
435 | .runtime_suspend = &sun4i_gpadc_runtime_suspend, |
436 | .runtime_resume = &sun4i_gpadc_runtime_resume, |
437 | }; |
438 | |
439 | static int sun4i_irq_init(struct platform_device *pdev, const char *name, |
440 | irq_handler_t handler, const char *devname, |
441 | unsigned int *irq, atomic_t *atomic) |
442 | { |
443 | int ret; |
444 | struct sun4i_gpadc_dev *mfd_dev = dev_get_drvdata(dev: pdev->dev.parent); |
445 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev: dev_get_drvdata(dev: &pdev->dev)); |
446 | |
447 | /* |
448 | * Once the interrupt is activated, the IP continuously performs |
449 | * conversions thus throws interrupts. The interrupt is activated right |
450 | * after being requested but we want to control when these interrupts |
451 | * occur thus we disable it right after being requested. However, an |
452 | * interrupt might occur between these two instructions and we have to |
453 | * make sure that does not happen, by using atomic flags. We set the |
454 | * flag before requesting the interrupt and unset it right after |
455 | * disabling the interrupt. When an interrupt occurs between these two |
456 | * instructions, reading the atomic flag will tell us to ignore the |
457 | * interrupt. |
458 | */ |
459 | atomic_set(v: atomic, i: 1); |
460 | |
461 | ret = platform_get_irq_byname(pdev, name); |
462 | if (ret < 0) |
463 | return ret; |
464 | |
465 | ret = regmap_irq_get_virq(data: mfd_dev->regmap_irqc, irq: ret); |
466 | if (ret < 0) { |
467 | dev_err(&pdev->dev, "failed to get virq for irq %s\n" , name); |
468 | return ret; |
469 | } |
470 | |
471 | *irq = ret; |
472 | ret = devm_request_any_context_irq(dev: &pdev->dev, irq: *irq, handler, |
473 | IRQF_NO_AUTOEN, |
474 | devname, dev_id: info); |
475 | if (ret < 0) { |
476 | dev_err(&pdev->dev, "could not request %s interrupt: %d\n" , |
477 | name, ret); |
478 | return ret; |
479 | } |
480 | |
481 | atomic_set(v: atomic, i: 0); |
482 | |
483 | return 0; |
484 | } |
485 | |
486 | static const struct of_device_id sun4i_gpadc_of_id[] = { |
487 | { |
488 | .compatible = "allwinner,sun8i-a33-ths" , |
489 | .data = &sun8i_a33_gpadc_data, |
490 | }, |
491 | { /* sentinel */ } |
492 | }; |
493 | |
494 | static int sun4i_gpadc_probe_dt(struct platform_device *pdev, |
495 | struct iio_dev *indio_dev) |
496 | { |
497 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
498 | void __iomem *base; |
499 | int ret; |
500 | |
501 | info->data = of_device_get_match_data(dev: &pdev->dev); |
502 | if (!info->data) |
503 | return -ENODEV; |
504 | |
505 | info->no_irq = true; |
506 | indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels); |
507 | indio_dev->channels = sun8i_a33_gpadc_channels; |
508 | |
509 | base = devm_platform_ioremap_resource(pdev, index: 0); |
510 | if (IS_ERR(ptr: base)) |
511 | return PTR_ERR(ptr: base); |
512 | |
513 | info->regmap = devm_regmap_init_mmio(&pdev->dev, base, |
514 | &sun4i_gpadc_regmap_config); |
515 | if (IS_ERR(ptr: info->regmap)) { |
516 | ret = PTR_ERR(ptr: info->regmap); |
517 | dev_err(&pdev->dev, "failed to init regmap: %d\n" , ret); |
518 | return ret; |
519 | } |
520 | |
521 | if (IS_ENABLED(CONFIG_THERMAL_OF)) |
522 | info->sensor_device = &pdev->dev; |
523 | |
524 | return 0; |
525 | } |
526 | |
527 | static int sun4i_gpadc_probe_mfd(struct platform_device *pdev, |
528 | struct iio_dev *indio_dev) |
529 | { |
530 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
531 | struct sun4i_gpadc_dev *sun4i_gpadc_dev = |
532 | dev_get_drvdata(dev: pdev->dev.parent); |
533 | int ret; |
534 | |
535 | info->no_irq = false; |
536 | info->regmap = sun4i_gpadc_dev->regmap; |
537 | |
538 | indio_dev->num_channels = ARRAY_SIZE(sun4i_gpadc_channels); |
539 | indio_dev->channels = sun4i_gpadc_channels; |
540 | |
541 | info->data = (struct gpadc_data *)platform_get_device_id(pdev)->driver_data; |
542 | |
543 | /* |
544 | * Since the controller needs to be in touchscreen mode for its thermal |
545 | * sensor to operate properly, and that switching between the two modes |
546 | * needs a delay, always registering in the thermal framework will |
547 | * significantly slow down the conversion rate of the ADCs. |
548 | * |
549 | * Therefore, instead of depending on THERMAL_OF in Kconfig, we only |
550 | * register the sensor if that option is enabled, eventually leaving |
551 | * that choice to the user. |
552 | */ |
553 | |
554 | if (IS_ENABLED(CONFIG_THERMAL_OF)) { |
555 | /* |
556 | * This driver is a child of an MFD which has a node in the DT |
557 | * but not its children, because of DT backward compatibility |
558 | * for A10, A13 and A31 SoCs. Therefore, the resulting devices |
559 | * of this driver do not have an of_node variable. |
560 | * However, its parent (the MFD driver) has an of_node variable |
561 | * and since devm_thermal_zone_of_sensor_register uses its first |
562 | * argument to match the phandle defined in the node of the |
563 | * thermal driver with the of_node of the device passed as first |
564 | * argument and the third argument to call ops from |
565 | * thermal_zone_of_device_ops, the solution is to use the parent |
566 | * device as first argument to match the phandle with its |
567 | * of_node, and the device from this driver as third argument to |
568 | * return the temperature. |
569 | */ |
570 | info->sensor_device = pdev->dev.parent; |
571 | } else { |
572 | indio_dev->num_channels = |
573 | ARRAY_SIZE(sun4i_gpadc_channels_no_temp); |
574 | indio_dev->channels = sun4i_gpadc_channels_no_temp; |
575 | } |
576 | |
577 | if (IS_ENABLED(CONFIG_THERMAL_OF)) { |
578 | ret = sun4i_irq_init(pdev, name: "TEMP_DATA_PENDING" , |
579 | handler: sun4i_gpadc_temp_data_irq_handler, |
580 | devname: "temp_data" , irq: &info->temp_data_irq, |
581 | atomic: &info->ignore_temp_data_irq); |
582 | if (ret < 0) |
583 | return ret; |
584 | } |
585 | |
586 | ret = sun4i_irq_init(pdev, name: "FIFO_DATA_PENDING" , |
587 | handler: sun4i_gpadc_fifo_data_irq_handler, devname: "fifo_data" , |
588 | irq: &info->fifo_data_irq, atomic: &info->ignore_fifo_data_irq); |
589 | if (ret < 0) |
590 | return ret; |
591 | |
592 | if (IS_ENABLED(CONFIG_THERMAL_OF)) { |
593 | ret = iio_map_array_register(indio_dev, map: sun4i_gpadc_hwmon_maps); |
594 | if (ret < 0) { |
595 | dev_err(&pdev->dev, |
596 | "failed to register iio map array\n" ); |
597 | return ret; |
598 | } |
599 | } |
600 | |
601 | return 0; |
602 | } |
603 | |
604 | static int sun4i_gpadc_probe(struct platform_device *pdev) |
605 | { |
606 | struct sun4i_gpadc_iio *info; |
607 | struct iio_dev *indio_dev; |
608 | int ret; |
609 | |
610 | indio_dev = devm_iio_device_alloc(parent: &pdev->dev, sizeof_priv: sizeof(*info)); |
611 | if (!indio_dev) |
612 | return -ENOMEM; |
613 | |
614 | info = iio_priv(indio_dev); |
615 | platform_set_drvdata(pdev, data: indio_dev); |
616 | |
617 | mutex_init(&info->mutex); |
618 | info->indio_dev = indio_dev; |
619 | init_completion(x: &info->completion); |
620 | indio_dev->name = dev_name(dev: &pdev->dev); |
621 | indio_dev->info = &sun4i_gpadc_iio_info; |
622 | indio_dev->modes = INDIO_DIRECT_MODE; |
623 | |
624 | if (pdev->dev.of_node) |
625 | ret = sun4i_gpadc_probe_dt(pdev, indio_dev); |
626 | else |
627 | ret = sun4i_gpadc_probe_mfd(pdev, indio_dev); |
628 | |
629 | if (ret) |
630 | return ret; |
631 | |
632 | pm_runtime_set_autosuspend_delay(dev: &pdev->dev, |
633 | SUN4I_GPADC_AUTOSUSPEND_DELAY); |
634 | pm_runtime_use_autosuspend(dev: &pdev->dev); |
635 | pm_runtime_set_suspended(dev: &pdev->dev); |
636 | pm_runtime_enable(dev: &pdev->dev); |
637 | |
638 | if (IS_ENABLED(CONFIG_THERMAL_OF)) { |
639 | info->tzd = devm_thermal_of_zone_register(dev: info->sensor_device, |
640 | id: 0, data: info, |
641 | ops: &sun4i_ts_tz_ops); |
642 | /* |
643 | * Do not fail driver probing when failing to register in |
644 | * thermal because no thermal DT node is found. |
645 | */ |
646 | if (IS_ERR(ptr: info->tzd) && PTR_ERR(ptr: info->tzd) != -ENODEV) { |
647 | dev_err(&pdev->dev, |
648 | "could not register thermal sensor: %ld\n" , |
649 | PTR_ERR(info->tzd)); |
650 | return PTR_ERR(ptr: info->tzd); |
651 | } |
652 | } |
653 | |
654 | ret = devm_iio_device_register(&pdev->dev, indio_dev); |
655 | if (ret < 0) { |
656 | dev_err(&pdev->dev, "could not register the device\n" ); |
657 | goto err_map; |
658 | } |
659 | |
660 | return 0; |
661 | |
662 | err_map: |
663 | if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF)) |
664 | iio_map_array_unregister(indio_dev); |
665 | |
666 | pm_runtime_put(dev: &pdev->dev); |
667 | pm_runtime_disable(dev: &pdev->dev); |
668 | |
669 | return ret; |
670 | } |
671 | |
672 | static void sun4i_gpadc_remove(struct platform_device *pdev) |
673 | { |
674 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); |
675 | struct sun4i_gpadc_iio *info = iio_priv(indio_dev); |
676 | |
677 | pm_runtime_put(dev: &pdev->dev); |
678 | pm_runtime_disable(dev: &pdev->dev); |
679 | |
680 | if (!IS_ENABLED(CONFIG_THERMAL_OF)) |
681 | return; |
682 | |
683 | if (!info->no_irq) |
684 | iio_map_array_unregister(indio_dev); |
685 | } |
686 | |
687 | static const struct platform_device_id sun4i_gpadc_id[] = { |
688 | { "sun4i-a10-gpadc-iio" , (kernel_ulong_t)&sun4i_gpadc_data }, |
689 | { "sun5i-a13-gpadc-iio" , (kernel_ulong_t)&sun5i_gpadc_data }, |
690 | { "sun6i-a31-gpadc-iio" , (kernel_ulong_t)&sun6i_gpadc_data }, |
691 | { /* sentinel */ }, |
692 | }; |
693 | MODULE_DEVICE_TABLE(platform, sun4i_gpadc_id); |
694 | |
695 | static struct platform_driver sun4i_gpadc_driver = { |
696 | .driver = { |
697 | .name = "sun4i-gpadc-iio" , |
698 | .of_match_table = sun4i_gpadc_of_id, |
699 | .pm = &sun4i_gpadc_pm_ops, |
700 | }, |
701 | .id_table = sun4i_gpadc_id, |
702 | .probe = sun4i_gpadc_probe, |
703 | .remove_new = sun4i_gpadc_remove, |
704 | }; |
705 | MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_id); |
706 | |
707 | module_platform_driver(sun4i_gpadc_driver); |
708 | |
709 | MODULE_DESCRIPTION("ADC driver for sunxi platforms" ); |
710 | MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>" ); |
711 | MODULE_LICENSE("GPL v2" ); |
712 | |