1 // SPDX-License-Identifier: GPL-2.0
3 * ADC driver for the Ingenic JZ47xx SoCs
4 * Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu>
6 * based on drivers/mfd/jz4740-adc.c
9 #include <dt-bindings/iio/adc/ingenic,adc.h>
10 #include <linux/clk.h>
11 #include <linux/iio/iio.h>
13 #include <linux/iopoll.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/mutex.h>
18 #include <linux/platform_device.h>
20 #define JZ_ADC_REG_ENABLE 0x00
21 #define JZ_ADC_REG_CFG 0x04
22 #define JZ_ADC_REG_CTRL 0x08
23 #define JZ_ADC_REG_STATUS 0x0c
24 #define JZ_ADC_REG_ADTCH 0x18
25 #define JZ_ADC_REG_ADBDAT 0x1c
26 #define JZ_ADC_REG_ADSDAT 0x20
27 #define JZ_ADC_REG_ADCLK 0x28
29 #define JZ_ADC_REG_ENABLE_PD BIT(7)
30 #define JZ_ADC_REG_CFG_AUX_MD (BIT(0) | BIT(1))
31 #define JZ_ADC_REG_CFG_BAT_MD BIT(4)
32 #define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0
33 #define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16
34 #define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB 8
35 #define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB 16
37 #define JZ_ADC_AUX_VREF 3300
38 #define JZ_ADC_AUX_VREF_BITS 12
39 #define JZ_ADC_BATTERY_LOW_VREF 2500
40 #define JZ_ADC_BATTERY_LOW_VREF_BITS 12
41 #define JZ4725B_ADC_BATTERY_HIGH_VREF 7500
42 #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10
43 #define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986)
44 #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12
45 #define JZ4770_ADC_BATTERY_VREF 6600
46 #define JZ4770_ADC_BATTERY_VREF_BITS 12
50 struct ingenic_adc_soc_data {
51 unsigned int battery_high_vref;
52 unsigned int battery_high_vref_bits;
53 const int *battery_raw_avail;
54 size_t battery_raw_avail_size;
55 const int *battery_scale_avail;
56 size_t battery_scale_avail_size;
57 unsigned int battery_vref_mode: 1;
58 unsigned int has_aux2: 1;
59 int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
66 struct mutex aux_lock;
67 const struct ingenic_adc_soc_data *soc_data;
71 static void ingenic_adc_set_config(struct ingenic_adc *adc,
78 mutex_lock(&adc->lock);
80 cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
82 writel(cfg, adc->base + JZ_ADC_REG_CFG);
84 mutex_unlock(&adc->lock);
85 clk_disable(adc->clk);
88 static void ingenic_adc_enable(struct ingenic_adc *adc,
94 mutex_lock(&adc->lock);
95 val = readb(adc->base + JZ_ADC_REG_ENABLE);
102 writeb(val, adc->base + JZ_ADC_REG_ENABLE);
103 mutex_unlock(&adc->lock);
106 static int ingenic_adc_capture(struct ingenic_adc *adc,
112 ingenic_adc_enable(adc, engine, true);
113 ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
114 !(val & BIT(engine)), 250, 1000);
116 ingenic_adc_enable(adc, engine, false);
121 static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
122 struct iio_chan_spec const *chan,
127 struct ingenic_adc *adc = iio_priv(iio_dev);
130 case IIO_CHAN_INFO_SCALE:
131 switch (chan->channel) {
132 case INGENIC_ADC_BATTERY:
133 if (!adc->soc_data->battery_vref_mode)
135 if (val > JZ_ADC_BATTERY_LOW_VREF) {
136 ingenic_adc_set_config(adc,
137 JZ_ADC_REG_CFG_BAT_MD,
139 adc->low_vref_mode = false;
141 ingenic_adc_set_config(adc,
142 JZ_ADC_REG_CFG_BAT_MD,
143 JZ_ADC_REG_CFG_BAT_MD);
144 adc->low_vref_mode = true;
155 static const int jz4725b_adc_battery_raw_avail[] = {
156 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
159 static const int jz4725b_adc_battery_scale_avail[] = {
160 JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
161 JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
164 static const int jz4740_adc_battery_raw_avail[] = {
165 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
168 static const int jz4740_adc_battery_scale_avail[] = {
169 JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
170 JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
173 static const int jz4770_adc_battery_raw_avail[] = {
174 0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
177 static const int jz4770_adc_battery_scale_avail[] = {
178 JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
181 static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
183 struct clk *parent_clk;
184 unsigned long parent_rate, rate;
185 unsigned int div_main, div_10us;
187 parent_clk = clk_get_parent(adc->clk);
189 dev_err(dev, "ADC clock has no parent\n");
192 parent_rate = clk_get_rate(parent_clk);
195 * The JZ4725B ADC works at 500 kHz to 8 MHz.
196 * We pick the highest rate possible.
197 * In practice we typically get 6 MHz, half of the 12 MHz EXT clock.
199 div_main = DIV_ROUND_UP(parent_rate, 8000000);
200 div_main = clamp(div_main, 1u, 64u);
201 rate = parent_rate / div_main;
202 if (rate < 500000 || rate > 8000000) {
203 dev_err(dev, "No valid divider for ADC main clock\n");
207 /* We also need a divider that produces a 10us clock. */
208 div_10us = DIV_ROUND_UP(rate, 100000);
210 writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) |
211 (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
212 adc->base + JZ_ADC_REG_ADCLK);
217 static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
219 struct clk *parent_clk;
220 unsigned long parent_rate, rate;
221 unsigned int div_main, div_ms, div_10us;
223 parent_clk = clk_get_parent(adc->clk);
225 dev_err(dev, "ADC clock has no parent\n");
228 parent_rate = clk_get_rate(parent_clk);
231 * The JZ4770 ADC works at 20 kHz to 200 kHz.
232 * We pick the highest rate possible.
234 div_main = DIV_ROUND_UP(parent_rate, 200000);
235 div_main = clamp(div_main, 1u, 256u);
236 rate = parent_rate / div_main;
237 if (rate < 20000 || rate > 200000) {
238 dev_err(dev, "No valid divider for ADC main clock\n");
242 /* We also need a divider that produces a 10us clock. */
243 div_10us = DIV_ROUND_UP(rate, 10000);
244 /* And another, which produces a 1ms clock. */
245 div_ms = DIV_ROUND_UP(rate, 1000);
247 writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) |
248 ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) |
249 (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
250 adc->base + JZ_ADC_REG_ADCLK);
255 static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
256 .battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF,
257 .battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
258 .battery_raw_avail = jz4725b_adc_battery_raw_avail,
259 .battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
260 .battery_scale_avail = jz4725b_adc_battery_scale_avail,
261 .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
262 .battery_vref_mode = true,
264 .init_clk_div = jz4725b_adc_init_clk_div,
267 static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
268 .battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF,
269 .battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
270 .battery_raw_avail = jz4740_adc_battery_raw_avail,
271 .battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
272 .battery_scale_avail = jz4740_adc_battery_scale_avail,
273 .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
274 .battery_vref_mode = true,
276 .init_clk_div = NULL, /* no ADCLK register on JZ4740 */
279 static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
280 .battery_high_vref = JZ4770_ADC_BATTERY_VREF,
281 .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
282 .battery_raw_avail = jz4770_adc_battery_raw_avail,
283 .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
284 .battery_scale_avail = jz4770_adc_battery_scale_avail,
285 .battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
286 .battery_vref_mode = false,
288 .init_clk_div = jz4770_adc_init_clk_div,
291 static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
292 struct iio_chan_spec const *chan,
298 struct ingenic_adc *adc = iio_priv(iio_dev);
301 case IIO_CHAN_INFO_RAW:
303 *length = adc->soc_data->battery_raw_avail_size;
304 *vals = adc->soc_data->battery_raw_avail;
305 return IIO_AVAIL_RANGE;
306 case IIO_CHAN_INFO_SCALE:
307 *type = IIO_VAL_FRACTIONAL_LOG2;
308 *length = adc->soc_data->battery_scale_avail_size;
309 *vals = adc->soc_data->battery_scale_avail;
310 return IIO_AVAIL_LIST;
316 static int ingenic_adc_read_chan_info_raw(struct ingenic_adc *adc,
317 struct iio_chan_spec const *chan,
320 int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
322 /* We cannot sample AUX/AUX2 in parallel. */
323 mutex_lock(&adc->aux_lock);
324 if (adc->soc_data->has_aux2 && engine == 0) {
325 bit = BIT(chan->channel == INGENIC_ADC_AUX2);
326 ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
329 clk_enable(adc->clk);
330 ret = ingenic_adc_capture(adc, engine);
334 switch (chan->channel) {
335 case INGENIC_ADC_AUX:
336 case INGENIC_ADC_AUX2:
337 *val = readw(adc->base + JZ_ADC_REG_ADSDAT);
339 case INGENIC_ADC_BATTERY:
340 *val = readw(adc->base + JZ_ADC_REG_ADBDAT);
346 clk_disable(adc->clk);
347 mutex_unlock(&adc->aux_lock);
352 static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
353 struct iio_chan_spec const *chan,
358 struct ingenic_adc *adc = iio_priv(iio_dev);
361 case IIO_CHAN_INFO_RAW:
362 return ingenic_adc_read_chan_info_raw(adc, chan, val);
363 case IIO_CHAN_INFO_SCALE:
364 switch (chan->channel) {
365 case INGENIC_ADC_AUX:
366 case INGENIC_ADC_AUX2:
367 *val = JZ_ADC_AUX_VREF;
368 *val2 = JZ_ADC_AUX_VREF_BITS;
370 case INGENIC_ADC_BATTERY:
371 if (adc->low_vref_mode) {
372 *val = JZ_ADC_BATTERY_LOW_VREF;
373 *val2 = JZ_ADC_BATTERY_LOW_VREF_BITS;
375 *val = adc->soc_data->battery_high_vref;
376 *val2 = adc->soc_data->battery_high_vref_bits;
381 return IIO_VAL_FRACTIONAL_LOG2;
387 static void ingenic_adc_clk_cleanup(void *data)
392 static const struct iio_info ingenic_adc_info = {
393 .write_raw = ingenic_adc_write_raw,
394 .read_raw = ingenic_adc_read_raw,
395 .read_avail = ingenic_adc_read_avail,
398 static const struct iio_chan_spec ingenic_channels[] = {
400 .extend_name = "aux",
402 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
403 BIT(IIO_CHAN_INFO_SCALE),
405 .channel = INGENIC_ADC_AUX,
408 .extend_name = "battery",
410 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
411 BIT(IIO_CHAN_INFO_SCALE),
412 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
413 BIT(IIO_CHAN_INFO_SCALE),
415 .channel = INGENIC_ADC_BATTERY,
417 { /* Must always be last in the array. */
418 .extend_name = "aux2",
420 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
421 BIT(IIO_CHAN_INFO_SCALE),
423 .channel = INGENIC_ADC_AUX2,
427 static int ingenic_adc_probe(struct platform_device *pdev)
429 struct device *dev = &pdev->dev;
430 struct iio_dev *iio_dev;
431 struct ingenic_adc *adc;
432 const struct ingenic_adc_soc_data *soc_data;
435 soc_data = device_get_match_data(dev);
439 iio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
443 adc = iio_priv(iio_dev);
444 mutex_init(&adc->lock);
445 mutex_init(&adc->aux_lock);
446 adc->soc_data = soc_data;
448 adc->base = devm_platform_ioremap_resource(pdev, 0);
449 if (IS_ERR(adc->base))
450 return PTR_ERR(adc->base);
452 adc->clk = devm_clk_get(dev, "adc");
453 if (IS_ERR(adc->clk)) {
454 dev_err(dev, "Unable to get clock\n");
455 return PTR_ERR(adc->clk);
458 ret = clk_prepare_enable(adc->clk);
460 dev_err(dev, "Failed to enable clock\n");
464 /* Set clock dividers. */
465 if (soc_data->init_clk_div) {
466 ret = soc_data->init_clk_div(dev, adc);
468 clk_disable_unprepare(adc->clk);
473 /* Put hardware in a known passive state. */
474 writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
475 writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
476 usleep_range(2000, 3000); /* Must wait at least 2ms. */
477 clk_disable(adc->clk);
479 ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
481 dev_err(dev, "Unable to add action\n");
485 iio_dev->name = "jz-adc";
486 iio_dev->modes = INDIO_DIRECT_MODE;
487 iio_dev->channels = ingenic_channels;
488 iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
489 /* Remove AUX2 from the list of supported channels. */
490 if (!adc->soc_data->has_aux2)
491 iio_dev->num_channels -= 1;
492 iio_dev->info = &ingenic_adc_info;
494 ret = devm_iio_device_register(dev, iio_dev);
496 dev_err(dev, "Unable to register IIO device\n");
501 static const struct of_device_id ingenic_adc_of_match[] = {
502 { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
503 { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
504 { .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
507 MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
509 static struct platform_driver ingenic_adc_driver = {
511 .name = "ingenic-adc",
512 .of_match_table = ingenic_adc_of_match,
514 .probe = ingenic_adc_probe,
516 module_platform_driver(ingenic_adc_driver);
517 MODULE_LICENSE("GPL v2");