blob: 1b35bf22014f9f038c04bd46924e0101c347385f [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +01002/*
3 * Copyright (C) 2015 Samsung Electronics
4 * Przemyslaw Marczak <p.marczak@samsung.com>
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +01005 */
6
Patrick Delaunayb953ec22021-04-27 11:02:19 +02007#define LOG_CATEGORY UCLASS_ADC
8
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +01009#include <common.h>
10#include <errno.h>
Fabrice Gasnier63f004e2018-11-12 14:03:58 +010011#include <div64.h>
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010012#include <dm.h>
13#include <dm/lists.h>
14#include <dm/device-internal.h>
15#include <dm/uclass-internal.h>
16#include <adc.h>
Simon Glassc05ed002020-05-10 11:40:11 -060017#include <linux/delay.h>
Simon Glass1e94b462023-09-14 18:21:46 -060018#include <linux/printk.h>
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010019#include <power/regulator.h>
20
Simon Glasscaa4daa2020-12-03 16:55:18 -070021#define ADC_UCLASS_PLATDATA_SIZE sizeof(struct adc_uclass_plat)
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010022#define CHECK_NUMBER true
23#define CHECK_MASK (!CHECK_NUMBER)
24
25/* TODO: add support for timer uclass (for early calls) */
Tom Rinic4659712022-12-02 16:42:43 -050026#ifdef CONFIG_SANDBOX
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010027#define sdelay(x) udelay(x)
28#else
29extern void sdelay(unsigned long loops);
30#endif
31
32static int check_channel(struct udevice *dev, int value, bool number_or_mask,
33 const char *caller_function)
34{
Simon Glasscaa4daa2020-12-03 16:55:18 -070035 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010036 unsigned mask = number_or_mask ? (1 << value) : value;
37
38 /* For the real ADC hardware, some ADC channels can be inactive.
39 * For example if device has 4 analog channels, and only channels
40 * 1-st and 3-rd are valid, then channel mask is: 0b1010, so request
41 * with mask 0b1110 should return an error.
42 */
43 if ((uc_pdata->channel_mask >= mask) && (uc_pdata->channel_mask & mask))
44 return 0;
45
46 printf("Error in %s/%s().\nWrong channel selection for device: %s\n",
47 __FILE__, caller_function, dev->name);
48
49 return -EINVAL;
50}
51
52static int adc_supply_enable(struct udevice *dev)
53{
Simon Glasscaa4daa2020-12-03 16:55:18 -070054 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Jonas Karlmand82cbc52023-07-19 21:20:55 +000055 int ret;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010056
Jonas Karlmand82cbc52023-07-19 21:20:55 +000057 ret = regulator_set_enable_if_allowed(uc_pdata->vdd_supply, true);
58 if (ret && ret != -ENOSYS) {
59 pr_err("%s: can't enable vdd-supply!", dev->name);
60 return ret;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010061 }
62
Jonas Karlmand82cbc52023-07-19 21:20:55 +000063 ret = regulator_set_enable_if_allowed(uc_pdata->vss_supply, true);
64 if (ret && ret != -ENOSYS) {
65 pr_err("%s: can't enable vss-supply!", dev->name);
66 return ret;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010067 }
68
Jonas Karlmand82cbc52023-07-19 21:20:55 +000069 return 0;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010070}
71
72int adc_data_mask(struct udevice *dev, unsigned int *data_mask)
73{
Simon Glasscaa4daa2020-12-03 16:55:18 -070074 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010075
76 if (!uc_pdata)
77 return -ENOSYS;
78
79 *data_mask = uc_pdata->data_mask;
80 return 0;
81}
82
Fabrice Gasnier63f004e2018-11-12 14:03:58 +010083int adc_channel_mask(struct udevice *dev, unsigned int *channel_mask)
84{
Simon Glasscaa4daa2020-12-03 16:55:18 -070085 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Fabrice Gasnier63f004e2018-11-12 14:03:58 +010086
87 if (!uc_pdata)
88 return -ENOSYS;
89
90 *channel_mask = uc_pdata->channel_mask;
91
92 return 0;
93}
94
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +010095int adc_stop(struct udevice *dev)
96{
97 const struct adc_ops *ops = dev_get_driver_ops(dev);
98
99 if (!ops->stop)
100 return -ENOSYS;
101
102 return ops->stop(dev);
103}
104
105int adc_start_channel(struct udevice *dev, int channel)
106{
107 const struct adc_ops *ops = dev_get_driver_ops(dev);
108 int ret;
109
110 if (!ops->start_channel)
111 return -ENOSYS;
112
113 ret = check_channel(dev, channel, CHECK_NUMBER, __func__);
114 if (ret)
115 return ret;
116
117 ret = adc_supply_enable(dev);
118 if (ret)
119 return ret;
120
121 return ops->start_channel(dev, channel);
122}
123
124int adc_start_channels(struct udevice *dev, unsigned int channel_mask)
125{
126 const struct adc_ops *ops = dev_get_driver_ops(dev);
127 int ret;
128
129 if (!ops->start_channels)
130 return -ENOSYS;
131
132 ret = check_channel(dev, channel_mask, CHECK_MASK, __func__);
133 if (ret)
134 return ret;
135
136 ret = adc_supply_enable(dev);
137 if (ret)
138 return ret;
139
140 return ops->start_channels(dev, channel_mask);
141}
142
143int adc_channel_data(struct udevice *dev, int channel, unsigned int *data)
144{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700145 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100146 const struct adc_ops *ops = dev_get_driver_ops(dev);
147 unsigned int timeout_us = uc_pdata->data_timeout_us;
148 int ret;
149
150 if (!ops->channel_data)
151 return -ENOSYS;
152
153 ret = check_channel(dev, channel, CHECK_NUMBER, __func__);
154 if (ret)
155 return ret;
156
157 do {
158 ret = ops->channel_data(dev, channel, data);
159 if (!ret || ret != -EBUSY)
160 break;
161
162 /* TODO: use timer uclass (for early calls). */
163 sdelay(5);
164 } while (timeout_us--);
165
166 return ret;
167}
168
169int adc_channels_data(struct udevice *dev, unsigned int channel_mask,
170 struct adc_channel *channels)
171{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700172 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100173 unsigned int timeout_us = uc_pdata->multidata_timeout_us;
174 const struct adc_ops *ops = dev_get_driver_ops(dev);
175 int ret;
176
177 if (!ops->channels_data)
178 return -ENOSYS;
179
180 ret = check_channel(dev, channel_mask, CHECK_MASK, __func__);
181 if (ret)
182 return ret;
183
184 do {
185 ret = ops->channels_data(dev, channel_mask, channels);
186 if (!ret || ret != -EBUSY)
187 break;
188
189 /* TODO: use timer uclass (for early calls). */
190 sdelay(5);
191 } while (timeout_us--);
192
193 return ret;
194}
195
196int adc_channel_single_shot(const char *name, int channel, unsigned int *data)
197{
198 struct udevice *dev;
199 int ret;
200
201 ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
202 if (ret)
203 return ret;
204
205 ret = adc_start_channel(dev, channel);
206 if (ret)
207 return ret;
208
209 ret = adc_channel_data(dev, channel, data);
210 if (ret)
211 return ret;
212
213 return 0;
214}
215
216static int _adc_channels_single_shot(struct udevice *dev,
217 unsigned int channel_mask,
218 struct adc_channel *channels)
219{
220 unsigned int data;
221 int channel, ret;
222
223 for (channel = 0; channel <= ADC_MAX_CHANNEL; channel++) {
224 /* Check channel bit. */
225 if (!((channel_mask >> channel) & 0x1))
226 continue;
227
228 ret = adc_start_channel(dev, channel);
229 if (ret)
230 return ret;
231
232 ret = adc_channel_data(dev, channel, &data);
233 if (ret)
234 return ret;
235
236 channels->id = channel;
237 channels->data = data;
238 channels++;
239 }
240
241 return 0;
242}
243
244int adc_channels_single_shot(const char *name, unsigned int channel_mask,
245 struct adc_channel *channels)
246{
247 struct udevice *dev;
248 int ret;
249
250 ret = uclass_get_device_by_name(UCLASS_ADC, name, &dev);
251 if (ret)
252 return ret;
253
254 ret = adc_start_channels(dev, channel_mask);
255 if (ret)
256 goto try_manual;
257
258 ret = adc_channels_data(dev, channel_mask, channels);
259 if (ret)
260 return ret;
261
262 return 0;
263
264try_manual:
265 if (ret != -ENOSYS)
266 return ret;
267
268 return _adc_channels_single_shot(dev, channel_mask, channels);
269}
270
Simon Glass8a8d24b2020-12-03 16:55:23 -0700271static int adc_vdd_plat_update(struct udevice *dev)
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100272{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700273 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100274 int ret;
275
276 /* Warning!
277 * This function can't return supply device before its bind.
278 * Please pay attention to proper fdt scan sequence. If ADC device
279 * will bind before its supply regulator device, then the below 'get'
280 * will return an error.
281 */
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200282 if (!uc_pdata->vdd_supply)
283 return 0;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100284
285 ret = regulator_get_value(uc_pdata->vdd_supply);
286 if (ret < 0)
287 return ret;
288
289 uc_pdata->vdd_microvolts = ret;
290
291 return 0;
292}
293
Simon Glass8a8d24b2020-12-03 16:55:23 -0700294static int adc_vss_plat_update(struct udevice *dev)
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100295{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700296 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100297 int ret;
298
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200299 if (!uc_pdata->vss_supply)
300 return 0;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100301
302 ret = regulator_get_value(uc_pdata->vss_supply);
303 if (ret < 0)
304 return ret;
305
306 uc_pdata->vss_microvolts = ret;
307
308 return 0;
309}
310
311int adc_vdd_value(struct udevice *dev, int *uV)
312{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700313 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100314 int ret, value_sign = uc_pdata->vdd_polarity_negative ? -1 : 1;
315
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100316 /* Update the regulator Value. */
Simon Glass8a8d24b2020-12-03 16:55:23 -0700317 ret = adc_vdd_plat_update(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100318 if (ret)
319 return ret;
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200320
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100321 if (uc_pdata->vdd_microvolts == -ENODATA)
322 return -ENODATA;
323
324 *uV = uc_pdata->vdd_microvolts * value_sign;
325
326 return 0;
327}
328
329int adc_vss_value(struct udevice *dev, int *uV)
330{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700331 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100332 int ret, value_sign = uc_pdata->vss_polarity_negative ? -1 : 1;
333
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100334 /* Update the regulator Value. */
Simon Glass8a8d24b2020-12-03 16:55:23 -0700335 ret = adc_vss_plat_update(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100336 if (ret)
337 return ret;
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200338
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100339 if (uc_pdata->vss_microvolts == -ENODATA)
340 return -ENODATA;
341
342 *uV = uc_pdata->vss_microvolts * value_sign;
343
344 return 0;
345}
346
Fabrice Gasnier63f004e2018-11-12 14:03:58 +0100347int adc_raw_to_uV(struct udevice *dev, unsigned int raw, int *uV)
348{
349 unsigned int data_mask;
350 int ret, val, vref;
351 u64 raw64 = raw;
352
353 ret = adc_vdd_value(dev, &vref);
354 if (ret)
355 return ret;
356
357 if (!adc_vss_value(dev, &val))
358 vref -= val;
359
360 ret = adc_data_mask(dev, &data_mask);
361 if (ret)
362 return ret;
363
364 raw64 *= vref;
365 do_div(raw64, data_mask);
366 *uV = raw64;
367
368 return 0;
369}
370
Simon Glass8a8d24b2020-12-03 16:55:23 -0700371static int adc_vdd_plat_set(struct udevice *dev)
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100372{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700373 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Simon Glass53d788d2017-05-18 20:09:37 -0600374 int ret;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100375 char *prop;
376
377 prop = "vdd-polarity-negative";
Simon Glass53d788d2017-05-18 20:09:37 -0600378 uc_pdata->vdd_polarity_negative = dev_read_bool(dev, prop);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100379
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200380 /* Optionally get regulators */
381 ret = device_get_supply_regulator(dev, "vdd-supply",
382 &uc_pdata->vdd_supply);
383 if (!ret)
Simon Glass8a8d24b2020-12-03 16:55:23 -0700384 return adc_vdd_plat_update(dev);
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200385
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100386 if (ret != -ENOENT)
387 return ret;
388
389 /* No vdd-supply phandle. */
390 prop = "vdd-microvolts";
Simon Glass53d788d2017-05-18 20:09:37 -0600391 uc_pdata->vdd_microvolts = dev_read_u32_default(dev, prop, -ENODATA);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100392
393 return 0;
394}
395
Simon Glass8a8d24b2020-12-03 16:55:23 -0700396static int adc_vss_plat_set(struct udevice *dev)
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100397{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700398 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Simon Glass53d788d2017-05-18 20:09:37 -0600399 int ret;
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100400 char *prop;
401
402 prop = "vss-polarity-negative";
Simon Glass53d788d2017-05-18 20:09:37 -0600403 uc_pdata->vss_polarity_negative = dev_read_bool(dev, prop);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100404
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200405 ret = device_get_supply_regulator(dev, "vss-supply",
406 &uc_pdata->vss_supply);
407 if (!ret)
Simon Glass8a8d24b2020-12-03 16:55:23 -0700408 return adc_vss_plat_update(dev);
Fabrice Gasniera4a87f72018-07-24 16:31:29 +0200409
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100410 if (ret != -ENOENT)
411 return ret;
412
413 /* No vss-supply phandle. */
414 prop = "vss-microvolts";
Simon Glass53d788d2017-05-18 20:09:37 -0600415 uc_pdata->vss_microvolts = dev_read_u32_default(dev, prop, -ENODATA);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100416
417 return 0;
418}
419
420static int adc_pre_probe(struct udevice *dev)
421{
422 int ret;
423
Simon Glasscaa4daa2020-12-03 16:55:18 -0700424 /* Set ADC VDD plat: polarity, uV, regulator (phandle). */
Simon Glass8a8d24b2020-12-03 16:55:23 -0700425 ret = adc_vdd_plat_set(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100426 if (ret)
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900427 pr_err("%s: Can't update Vdd. Error: %d", dev->name, ret);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100428
Simon Glasscaa4daa2020-12-03 16:55:18 -0700429 /* Set ADC VSS plat: polarity, uV, regulator (phandle). */
Simon Glass8a8d24b2020-12-03 16:55:23 -0700430 ret = adc_vss_plat_set(dev);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100431 if (ret)
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900432 pr_err("%s: Can't update Vss. Error: %d", dev->name, ret);
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100433
434 return 0;
435}
436
437UCLASS_DRIVER(adc) = {
438 .id = UCLASS_ADC,
439 .name = "adc",
440 .pre_probe = adc_pre_probe,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700441 .per_device_plat_auto = ADC_UCLASS_PLATDATA_SIZE,
Przemyslaw Marczak5decbf52015-10-27 13:08:00 +0100442};