1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* ADC driver for AXP20X and AXP22X PMICs |
3 | * |
4 | * Copyright (c) 2016 Free Electrons NextThing Co. |
5 | * Quentin Schulz <quentin.schulz@free-electrons.com> |
6 | */ |
7 | |
8 | #include <linux/bitfield.h> |
9 | #include <linux/completion.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/io.h> |
12 | #include <linux/module.h> |
13 | #include <linux/mod_devicetable.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/pm_runtime.h> |
16 | #include <linux/property.h> |
17 | #include <linux/regmap.h> |
18 | #include <linux/thermal.h> |
19 | |
20 | #include <linux/iio/iio.h> |
21 | #include <linux/iio/driver.h> |
22 | #include <linux/iio/machine.h> |
23 | #include <linux/mfd/axp20x.h> |
24 | |
25 | #define AXP20X_ADC_EN1_MASK GENMASK(7, 0) |
26 | #define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7)) |
27 | |
28 | #define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0)) |
29 | |
30 | #define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0) |
31 | #define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1) |
32 | |
33 | #define AXP20X_ADC_RATE_MASK GENMASK(7, 6) |
34 | #define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK) |
35 | |
36 | #define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK) |
37 | |
38 | #define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4) |
39 | #define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK) |
40 | #define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x) |
41 | #define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK) |
42 | #define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x)) |
43 | |
44 | #define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \ |
45 | { \ |
46 | .type = _type, \ |
47 | .indexed = 1, \ |
48 | .channel = _channel, \ |
49 | .address = _reg, \ |
50 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
51 | BIT(IIO_CHAN_INFO_SCALE), \ |
52 | .datasheet_name = _name, \ |
53 | } |
54 | |
55 | #define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \ |
56 | { \ |
57 | .type = _type, \ |
58 | .indexed = 1, \ |
59 | .channel = _channel, \ |
60 | .address = _reg, \ |
61 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
62 | BIT(IIO_CHAN_INFO_SCALE) |\ |
63 | BIT(IIO_CHAN_INFO_OFFSET),\ |
64 | .datasheet_name = _name, \ |
65 | } |
66 | |
67 | struct axp_data; |
68 | |
69 | struct axp20x_adc_iio { |
70 | struct regmap *regmap; |
71 | const struct axp_data *data; |
72 | }; |
73 | |
74 | enum axp20x_adc_channel_v { |
75 | AXP20X_ACIN_V = 0, |
76 | AXP20X_VBUS_V, |
77 | AXP20X_TS_IN, |
78 | AXP20X_GPIO0_V, |
79 | AXP20X_GPIO1_V, |
80 | AXP20X_IPSOUT_V, |
81 | AXP20X_BATT_V, |
82 | }; |
83 | |
84 | enum axp20x_adc_channel_i { |
85 | AXP20X_ACIN_I = 0, |
86 | AXP20X_VBUS_I, |
87 | AXP20X_BATT_CHRG_I, |
88 | AXP20X_BATT_DISCHRG_I, |
89 | }; |
90 | |
91 | enum axp22x_adc_channel_v { |
92 | AXP22X_TS_IN = 0, |
93 | AXP22X_BATT_V, |
94 | }; |
95 | |
96 | enum axp22x_adc_channel_i { |
97 | AXP22X_BATT_CHRG_I = 1, |
98 | AXP22X_BATT_DISCHRG_I, |
99 | }; |
100 | |
101 | enum axp813_adc_channel_v { |
102 | AXP813_TS_IN = 0, |
103 | AXP813_GPIO0_V, |
104 | AXP813_BATT_V, |
105 | }; |
106 | |
107 | static struct iio_map axp20x_maps[] = { |
108 | { |
109 | .consumer_dev_name = "axp20x-usb-power-supply" , |
110 | .consumer_channel = "vbus_v" , |
111 | .adc_channel_label = "vbus_v" , |
112 | }, { |
113 | .consumer_dev_name = "axp20x-usb-power-supply" , |
114 | .consumer_channel = "vbus_i" , |
115 | .adc_channel_label = "vbus_i" , |
116 | }, { |
117 | .consumer_dev_name = "axp20x-ac-power-supply" , |
118 | .consumer_channel = "acin_v" , |
119 | .adc_channel_label = "acin_v" , |
120 | }, { |
121 | .consumer_dev_name = "axp20x-ac-power-supply" , |
122 | .consumer_channel = "acin_i" , |
123 | .adc_channel_label = "acin_i" , |
124 | }, { |
125 | .consumer_dev_name = "axp20x-battery-power-supply" , |
126 | .consumer_channel = "batt_v" , |
127 | .adc_channel_label = "batt_v" , |
128 | }, { |
129 | .consumer_dev_name = "axp20x-battery-power-supply" , |
130 | .consumer_channel = "batt_chrg_i" , |
131 | .adc_channel_label = "batt_chrg_i" , |
132 | }, { |
133 | .consumer_dev_name = "axp20x-battery-power-supply" , |
134 | .consumer_channel = "batt_dischrg_i" , |
135 | .adc_channel_label = "batt_dischrg_i" , |
136 | }, { /* sentinel */ } |
137 | }; |
138 | |
139 | static struct iio_map axp22x_maps[] = { |
140 | { |
141 | .consumer_dev_name = "axp20x-battery-power-supply" , |
142 | .consumer_channel = "batt_v" , |
143 | .adc_channel_label = "batt_v" , |
144 | }, { |
145 | .consumer_dev_name = "axp20x-battery-power-supply" , |
146 | .consumer_channel = "batt_chrg_i" , |
147 | .adc_channel_label = "batt_chrg_i" , |
148 | }, { |
149 | .consumer_dev_name = "axp20x-battery-power-supply" , |
150 | .consumer_channel = "batt_dischrg_i" , |
151 | .adc_channel_label = "batt_dischrg_i" , |
152 | }, { /* sentinel */ } |
153 | }; |
154 | |
155 | /* |
156 | * Channels are mapped by physical system. Their channels share the same index. |
157 | * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw. |
158 | * The only exception is for the battery. batt_v will be in_voltage6_raw and |
159 | * charge current in_current6_raw and discharge current will be in_current7_raw. |
160 | */ |
161 | static const struct iio_chan_spec axp20x_adc_channels[] = { |
162 | AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v" , IIO_VOLTAGE, |
163 | AXP20X_ACIN_V_ADC_H), |
164 | AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i" , IIO_CURRENT, |
165 | AXP20X_ACIN_I_ADC_H), |
166 | AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v" , IIO_VOLTAGE, |
167 | AXP20X_VBUS_V_ADC_H), |
168 | AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i" , IIO_CURRENT, |
169 | AXP20X_VBUS_I_ADC_H), |
170 | { |
171 | .type = IIO_TEMP, |
172 | .address = AXP20X_TEMP_ADC_H, |
173 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
174 | BIT(IIO_CHAN_INFO_SCALE) | |
175 | BIT(IIO_CHAN_INFO_OFFSET), |
176 | .datasheet_name = "pmic_temp" , |
177 | }, |
178 | AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v" , IIO_VOLTAGE, |
179 | AXP20X_GPIO0_V_ADC_H), |
180 | AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v" , IIO_VOLTAGE, |
181 | AXP20X_GPIO1_V_ADC_H), |
182 | AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v" , IIO_VOLTAGE, |
183 | AXP20X_IPSOUT_V_HIGH_H), |
184 | AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v" , IIO_VOLTAGE, |
185 | AXP20X_BATT_V_H), |
186 | AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i" , IIO_CURRENT, |
187 | AXP20X_BATT_CHRG_I_H), |
188 | AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i" , IIO_CURRENT, |
189 | AXP20X_BATT_DISCHRG_I_H), |
190 | AXP20X_ADC_CHANNEL(AXP20X_TS_IN, "ts_v" , IIO_VOLTAGE, |
191 | AXP20X_TS_IN_H), |
192 | }; |
193 | |
194 | static const struct iio_chan_spec axp22x_adc_channels[] = { |
195 | { |
196 | .type = IIO_TEMP, |
197 | .address = AXP22X_PMIC_TEMP_H, |
198 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
199 | BIT(IIO_CHAN_INFO_SCALE) | |
200 | BIT(IIO_CHAN_INFO_OFFSET), |
201 | .datasheet_name = "pmic_temp" , |
202 | }, |
203 | AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v" , IIO_VOLTAGE, |
204 | AXP20X_BATT_V_H), |
205 | AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i" , IIO_CURRENT, |
206 | AXP20X_BATT_CHRG_I_H), |
207 | AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i" , IIO_CURRENT, |
208 | AXP20X_BATT_DISCHRG_I_H), |
209 | AXP20X_ADC_CHANNEL(AXP22X_TS_IN, "ts_v" , IIO_VOLTAGE, |
210 | AXP22X_TS_ADC_H), |
211 | }; |
212 | |
213 | static const struct iio_chan_spec axp813_adc_channels[] = { |
214 | { |
215 | .type = IIO_TEMP, |
216 | .address = AXP22X_PMIC_TEMP_H, |
217 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
218 | BIT(IIO_CHAN_INFO_SCALE) | |
219 | BIT(IIO_CHAN_INFO_OFFSET), |
220 | .datasheet_name = "pmic_temp" , |
221 | }, |
222 | AXP20X_ADC_CHANNEL(AXP813_GPIO0_V, "gpio0_v" , IIO_VOLTAGE, |
223 | AXP288_GP_ADC_H), |
224 | AXP20X_ADC_CHANNEL(AXP813_BATT_V, "batt_v" , IIO_VOLTAGE, |
225 | AXP20X_BATT_V_H), |
226 | AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i" , IIO_CURRENT, |
227 | AXP20X_BATT_CHRG_I_H), |
228 | AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i" , IIO_CURRENT, |
229 | AXP20X_BATT_DISCHRG_I_H), |
230 | AXP20X_ADC_CHANNEL(AXP813_TS_IN, "ts_v" , IIO_VOLTAGE, |
231 | AXP288_TS_ADC_H), |
232 | }; |
233 | |
234 | static int axp20x_adc_raw(struct iio_dev *indio_dev, |
235 | struct iio_chan_spec const *chan, int *val) |
236 | { |
237 | struct axp20x_adc_iio *info = iio_priv(indio_dev); |
238 | int ret, size; |
239 | |
240 | /* |
241 | * N.B.: Unlike the Chinese datasheets tell, the charging current is |
242 | * stored on 12 bits, not 13 bits. Only discharging current is on 13 |
243 | * bits. |
244 | */ |
245 | if (chan->type == IIO_CURRENT && chan->channel == AXP20X_BATT_DISCHRG_I) |
246 | size = 13; |
247 | else |
248 | size = 12; |
249 | |
250 | ret = axp20x_read_variable_width(regmap: info->regmap, reg: chan->address, width: size); |
251 | if (ret < 0) |
252 | return ret; |
253 | |
254 | *val = ret; |
255 | return IIO_VAL_INT; |
256 | } |
257 | |
258 | static int axp22x_adc_raw(struct iio_dev *indio_dev, |
259 | struct iio_chan_spec const *chan, int *val) |
260 | { |
261 | struct axp20x_adc_iio *info = iio_priv(indio_dev); |
262 | int ret; |
263 | |
264 | ret = axp20x_read_variable_width(regmap: info->regmap, reg: chan->address, width: 12); |
265 | if (ret < 0) |
266 | return ret; |
267 | |
268 | *val = ret; |
269 | return IIO_VAL_INT; |
270 | } |
271 | |
272 | static int axp813_adc_raw(struct iio_dev *indio_dev, |
273 | struct iio_chan_spec const *chan, int *val) |
274 | { |
275 | struct axp20x_adc_iio *info = iio_priv(indio_dev); |
276 | int ret; |
277 | |
278 | ret = axp20x_read_variable_width(regmap: info->regmap, reg: chan->address, width: 12); |
279 | if (ret < 0) |
280 | return ret; |
281 | |
282 | *val = ret; |
283 | return IIO_VAL_INT; |
284 | } |
285 | |
286 | static int axp20x_adc_scale_voltage(int channel, int *val, int *val2) |
287 | { |
288 | switch (channel) { |
289 | case AXP20X_ACIN_V: |
290 | case AXP20X_VBUS_V: |
291 | *val = 1; |
292 | *val2 = 700000; |
293 | return IIO_VAL_INT_PLUS_MICRO; |
294 | |
295 | case AXP20X_GPIO0_V: |
296 | case AXP20X_GPIO1_V: |
297 | *val = 0; |
298 | *val2 = 500000; |
299 | return IIO_VAL_INT_PLUS_MICRO; |
300 | |
301 | case AXP20X_BATT_V: |
302 | *val = 1; |
303 | *val2 = 100000; |
304 | return IIO_VAL_INT_PLUS_MICRO; |
305 | |
306 | case AXP20X_IPSOUT_V: |
307 | *val = 1; |
308 | *val2 = 400000; |
309 | return IIO_VAL_INT_PLUS_MICRO; |
310 | |
311 | case AXP20X_TS_IN: |
312 | /* 0.8 mV per LSB */ |
313 | *val = 0; |
314 | *val2 = 800000; |
315 | return IIO_VAL_INT_PLUS_MICRO; |
316 | |
317 | default: |
318 | return -EINVAL; |
319 | } |
320 | } |
321 | |
322 | static int axp22x_adc_scale_voltage(int channel, int *val, int *val2) |
323 | { |
324 | switch (channel) { |
325 | case AXP22X_BATT_V: |
326 | /* 1.1 mV per LSB */ |
327 | *val = 1; |
328 | *val2 = 100000; |
329 | return IIO_VAL_INT_PLUS_MICRO; |
330 | |
331 | case AXP22X_TS_IN: |
332 | /* 0.8 mV per LSB */ |
333 | *val = 0; |
334 | *val2 = 800000; |
335 | return IIO_VAL_INT_PLUS_MICRO; |
336 | |
337 | default: |
338 | return -EINVAL; |
339 | } |
340 | } |
341 | static int axp813_adc_scale_voltage(int channel, int *val, int *val2) |
342 | { |
343 | switch (channel) { |
344 | case AXP813_GPIO0_V: |
345 | *val = 0; |
346 | *val2 = 800000; |
347 | return IIO_VAL_INT_PLUS_MICRO; |
348 | |
349 | case AXP813_BATT_V: |
350 | *val = 1; |
351 | *val2 = 100000; |
352 | return IIO_VAL_INT_PLUS_MICRO; |
353 | |
354 | case AXP813_TS_IN: |
355 | /* 0.8 mV per LSB */ |
356 | *val = 0; |
357 | *val2 = 800000; |
358 | return IIO_VAL_INT_PLUS_MICRO; |
359 | |
360 | default: |
361 | return -EINVAL; |
362 | } |
363 | } |
364 | |
365 | static int axp20x_adc_scale_current(int channel, int *val, int *val2) |
366 | { |
367 | switch (channel) { |
368 | case AXP20X_ACIN_I: |
369 | *val = 0; |
370 | *val2 = 625000; |
371 | return IIO_VAL_INT_PLUS_MICRO; |
372 | |
373 | case AXP20X_VBUS_I: |
374 | *val = 0; |
375 | *val2 = 375000; |
376 | return IIO_VAL_INT_PLUS_MICRO; |
377 | |
378 | case AXP20X_BATT_DISCHRG_I: |
379 | case AXP20X_BATT_CHRG_I: |
380 | *val = 0; |
381 | *val2 = 500000; |
382 | return IIO_VAL_INT_PLUS_MICRO; |
383 | |
384 | default: |
385 | return -EINVAL; |
386 | } |
387 | } |
388 | |
389 | static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val, |
390 | int *val2) |
391 | { |
392 | switch (chan->type) { |
393 | case IIO_VOLTAGE: |
394 | return axp20x_adc_scale_voltage(channel: chan->channel, val, val2); |
395 | |
396 | case IIO_CURRENT: |
397 | return axp20x_adc_scale_current(channel: chan->channel, val, val2); |
398 | |
399 | case IIO_TEMP: |
400 | *val = 100; |
401 | return IIO_VAL_INT; |
402 | |
403 | default: |
404 | return -EINVAL; |
405 | } |
406 | } |
407 | |
408 | static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val, |
409 | int *val2) |
410 | { |
411 | switch (chan->type) { |
412 | case IIO_VOLTAGE: |
413 | return axp22x_adc_scale_voltage(channel: chan->channel, val, val2); |
414 | |
415 | case IIO_CURRENT: |
416 | *val = 1; |
417 | return IIO_VAL_INT; |
418 | |
419 | case IIO_TEMP: |
420 | *val = 100; |
421 | return IIO_VAL_INT; |
422 | |
423 | default: |
424 | return -EINVAL; |
425 | } |
426 | } |
427 | |
428 | static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val, |
429 | int *val2) |
430 | { |
431 | switch (chan->type) { |
432 | case IIO_VOLTAGE: |
433 | return axp813_adc_scale_voltage(channel: chan->channel, val, val2); |
434 | |
435 | case IIO_CURRENT: |
436 | *val = 1; |
437 | return IIO_VAL_INT; |
438 | |
439 | case IIO_TEMP: |
440 | *val = 100; |
441 | return IIO_VAL_INT; |
442 | |
443 | default: |
444 | return -EINVAL; |
445 | } |
446 | } |
447 | |
448 | static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel, |
449 | int *val) |
450 | { |
451 | struct axp20x_adc_iio *info = iio_priv(indio_dev); |
452 | unsigned int regval; |
453 | int ret; |
454 | |
455 | ret = regmap_read(map: info->regmap, AXP20X_GPIO10_IN_RANGE, val: ®val); |
456 | if (ret < 0) |
457 | return ret; |
458 | |
459 | switch (channel) { |
460 | case AXP20X_GPIO0_V: |
461 | regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO0, regval); |
462 | break; |
463 | |
464 | case AXP20X_GPIO1_V: |
465 | regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO1, regval); |
466 | break; |
467 | |
468 | default: |
469 | return -EINVAL; |
470 | } |
471 | |
472 | *val = regval ? 700000 : 0; |
473 | return IIO_VAL_INT; |
474 | } |
475 | |
476 | static int axp20x_adc_offset(struct iio_dev *indio_dev, |
477 | struct iio_chan_spec const *chan, int *val) |
478 | { |
479 | switch (chan->type) { |
480 | case IIO_VOLTAGE: |
481 | return axp20x_adc_offset_voltage(indio_dev, channel: chan->channel, val); |
482 | |
483 | case IIO_TEMP: |
484 | *val = -1447; |
485 | return IIO_VAL_INT; |
486 | |
487 | default: |
488 | return -EINVAL; |
489 | } |
490 | } |
491 | |
492 | static int axp20x_read_raw(struct iio_dev *indio_dev, |
493 | struct iio_chan_spec const *chan, int *val, |
494 | int *val2, long mask) |
495 | { |
496 | switch (mask) { |
497 | case IIO_CHAN_INFO_OFFSET: |
498 | return axp20x_adc_offset(indio_dev, chan, val); |
499 | |
500 | case IIO_CHAN_INFO_SCALE: |
501 | return axp20x_adc_scale(chan, val, val2); |
502 | |
503 | case IIO_CHAN_INFO_RAW: |
504 | return axp20x_adc_raw(indio_dev, chan, val); |
505 | |
506 | default: |
507 | return -EINVAL; |
508 | } |
509 | } |
510 | |
511 | static int axp22x_read_raw(struct iio_dev *indio_dev, |
512 | struct iio_chan_spec const *chan, int *val, |
513 | int *val2, long mask) |
514 | { |
515 | switch (mask) { |
516 | case IIO_CHAN_INFO_OFFSET: |
517 | /* For PMIC temp only */ |
518 | *val = -2677; |
519 | return IIO_VAL_INT; |
520 | |
521 | case IIO_CHAN_INFO_SCALE: |
522 | return axp22x_adc_scale(chan, val, val2); |
523 | |
524 | case IIO_CHAN_INFO_RAW: |
525 | return axp22x_adc_raw(indio_dev, chan, val); |
526 | |
527 | default: |
528 | return -EINVAL; |
529 | } |
530 | } |
531 | |
532 | static int axp813_read_raw(struct iio_dev *indio_dev, |
533 | struct iio_chan_spec const *chan, int *val, |
534 | int *val2, long mask) |
535 | { |
536 | switch (mask) { |
537 | case IIO_CHAN_INFO_OFFSET: |
538 | *val = -2667; |
539 | return IIO_VAL_INT; |
540 | |
541 | case IIO_CHAN_INFO_SCALE: |
542 | return axp813_adc_scale(chan, val, val2); |
543 | |
544 | case IIO_CHAN_INFO_RAW: |
545 | return axp813_adc_raw(indio_dev, chan, val); |
546 | |
547 | default: |
548 | return -EINVAL; |
549 | } |
550 | } |
551 | |
552 | static int axp20x_write_raw(struct iio_dev *indio_dev, |
553 | struct iio_chan_spec const *chan, int val, int val2, |
554 | long mask) |
555 | { |
556 | struct axp20x_adc_iio *info = iio_priv(indio_dev); |
557 | unsigned int regmask, regval; |
558 | |
559 | /* |
560 | * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets |
561 | * for (independently) GPIO0 and GPIO1 when in ADC mode. |
562 | */ |
563 | if (mask != IIO_CHAN_INFO_OFFSET) |
564 | return -EINVAL; |
565 | |
566 | if (val != 0 && val != 700000) |
567 | return -EINVAL; |
568 | |
569 | switch (chan->channel) { |
570 | case AXP20X_GPIO0_V: |
571 | regmask = AXP20X_GPIO10_IN_RANGE_GPIO0; |
572 | regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO0, !!val); |
573 | break; |
574 | |
575 | case AXP20X_GPIO1_V: |
576 | regmask = AXP20X_GPIO10_IN_RANGE_GPIO1; |
577 | regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO1, !!val); |
578 | break; |
579 | |
580 | default: |
581 | return -EINVAL; |
582 | } |
583 | |
584 | return regmap_update_bits(map: info->regmap, AXP20X_GPIO10_IN_RANGE, mask: regmask, val: regval); |
585 | } |
586 | |
587 | static const struct iio_info axp20x_adc_iio_info = { |
588 | .read_raw = axp20x_read_raw, |
589 | .write_raw = axp20x_write_raw, |
590 | }; |
591 | |
592 | static const struct iio_info axp22x_adc_iio_info = { |
593 | .read_raw = axp22x_read_raw, |
594 | }; |
595 | |
596 | static const struct iio_info axp813_adc_iio_info = { |
597 | .read_raw = axp813_read_raw, |
598 | }; |
599 | |
600 | static int axp20x_adc_rate(struct axp20x_adc_iio *info, int rate) |
601 | { |
602 | return regmap_update_bits(map: info->regmap, AXP20X_ADC_RATE, |
603 | AXP20X_ADC_RATE_MASK, |
604 | AXP20X_ADC_RATE_HZ(rate)); |
605 | } |
606 | |
607 | static int axp22x_adc_rate(struct axp20x_adc_iio *info, int rate) |
608 | { |
609 | return regmap_update_bits(map: info->regmap, AXP20X_ADC_RATE, |
610 | AXP20X_ADC_RATE_MASK, |
611 | AXP22X_ADC_RATE_HZ(rate)); |
612 | } |
613 | |
614 | static int axp813_adc_rate(struct axp20x_adc_iio *info, int rate) |
615 | { |
616 | return regmap_update_bits(map: info->regmap, AXP813_ADC_RATE, |
617 | AXP813_ADC_RATE_MASK, |
618 | AXP813_ADC_RATE_HZ(rate)); |
619 | } |
620 | |
621 | struct axp_data { |
622 | const struct iio_info *iio_info; |
623 | int num_channels; |
624 | struct iio_chan_spec const *channels; |
625 | unsigned long adc_en1_mask; |
626 | unsigned long adc_en2_mask; |
627 | int (*adc_rate)(struct axp20x_adc_iio *info, |
628 | int rate); |
629 | struct iio_map *maps; |
630 | }; |
631 | |
632 | static const struct axp_data axp20x_data = { |
633 | .iio_info = &axp20x_adc_iio_info, |
634 | .num_channels = ARRAY_SIZE(axp20x_adc_channels), |
635 | .channels = axp20x_adc_channels, |
636 | .adc_en1_mask = AXP20X_ADC_EN1_MASK, |
637 | .adc_en2_mask = AXP20X_ADC_EN2_MASK, |
638 | .adc_rate = axp20x_adc_rate, |
639 | .maps = axp20x_maps, |
640 | }; |
641 | |
642 | static const struct axp_data axp22x_data = { |
643 | .iio_info = &axp22x_adc_iio_info, |
644 | .num_channels = ARRAY_SIZE(axp22x_adc_channels), |
645 | .channels = axp22x_adc_channels, |
646 | .adc_en1_mask = AXP22X_ADC_EN1_MASK, |
647 | .adc_rate = axp22x_adc_rate, |
648 | .maps = axp22x_maps, |
649 | }; |
650 | |
651 | static const struct axp_data axp813_data = { |
652 | .iio_info = &axp813_adc_iio_info, |
653 | .num_channels = ARRAY_SIZE(axp813_adc_channels), |
654 | .channels = axp813_adc_channels, |
655 | .adc_en1_mask = AXP22X_ADC_EN1_MASK, |
656 | .adc_rate = axp813_adc_rate, |
657 | .maps = axp22x_maps, |
658 | }; |
659 | |
660 | static const struct of_device_id axp20x_adc_of_match[] = { |
661 | { .compatible = "x-powers,axp209-adc" , .data = (void *)&axp20x_data, }, |
662 | { .compatible = "x-powers,axp221-adc" , .data = (void *)&axp22x_data, }, |
663 | { .compatible = "x-powers,axp813-adc" , .data = (void *)&axp813_data, }, |
664 | { /* sentinel */ } |
665 | }; |
666 | MODULE_DEVICE_TABLE(of, axp20x_adc_of_match); |
667 | |
668 | static const struct platform_device_id axp20x_adc_id_match[] = { |
669 | { .name = "axp20x-adc" , .driver_data = (kernel_ulong_t)&axp20x_data, }, |
670 | { .name = "axp22x-adc" , .driver_data = (kernel_ulong_t)&axp22x_data, }, |
671 | { .name = "axp813-adc" , .driver_data = (kernel_ulong_t)&axp813_data, }, |
672 | { /* sentinel */ }, |
673 | }; |
674 | MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match); |
675 | |
676 | static int axp20x_probe(struct platform_device *pdev) |
677 | { |
678 | struct axp20x_adc_iio *info; |
679 | struct iio_dev *indio_dev; |
680 | struct axp20x_dev *axp20x_dev; |
681 | int ret; |
682 | |
683 | axp20x_dev = dev_get_drvdata(dev: pdev->dev.parent); |
684 | |
685 | indio_dev = devm_iio_device_alloc(parent: &pdev->dev, sizeof_priv: sizeof(*info)); |
686 | if (!indio_dev) |
687 | return -ENOMEM; |
688 | |
689 | info = iio_priv(indio_dev); |
690 | platform_set_drvdata(pdev, data: indio_dev); |
691 | |
692 | info->regmap = axp20x_dev->regmap; |
693 | indio_dev->modes = INDIO_DIRECT_MODE; |
694 | |
695 | if (!dev_fwnode(&pdev->dev)) { |
696 | const struct platform_device_id *id; |
697 | |
698 | id = platform_get_device_id(pdev); |
699 | info->data = (const struct axp_data *)id->driver_data; |
700 | } else { |
701 | struct device *dev = &pdev->dev; |
702 | |
703 | info->data = device_get_match_data(dev); |
704 | } |
705 | |
706 | indio_dev->name = platform_get_device_id(pdev)->name; |
707 | indio_dev->info = info->data->iio_info; |
708 | indio_dev->num_channels = info->data->num_channels; |
709 | indio_dev->channels = info->data->channels; |
710 | |
711 | /* Enable the ADCs on IP */ |
712 | regmap_write(map: info->regmap, AXP20X_ADC_EN1, val: info->data->adc_en1_mask); |
713 | |
714 | if (info->data->adc_en2_mask) |
715 | regmap_update_bits(map: info->regmap, AXP20X_ADC_EN2, |
716 | mask: info->data->adc_en2_mask, |
717 | val: info->data->adc_en2_mask); |
718 | |
719 | /* Configure ADCs rate */ |
720 | info->data->adc_rate(info, 100); |
721 | |
722 | ret = iio_map_array_register(indio_dev, map: info->data->maps); |
723 | if (ret < 0) { |
724 | dev_err(&pdev->dev, "failed to register IIO maps: %d\n" , ret); |
725 | goto fail_map; |
726 | } |
727 | |
728 | ret = iio_device_register(indio_dev); |
729 | if (ret < 0) { |
730 | dev_err(&pdev->dev, "could not register the device\n" ); |
731 | goto fail_register; |
732 | } |
733 | |
734 | return 0; |
735 | |
736 | fail_register: |
737 | iio_map_array_unregister(indio_dev); |
738 | |
739 | fail_map: |
740 | regmap_write(map: info->regmap, AXP20X_ADC_EN1, val: 0); |
741 | |
742 | if (info->data->adc_en2_mask) |
743 | regmap_write(map: info->regmap, AXP20X_ADC_EN2, val: 0); |
744 | |
745 | return ret; |
746 | } |
747 | |
748 | static void axp20x_remove(struct platform_device *pdev) |
749 | { |
750 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); |
751 | struct axp20x_adc_iio *info = iio_priv(indio_dev); |
752 | |
753 | iio_device_unregister(indio_dev); |
754 | iio_map_array_unregister(indio_dev); |
755 | |
756 | regmap_write(map: info->regmap, AXP20X_ADC_EN1, val: 0); |
757 | |
758 | if (info->data->adc_en2_mask) |
759 | regmap_write(map: info->regmap, AXP20X_ADC_EN2, val: 0); |
760 | } |
761 | |
762 | static struct platform_driver axp20x_adc_driver = { |
763 | .driver = { |
764 | .name = "axp20x-adc" , |
765 | .of_match_table = axp20x_adc_of_match, |
766 | }, |
767 | .id_table = axp20x_adc_id_match, |
768 | .probe = axp20x_probe, |
769 | .remove_new = axp20x_remove, |
770 | }; |
771 | |
772 | module_platform_driver(axp20x_adc_driver); |
773 | |
774 | MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs" ); |
775 | MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>" ); |
776 | MODULE_LICENSE("GPL" ); |
777 | |