1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * DA9150 GPADC Driver |
4 | * |
5 | * Copyright (c) 2014 Dialog Semiconductor |
6 | * |
7 | * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/module.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/mutex.h> |
16 | #include <linux/completion.h> |
17 | #include <linux/iio/iio.h> |
18 | #include <linux/iio/machine.h> |
19 | #include <linux/iio/driver.h> |
20 | #include <linux/mfd/da9150/core.h> |
21 | #include <linux/mfd/da9150/registers.h> |
22 | |
23 | /* Channels */ |
24 | enum da9150_gpadc_hw_channel { |
25 | DA9150_GPADC_HW_CHAN_GPIOA_2V = 0, |
26 | DA9150_GPADC_HW_CHAN_GPIOA_2V_, |
27 | DA9150_GPADC_HW_CHAN_GPIOB_2V, |
28 | DA9150_GPADC_HW_CHAN_GPIOB_2V_, |
29 | DA9150_GPADC_HW_CHAN_GPIOC_2V, |
30 | DA9150_GPADC_HW_CHAN_GPIOC_2V_, |
31 | DA9150_GPADC_HW_CHAN_GPIOD_2V, |
32 | DA9150_GPADC_HW_CHAN_GPIOD_2V_, |
33 | DA9150_GPADC_HW_CHAN_IBUS_SENSE, |
34 | DA9150_GPADC_HW_CHAN_IBUS_SENSE_, |
35 | DA9150_GPADC_HW_CHAN_VBUS_DIV, |
36 | DA9150_GPADC_HW_CHAN_VBUS_DIV_, |
37 | DA9150_GPADC_HW_CHAN_ID, |
38 | DA9150_GPADC_HW_CHAN_ID_, |
39 | DA9150_GPADC_HW_CHAN_VSYS, |
40 | DA9150_GPADC_HW_CHAN_VSYS_, |
41 | DA9150_GPADC_HW_CHAN_GPIOA_6V, |
42 | DA9150_GPADC_HW_CHAN_GPIOA_6V_, |
43 | DA9150_GPADC_HW_CHAN_GPIOB_6V, |
44 | DA9150_GPADC_HW_CHAN_GPIOB_6V_, |
45 | DA9150_GPADC_HW_CHAN_GPIOC_6V, |
46 | DA9150_GPADC_HW_CHAN_GPIOC_6V_, |
47 | DA9150_GPADC_HW_CHAN_GPIOD_6V, |
48 | DA9150_GPADC_HW_CHAN_GPIOD_6V_, |
49 | DA9150_GPADC_HW_CHAN_VBAT, |
50 | DA9150_GPADC_HW_CHAN_VBAT_, |
51 | DA9150_GPADC_HW_CHAN_TBAT, |
52 | DA9150_GPADC_HW_CHAN_TBAT_, |
53 | DA9150_GPADC_HW_CHAN_TJUNC_CORE, |
54 | DA9150_GPADC_HW_CHAN_TJUNC_CORE_, |
55 | DA9150_GPADC_HW_CHAN_TJUNC_OVP, |
56 | DA9150_GPADC_HW_CHAN_TJUNC_OVP_, |
57 | }; |
58 | |
59 | enum da9150_gpadc_channel { |
60 | DA9150_GPADC_CHAN_GPIOA = 0, |
61 | DA9150_GPADC_CHAN_GPIOB, |
62 | DA9150_GPADC_CHAN_GPIOC, |
63 | DA9150_GPADC_CHAN_GPIOD, |
64 | DA9150_GPADC_CHAN_IBUS, |
65 | DA9150_GPADC_CHAN_VBUS, |
66 | DA9150_GPADC_CHAN_VSYS, |
67 | DA9150_GPADC_CHAN_VBAT, |
68 | DA9150_GPADC_CHAN_TBAT, |
69 | DA9150_GPADC_CHAN_TJUNC_CORE, |
70 | DA9150_GPADC_CHAN_TJUNC_OVP, |
71 | }; |
72 | |
73 | /* Private data */ |
74 | struct da9150_gpadc { |
75 | struct da9150 *da9150; |
76 | struct device *dev; |
77 | |
78 | struct mutex lock; |
79 | struct completion complete; |
80 | }; |
81 | |
82 | |
83 | static irqreturn_t da9150_gpadc_irq(int irq, void *data) |
84 | { |
85 | |
86 | struct da9150_gpadc *gpadc = data; |
87 | |
88 | complete(&gpadc->complete); |
89 | |
90 | return IRQ_HANDLED; |
91 | } |
92 | |
93 | static int da9150_gpadc_read_adc(struct da9150_gpadc *gpadc, int hw_chan) |
94 | { |
95 | u8 result_regs[2]; |
96 | int result; |
97 | |
98 | mutex_lock(&gpadc->lock); |
99 | |
100 | /* Set channel & enable measurement */ |
101 | da9150_reg_write(da9150: gpadc->da9150, DA9150_GPADC_MAN, |
102 | val: (DA9150_GPADC_EN_MASK | |
103 | hw_chan << DA9150_GPADC_MUX_SHIFT)); |
104 | |
105 | /* Consume left-over completion from a previous timeout */ |
106 | try_wait_for_completion(x: &gpadc->complete); |
107 | |
108 | /* Check for actual completion */ |
109 | wait_for_completion_timeout(x: &gpadc->complete, timeout: msecs_to_jiffies(m: 5)); |
110 | |
111 | /* Read result and status from device */ |
112 | da9150_bulk_read(da9150: gpadc->da9150, DA9150_GPADC_RES_A, count: 2, buf: result_regs); |
113 | |
114 | mutex_unlock(lock: &gpadc->lock); |
115 | |
116 | /* Check to make sure device really has completed reading */ |
117 | if (result_regs[1] & DA9150_GPADC_RUN_MASK) { |
118 | dev_err(gpadc->dev, "Timeout on channel %d of GPADC\n" , |
119 | hw_chan); |
120 | return -ETIMEDOUT; |
121 | } |
122 | |
123 | /* LSBs - 2 bits */ |
124 | result = (result_regs[1] & DA9150_GPADC_RES_L_MASK) >> |
125 | DA9150_GPADC_RES_L_SHIFT; |
126 | /* MSBs - 8 bits */ |
127 | result |= result_regs[0] << DA9150_GPADC_RES_L_BITS; |
128 | |
129 | return result; |
130 | } |
131 | |
132 | static inline int da9150_gpadc_gpio_6v_voltage_now(int raw_val) |
133 | { |
134 | /* Convert to mV */ |
135 | return (6 * ((raw_val * 1000) + 500)) / 1024; |
136 | } |
137 | |
138 | static inline int da9150_gpadc_ibus_current_avg(int raw_val) |
139 | { |
140 | /* Convert to mA */ |
141 | return (4 * ((raw_val * 1000) + 500)) / 2048; |
142 | } |
143 | |
144 | static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val) |
145 | { |
146 | /* Convert to mV */ |
147 | return (21 * ((raw_val * 1000) + 500)) / 1024; |
148 | } |
149 | |
150 | static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val) |
151 | { |
152 | /* Convert to mV */ |
153 | return (3 * ((raw_val * 1000) + 500)) / 512; |
154 | } |
155 | |
156 | static int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel, |
157 | int hw_chan, int *val) |
158 | { |
159 | int raw_val; |
160 | |
161 | raw_val = da9150_gpadc_read_adc(gpadc, hw_chan); |
162 | if (raw_val < 0) |
163 | return raw_val; |
164 | |
165 | switch (channel) { |
166 | case DA9150_GPADC_CHAN_GPIOA: |
167 | case DA9150_GPADC_CHAN_GPIOB: |
168 | case DA9150_GPADC_CHAN_GPIOC: |
169 | case DA9150_GPADC_CHAN_GPIOD: |
170 | *val = da9150_gpadc_gpio_6v_voltage_now(raw_val); |
171 | break; |
172 | case DA9150_GPADC_CHAN_IBUS: |
173 | *val = da9150_gpadc_ibus_current_avg(raw_val); |
174 | break; |
175 | case DA9150_GPADC_CHAN_VBUS: |
176 | *val = da9150_gpadc_vbus_21v_voltage_now(raw_val); |
177 | break; |
178 | case DA9150_GPADC_CHAN_VSYS: |
179 | *val = da9150_gpadc_vsys_6v_voltage_now(raw_val); |
180 | break; |
181 | default: |
182 | /* No processing for other channels so return raw value */ |
183 | *val = raw_val; |
184 | break; |
185 | } |
186 | |
187 | return IIO_VAL_INT; |
188 | } |
189 | |
190 | static int da9150_gpadc_read_scale(int channel, int *val, int *val2) |
191 | { |
192 | switch (channel) { |
193 | case DA9150_GPADC_CHAN_VBAT: |
194 | *val = 2932; |
195 | *val2 = 1000; |
196 | return IIO_VAL_FRACTIONAL; |
197 | case DA9150_GPADC_CHAN_TJUNC_CORE: |
198 | case DA9150_GPADC_CHAN_TJUNC_OVP: |
199 | *val = 1000000; |
200 | *val2 = 4420; |
201 | return IIO_VAL_FRACTIONAL; |
202 | default: |
203 | return -EINVAL; |
204 | } |
205 | } |
206 | |
207 | static int da9150_gpadc_read_offset(int channel, int *val) |
208 | { |
209 | switch (channel) { |
210 | case DA9150_GPADC_CHAN_VBAT: |
211 | *val = 1500000 / 2932; |
212 | return IIO_VAL_INT; |
213 | case DA9150_GPADC_CHAN_TJUNC_CORE: |
214 | case DA9150_GPADC_CHAN_TJUNC_OVP: |
215 | *val = -144; |
216 | return IIO_VAL_INT; |
217 | default: |
218 | return -EINVAL; |
219 | } |
220 | } |
221 | |
222 | static int da9150_gpadc_read_raw(struct iio_dev *indio_dev, |
223 | struct iio_chan_spec const *chan, |
224 | int *val, int *val2, long mask) |
225 | { |
226 | struct da9150_gpadc *gpadc = iio_priv(indio_dev); |
227 | |
228 | if ((chan->channel < DA9150_GPADC_CHAN_GPIOA) || |
229 | (chan->channel > DA9150_GPADC_CHAN_TJUNC_OVP)) |
230 | return -EINVAL; |
231 | |
232 | switch (mask) { |
233 | case IIO_CHAN_INFO_RAW: |
234 | case IIO_CHAN_INFO_PROCESSED: |
235 | return da9150_gpadc_read_processed(gpadc, channel: chan->channel, |
236 | hw_chan: chan->address, val); |
237 | case IIO_CHAN_INFO_SCALE: |
238 | return da9150_gpadc_read_scale(channel: chan->channel, val, val2); |
239 | case IIO_CHAN_INFO_OFFSET: |
240 | return da9150_gpadc_read_offset(channel: chan->channel, val); |
241 | default: |
242 | return -EINVAL; |
243 | } |
244 | } |
245 | |
246 | static const struct iio_info da9150_gpadc_info = { |
247 | .read_raw = &da9150_gpadc_read_raw, |
248 | }; |
249 | |
250 | #define DA9150_GPADC_CHANNEL(_id, _hw_id, _type, chan_info, \ |
251 | _ext_name) { \ |
252 | .type = _type, \ |
253 | .indexed = 1, \ |
254 | .channel = DA9150_GPADC_CHAN_##_id, \ |
255 | .address = DA9150_GPADC_HW_CHAN_##_hw_id, \ |
256 | .info_mask_separate = chan_info, \ |
257 | .extend_name = _ext_name, \ |
258 | .datasheet_name = #_id, \ |
259 | } |
260 | |
261 | #define DA9150_GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name) \ |
262 | DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \ |
263 | BIT(IIO_CHAN_INFO_RAW), _ext_name) |
264 | |
265 | #define DA9150_GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name) \ |
266 | DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \ |
267 | BIT(IIO_CHAN_INFO_RAW) | \ |
268 | BIT(IIO_CHAN_INFO_SCALE) | \ |
269 | BIT(IIO_CHAN_INFO_OFFSET), \ |
270 | _ext_name) |
271 | |
272 | #define DA9150_GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name) \ |
273 | DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \ |
274 | BIT(IIO_CHAN_INFO_PROCESSED), _ext_name) |
275 | |
276 | /* Supported channels */ |
277 | static const struct iio_chan_spec da9150_gpadc_channels[] = { |
278 | DA9150_GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_6V, IIO_VOLTAGE, NULL), |
279 | DA9150_GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_6V, IIO_VOLTAGE, NULL), |
280 | DA9150_GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_6V, IIO_VOLTAGE, NULL), |
281 | DA9150_GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_6V, IIO_VOLTAGE, NULL), |
282 | DA9150_GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "ibus" ), |
283 | DA9150_GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "vbus" ), |
284 | DA9150_GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "vsys" ), |
285 | DA9150_GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "vbat" ), |
286 | DA9150_GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "tbat" ), |
287 | DA9150_GPADC_CHANNEL_SCALED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP, |
288 | "tjunc_core" ), |
289 | DA9150_GPADC_CHANNEL_SCALED(TJUNC_OVP, TJUNC_OVP, IIO_TEMP, |
290 | "tjunc_ovp" ), |
291 | }; |
292 | |
293 | /* Default maps used by da9150-charger */ |
294 | static struct iio_map da9150_gpadc_default_maps[] = { |
295 | { |
296 | .consumer_dev_name = "da9150-charger" , |
297 | .consumer_channel = "CHAN_IBUS" , |
298 | .adc_channel_label = "IBUS" , |
299 | }, |
300 | { |
301 | .consumer_dev_name = "da9150-charger" , |
302 | .consumer_channel = "CHAN_VBUS" , |
303 | .adc_channel_label = "VBUS" , |
304 | }, |
305 | { |
306 | .consumer_dev_name = "da9150-charger" , |
307 | .consumer_channel = "CHAN_TJUNC" , |
308 | .adc_channel_label = "TJUNC_CORE" , |
309 | }, |
310 | { |
311 | .consumer_dev_name = "da9150-charger" , |
312 | .consumer_channel = "CHAN_VBAT" , |
313 | .adc_channel_label = "VBAT" , |
314 | }, |
315 | {}, |
316 | }; |
317 | |
318 | static int da9150_gpadc_probe(struct platform_device *pdev) |
319 | { |
320 | struct device *dev = &pdev->dev; |
321 | struct da9150 *da9150 = dev_get_drvdata(dev: dev->parent); |
322 | struct da9150_gpadc *gpadc; |
323 | struct iio_dev *indio_dev; |
324 | int irq, ret; |
325 | |
326 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*gpadc)); |
327 | if (!indio_dev) { |
328 | dev_err(&pdev->dev, "Failed to allocate IIO device\n" ); |
329 | return -ENOMEM; |
330 | } |
331 | gpadc = iio_priv(indio_dev); |
332 | |
333 | gpadc->da9150 = da9150; |
334 | gpadc->dev = dev; |
335 | mutex_init(&gpadc->lock); |
336 | init_completion(x: &gpadc->complete); |
337 | |
338 | irq = platform_get_irq_byname(pdev, "GPADC" ); |
339 | if (irq < 0) |
340 | return irq; |
341 | |
342 | ret = devm_request_threaded_irq(dev, irq, NULL, thread_fn: da9150_gpadc_irq, |
343 | IRQF_ONESHOT, devname: "GPADC" , dev_id: gpadc); |
344 | if (ret) { |
345 | dev_err(dev, "Failed to request IRQ %d: %d\n" , irq, ret); |
346 | return ret; |
347 | } |
348 | |
349 | ret = devm_iio_map_array_register(dev: &pdev->dev, indio_dev, maps: da9150_gpadc_default_maps); |
350 | if (ret) { |
351 | dev_err(dev, "Failed to register IIO maps: %d\n" , ret); |
352 | return ret; |
353 | } |
354 | |
355 | indio_dev->name = dev_name(dev); |
356 | indio_dev->info = &da9150_gpadc_info; |
357 | indio_dev->modes = INDIO_DIRECT_MODE; |
358 | indio_dev->channels = da9150_gpadc_channels; |
359 | indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels); |
360 | |
361 | return devm_iio_device_register(&pdev->dev, indio_dev); |
362 | } |
363 | |
364 | static struct platform_driver da9150_gpadc_driver = { |
365 | .driver = { |
366 | .name = "da9150-gpadc" , |
367 | }, |
368 | .probe = da9150_gpadc_probe, |
369 | }; |
370 | |
371 | module_platform_driver(da9150_gpadc_driver); |
372 | |
373 | MODULE_DESCRIPTION("GPADC Driver for DA9150" ); |
374 | MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>" ); |
375 | MODULE_LICENSE("GPL" ); |
376 | |