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/mutex.h>
17 #include <linux/platform_device.h>
19 #define JZ_ADC_REG_ENABLE 0x00
20 #define JZ_ADC_REG_CFG 0x04
21 #define JZ_ADC_REG_CTRL 0x08
22 #define JZ_ADC_REG_STATUS 0x0c
23 #define JZ_ADC_REG_ADTCH 0x18
24 #define JZ_ADC_REG_ADBDAT 0x1c
25 #define JZ_ADC_REG_ADSDAT 0x20
26 #define JZ_ADC_REG_ADCLK 0x28
28 #define JZ_ADC_REG_ENABLE_PD BIT(7)
29 #define JZ_ADC_REG_CFG_AUX_MD (BIT(0) | BIT(1))
30 #define JZ_ADC_REG_CFG_BAT_MD BIT(4)
31 #define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0
32 #define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16
33 #define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB 8
34 #define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB 16
36 #define JZ_ADC_AUX_VREF 3300
37 #define JZ_ADC_AUX_VREF_BITS 12
38 #define JZ_ADC_BATTERY_LOW_VREF 2500
39 #define JZ_ADC_BATTERY_LOW_VREF_BITS 12
40 #define JZ4725B_ADC_BATTERY_HIGH_VREF 7500
41 #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10
42 #define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986)
43 #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12
44 #define JZ4770_ADC_BATTERY_VREF 6600
45 #define JZ4770_ADC_BATTERY_VREF_BITS 12
49 struct ingenic_adc_soc_data {
50 unsigned int battery_high_vref;
51 unsigned int battery_high_vref_bits;
52 const int *battery_raw_avail;
53 size_t battery_raw_avail_size;
54 const int *battery_scale_avail;
55 size_t battery_scale_avail_size;
56 unsigned int battery_vref_mode: 1;
57 unsigned int has_aux2: 1;
58 int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
65 struct mutex aux_lock;
66 const struct ingenic_adc_soc_data *soc_data;
70 static void ingenic_adc_set_config(struct ingenic_adc *adc,
77 mutex_lock(&adc->lock);
79 cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
81 writel(cfg, adc->base + JZ_ADC_REG_CFG);
83 mutex_unlock(&adc->lock);
84 clk_disable(adc->clk);
87 static void ingenic_adc_enable(struct ingenic_adc *adc,
93 mutex_lock(&adc->lock);
94 val = readb(adc->base + JZ_ADC_REG_ENABLE);
101 writeb(val, adc->base + JZ_ADC_REG_ENABLE);
102 mutex_unlock(&adc->lock);
105 static int ingenic_adc_capture(struct ingenic_adc *adc,
111 ingenic_adc_enable(adc, engine, true);
112 ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
113 !(val & BIT(engine)), 250, 1000);
115 ingenic_adc_enable(adc, engine, false);
120 static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
121 struct iio_chan_spec const *chan,
126 struct ingenic_adc *adc = iio_priv(iio_dev);
129 case IIO_CHAN_INFO_SCALE:
130 switch (chan->channel) {
131 case INGENIC_ADC_BATTERY:
132 if (!adc->soc_data->battery_vref_mode)
134 if (val > JZ_ADC_BATTERY_LOW_VREF) {
135 ingenic_adc_set_config(adc,
136 JZ_ADC_REG_CFG_BAT_MD,
138 adc->low_vref_mode = false;
140 ingenic_adc_set_config(adc,
141 JZ_ADC_REG_CFG_BAT_MD,
142 JZ_ADC_REG_CFG_BAT_MD);
143 adc->low_vref_mode = true;
154 static const int jz4725b_adc_battery_raw_avail[] = {
155 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
158 static const int jz4725b_adc_battery_scale_avail[] = {
159 JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
160 JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
163 static const int jz4740_adc_battery_raw_avail[] = {
164 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
167 static const int jz4740_adc_battery_scale_avail[] = {
168 JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
169 JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
172 static const int jz4770_adc_battery_raw_avail[] = {
173 0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
176 static const int jz4770_adc_battery_scale_avail[] = {
177 JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
180 static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
182 struct clk *parent_clk;
183 unsigned long parent_rate, rate;
184 unsigned int div_main, div_10us;
186 parent_clk = clk_get_parent(adc->clk);
188 dev_err(dev, "ADC clock has no parent\n");
191 parent_rate = clk_get_rate(parent_clk);
194 * The JZ4725B ADC works at 500 kHz to 8 MHz.
195 * We pick the highest rate possible.
196 * In practice we typically get 6 MHz, half of the 12 MHz EXT clock.
198 div_main = DIV_ROUND_UP(parent_rate, 8000000);
199 div_main = clamp(div_main, 1u, 64u);
200 rate = parent_rate / div_main;
201 if (rate < 500000 || rate > 8000000) {
202 dev_err(dev, "No valid divider for ADC main clock\n");
206 /* We also need a divider that produces a 10us clock. */
207 div_10us = DIV_ROUND_UP(rate, 100000);
209 writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) |
210 (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
211 adc->base + JZ_ADC_REG_ADCLK);
216 static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
218 struct clk *parent_clk;
219 unsigned long parent_rate, rate;
220 unsigned int div_main, div_ms, div_10us;
222 parent_clk = clk_get_parent(adc->clk);
224 dev_err(dev, "ADC clock has no parent\n");
227 parent_rate = clk_get_rate(parent_clk);
230 * The JZ4770 ADC works at 20 kHz to 200 kHz.
231 * We pick the highest rate possible.
233 div_main = DIV_ROUND_UP(parent_rate, 200000);
234 div_main = clamp(div_main, 1u, 256u);
235 rate = parent_rate / div_main;
236 if (rate < 20000 || rate > 200000) {
237 dev_err(dev, "No valid divider for ADC main clock\n");
241 /* We also need a divider that produces a 10us clock. */
242 div_10us = DIV_ROUND_UP(rate, 10000);
243 /* And another, which produces a 1ms clock. */
244 div_ms = DIV_ROUND_UP(rate, 1000);
246 writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) |
247 ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) |
248 (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
249 adc->base + JZ_ADC_REG_ADCLK);
254 static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
255 .battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF,
256 .battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
257 .battery_raw_avail = jz4725b_adc_battery_raw_avail,
258 .battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
259 .battery_scale_avail = jz4725b_adc_battery_scale_avail,
260 .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
261 .battery_vref_mode = true,
263 .init_clk_div = jz4725b_adc_init_clk_div,
266 static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
267 .battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF,
268 .battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
269 .battery_raw_avail = jz4740_adc_battery_raw_avail,
270 .battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
271 .battery_scale_avail = jz4740_adc_battery_scale_avail,
272 .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
273 .battery_vref_mode = true,
275 .init_clk_div = NULL, /* no ADCLK register on JZ4740 */
278 static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
279 .battery_high_vref = JZ4770_ADC_BATTERY_VREF,
280 .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
281 .battery_raw_avail = jz4770_adc_battery_raw_avail,
282 .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
283 .battery_scale_avail = jz4770_adc_battery_scale_avail,
284 .battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
285 .battery_vref_mode = false,
287 .init_clk_div = jz4770_adc_init_clk_div,
290 static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
291 struct iio_chan_spec const *chan,
297 struct ingenic_adc *adc = iio_priv(iio_dev);
300 case IIO_CHAN_INFO_RAW:
302 *length = adc->soc_data->battery_raw_avail_size;
303 *vals = adc->soc_data->battery_raw_avail;
304 return IIO_AVAIL_RANGE;
305 case IIO_CHAN_INFO_SCALE:
306 *type = IIO_VAL_FRACTIONAL_LOG2;
307 *length = adc->soc_data->battery_scale_avail_size;
308 *vals = adc->soc_data->battery_scale_avail;
309 return IIO_AVAIL_LIST;
315 static int ingenic_adc_read_chan_info_raw(struct ingenic_adc *adc,
316 struct iio_chan_spec const *chan,
319 int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
321 /* We cannot sample AUX/AUX2 in parallel. */
322 mutex_lock(&adc->aux_lock);
323 if (adc->soc_data->has_aux2 && engine == 0) {
324 bit = BIT(chan->channel == INGENIC_ADC_AUX2);
325 ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
328 clk_enable(adc->clk);
329 ret = ingenic_adc_capture(adc, engine);
333 switch (chan->channel) {
334 case INGENIC_ADC_AUX:
335 case INGENIC_ADC_AUX2:
336 *val = readw(adc->base + JZ_ADC_REG_ADSDAT);
338 case INGENIC_ADC_BATTERY:
339 *val = readw(adc->base + JZ_ADC_REG_ADBDAT);
345 clk_disable(adc->clk);
346 mutex_unlock(&adc->aux_lock);
351 static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
352 struct iio_chan_spec const *chan,
357 struct ingenic_adc *adc = iio_priv(iio_dev);
360 case IIO_CHAN_INFO_RAW:
361 return ingenic_adc_read_chan_info_raw(adc, chan, val);
362 case IIO_CHAN_INFO_SCALE:
363 switch (chan->channel) {
364 case INGENIC_ADC_AUX:
365 case INGENIC_ADC_AUX2:
366 *val = JZ_ADC_AUX_VREF;
367 *val2 = JZ_ADC_AUX_VREF_BITS;
369 case INGENIC_ADC_BATTERY:
370 if (adc->low_vref_mode) {
371 *val = JZ_ADC_BATTERY_LOW_VREF;
372 *val2 = JZ_ADC_BATTERY_LOW_VREF_BITS;
374 *val = adc->soc_data->battery_high_vref;
375 *val2 = adc->soc_data->battery_high_vref_bits;
380 return IIO_VAL_FRACTIONAL_LOG2;
386 static void ingenic_adc_clk_cleanup(void *data)
391 static const struct iio_info ingenic_adc_info = {
392 .write_raw = ingenic_adc_write_raw,
393 .read_raw = ingenic_adc_read_raw,
394 .read_avail = ingenic_adc_read_avail,
397 static const struct iio_chan_spec ingenic_channels[] = {
399 .extend_name = "aux",
401 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
402 BIT(IIO_CHAN_INFO_SCALE),
404 .channel = INGENIC_ADC_AUX,
407 .extend_name = "battery",
409 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
410 BIT(IIO_CHAN_INFO_SCALE),
411 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
412 BIT(IIO_CHAN_INFO_SCALE),
414 .channel = INGENIC_ADC_BATTERY,
416 { /* Must always be last in the array. */
417 .extend_name = "aux2",
419 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
420 BIT(IIO_CHAN_INFO_SCALE),
422 .channel = INGENIC_ADC_AUX2,
426 static int ingenic_adc_probe(struct platform_device *pdev)
428 struct device *dev = &pdev->dev;
429 struct iio_dev *iio_dev;
430 struct ingenic_adc *adc;
431 const struct ingenic_adc_soc_data *soc_data;
434 soc_data = device_get_match_data(dev);
438 iio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
442 adc = iio_priv(iio_dev);
443 mutex_init(&adc->lock);
444 mutex_init(&adc->aux_lock);
445 adc->soc_data = soc_data;
447 adc->base = devm_platform_ioremap_resource(pdev, 0);
448 if (IS_ERR(adc->base))
449 return PTR_ERR(adc->base);
451 adc->clk = devm_clk_get(dev, "adc");
452 if (IS_ERR(adc->clk)) {
453 dev_err(dev, "Unable to get clock\n");
454 return PTR_ERR(adc->clk);
457 ret = clk_prepare_enable(adc->clk);
459 dev_err(dev, "Failed to enable clock\n");
463 /* Set clock dividers. */
464 if (soc_data->init_clk_div) {
465 ret = soc_data->init_clk_div(dev, adc);
467 clk_disable_unprepare(adc->clk);
472 /* Put hardware in a known passive state. */
473 writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
474 writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
475 usleep_range(2000, 3000); /* Must wait at least 2ms. */
476 clk_disable(adc->clk);
478 ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
480 dev_err(dev, "Unable to add action\n");
484 iio_dev->dev.parent = dev;
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");
502 static const struct of_device_id ingenic_adc_of_match[] = {
503 { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
504 { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
505 { .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
508 MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
511 static struct platform_driver ingenic_adc_driver = {
513 .name = "ingenic-adc",
514 .of_match_table = of_match_ptr(ingenic_adc_of_match),
516 .probe = ingenic_adc_probe,
518 module_platform_driver(ingenic_adc_driver);
519 MODULE_LICENSE("GPL v2");