Lines Matching +full:adc +full:- +full:chan
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>
98 int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
112 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_set_adcmd() local
114 mutex_lock(&adc->lock); in ingenic_adc_set_adcmd()
117 readl(adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
124 adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
130 adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
138 adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
144 adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
151 adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
156 adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
160 writel(0, adc->base + JZ_ADC_REG_ADCMD); in ingenic_adc_set_adcmd()
162 mutex_unlock(&adc->lock); in ingenic_adc_set_adcmd()
165 static void ingenic_adc_set_config(struct ingenic_adc *adc, in ingenic_adc_set_config() argument
171 mutex_lock(&adc->lock); in ingenic_adc_set_config()
173 cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask; in ingenic_adc_set_config()
175 writel(cfg, adc->base + JZ_ADC_REG_CFG); in ingenic_adc_set_config()
177 mutex_unlock(&adc->lock); in ingenic_adc_set_config()
180 static void ingenic_adc_enable_unlocked(struct ingenic_adc *adc, in ingenic_adc_enable_unlocked() argument
186 val = readb(adc->base + JZ_ADC_REG_ENABLE); in ingenic_adc_enable_unlocked()
193 writeb(val, adc->base + JZ_ADC_REG_ENABLE); in ingenic_adc_enable_unlocked()
196 static void ingenic_adc_enable(struct ingenic_adc *adc, in ingenic_adc_enable() argument
200 mutex_lock(&adc->lock); in ingenic_adc_enable()
201 ingenic_adc_enable_unlocked(adc, engine, enabled); in ingenic_adc_enable()
202 mutex_unlock(&adc->lock); in ingenic_adc_enable()
205 static int ingenic_adc_capture(struct ingenic_adc *adc, in ingenic_adc_capture() argument
217 mutex_lock(&adc->lock); in ingenic_adc_capture()
218 cfg = readl(adc->base + JZ_ADC_REG_CFG); in ingenic_adc_capture()
219 writel(cfg & ~JZ_ADC_REG_CFG_CMD_SEL, adc->base + JZ_ADC_REG_CFG); in ingenic_adc_capture()
221 ingenic_adc_enable_unlocked(adc, engine, true); in ingenic_adc_capture()
222 ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val, in ingenic_adc_capture()
225 ingenic_adc_enable_unlocked(adc, engine, false); in ingenic_adc_capture()
227 writel(cfg, adc->base + JZ_ADC_REG_CFG); in ingenic_adc_capture()
228 mutex_unlock(&adc->lock); in ingenic_adc_capture()
234 struct iio_chan_spec const *chan, in ingenic_adc_write_raw() argument
239 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_write_raw() local
240 struct device *dev = iio_dev->dev.parent; in ingenic_adc_write_raw()
245 switch (chan->channel) { in ingenic_adc_write_raw()
247 if (!adc->soc_data->battery_vref_mode) in ingenic_adc_write_raw()
248 return -EINVAL; in ingenic_adc_write_raw()
250 ret = clk_enable(adc->clk); in ingenic_adc_write_raw()
258 ingenic_adc_set_config(adc, in ingenic_adc_write_raw()
261 adc->low_vref_mode = false; in ingenic_adc_write_raw()
263 ingenic_adc_set_config(adc, in ingenic_adc_write_raw()
266 adc->low_vref_mode = true; in ingenic_adc_write_raw()
269 clk_disable(adc->clk); in ingenic_adc_write_raw()
273 return -EINVAL; in ingenic_adc_write_raw()
276 return -EINVAL; in ingenic_adc_write_raw()
281 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
290 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
299 0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
306 static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc) in jz4725b_adc_init_clk_div() argument
312 parent_clk = clk_get_parent(adc->clk); in jz4725b_adc_init_clk_div()
314 dev_err(dev, "ADC clock has no parent\n"); in jz4725b_adc_init_clk_div()
315 return -ENODEV; in jz4725b_adc_init_clk_div()
320 * The JZ4725B ADC works at 500 kHz to 8 MHz. in jz4725b_adc_init_clk_div()
328 dev_err(dev, "No valid divider for ADC main clock\n"); in jz4725b_adc_init_clk_div()
329 return -EINVAL; in jz4725b_adc_init_clk_div()
335 writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) | in jz4725b_adc_init_clk_div()
336 (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB, in jz4725b_adc_init_clk_div()
337 adc->base + JZ_ADC_REG_ADCLK); in jz4725b_adc_init_clk_div()
342 static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc) in jz4770_adc_init_clk_div() argument
348 parent_clk = clk_get_parent(adc->clk); in jz4770_adc_init_clk_div()
350 dev_err(dev, "ADC clock has no parent\n"); in jz4770_adc_init_clk_div()
351 return -ENODEV; in jz4770_adc_init_clk_div()
356 * The JZ4770 ADC works at 20 kHz to 200 kHz. in jz4770_adc_init_clk_div()
363 dev_err(dev, "No valid divider for ADC main clock\n"); in jz4770_adc_init_clk_div()
364 return -EINVAL; in jz4770_adc_init_clk_div()
372 writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) | in jz4770_adc_init_clk_div()
373 ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) | in jz4770_adc_init_clk_div()
374 (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB, in jz4770_adc_init_clk_div()
375 adc->base + JZ_ADC_REG_ADCLK); in jz4770_adc_init_clk_div()
388 .scan_index = -1,
399 .scan_index = -1,
477 .scan_index = -1,
488 .scan_index = -1,
497 .scan_index = -1,
544 struct iio_chan_spec const *chan, in ingenic_adc_read_avail() argument
550 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_read_avail() local
555 *length = adc->soc_data->battery_raw_avail_size; in ingenic_adc_read_avail()
556 *vals = adc->soc_data->battery_raw_avail; in ingenic_adc_read_avail()
560 *length = adc->soc_data->battery_scale_avail_size; in ingenic_adc_read_avail()
561 *vals = adc->soc_data->battery_scale_avail; in ingenic_adc_read_avail()
564 return -EINVAL; in ingenic_adc_read_avail()
569 struct iio_chan_spec const *chan, in ingenic_adc_read_chan_info_raw() argument
572 int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); in ingenic_adc_read_chan_info_raw()
573 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_read_chan_info_raw() local
575 ret = clk_enable(adc->clk); in ingenic_adc_read_chan_info_raw()
577 dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", in ingenic_adc_read_chan_info_raw()
583 mutex_lock(&adc->aux_lock); in ingenic_adc_read_chan_info_raw()
584 if (adc->soc_data->has_aux2 && engine == 0) { in ingenic_adc_read_chan_info_raw()
585 bit = BIT(chan->channel == INGENIC_ADC_AUX2); in ingenic_adc_read_chan_info_raw()
586 ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit); in ingenic_adc_read_chan_info_raw()
589 ret = ingenic_adc_capture(adc, engine); in ingenic_adc_read_chan_info_raw()
593 switch (chan->channel) { in ingenic_adc_read_chan_info_raw()
596 *val = readw(adc->base + JZ_ADC_REG_ADSDAT); in ingenic_adc_read_chan_info_raw()
599 *val = readw(adc->base + JZ_ADC_REG_ADBDAT); in ingenic_adc_read_chan_info_raw()
605 mutex_unlock(&adc->aux_lock); in ingenic_adc_read_chan_info_raw()
606 clk_disable(adc->clk); in ingenic_adc_read_chan_info_raw()
612 struct iio_chan_spec const *chan, in ingenic_adc_read_raw() argument
617 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_read_raw() local
621 return ingenic_adc_read_chan_info_raw(iio_dev, chan, val); in ingenic_adc_read_raw()
623 switch (chan->channel) { in ingenic_adc_read_raw()
630 if (adc->low_vref_mode) { in ingenic_adc_read_raw()
634 *val = adc->soc_data->battery_high_vref; in ingenic_adc_read_raw()
635 *val2 = adc->soc_data->battery_high_vref_bits; in ingenic_adc_read_raw()
642 return -EINVAL; in ingenic_adc_read_raw()
651 if (!iiospec->args_count) in ingenic_adc_of_xlate()
652 return -EINVAL; in ingenic_adc_of_xlate()
654 for (i = 0; i < iio_dev->num_channels; ++i) in ingenic_adc_of_xlate()
655 if (iio_dev->channels[i].channel == iiospec->args[0]) in ingenic_adc_of_xlate()
658 return -EINVAL; in ingenic_adc_of_xlate()
675 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_buffer_enable() local
678 ret = clk_enable(adc->clk); in ingenic_adc_buffer_enable()
680 dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", in ingenic_adc_buffer_enable()
687 ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_TOUCH_OPS_MASK, in ingenic_adc_buffer_enable()
691 writew(80, adc->base + JZ_ADC_REG_ADWAIT); in ingenic_adc_buffer_enable()
692 writew(2, adc->base + JZ_ADC_REG_ADSAME); in ingenic_adc_buffer_enable()
693 writeb((u8)~JZ_ADC_IRQ_TOUCH, adc->base + JZ_ADC_REG_CTRL); in ingenic_adc_buffer_enable()
694 writel(0, adc->base + JZ_ADC_REG_ADTCH); in ingenic_adc_buffer_enable()
696 ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_CMD_SEL, in ingenic_adc_buffer_enable()
698 ingenic_adc_set_adcmd(iio_dev, iio_dev->active_scan_mask[0]); in ingenic_adc_buffer_enable()
700 ingenic_adc_enable(adc, 2, true); in ingenic_adc_buffer_enable()
707 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_buffer_disable() local
709 ingenic_adc_enable(adc, 2, false); in ingenic_adc_buffer_disable()
711 ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_CMD_SEL, 0); in ingenic_adc_buffer_disable()
713 writeb(0xff, adc->base + JZ_ADC_REG_CTRL); in ingenic_adc_buffer_disable()
714 writeb(0xff, adc->base + JZ_ADC_REG_STATUS); in ingenic_adc_buffer_disable()
715 ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_TOUCH_OPS_MASK, 0); in ingenic_adc_buffer_disable()
716 writew(0, adc->base + JZ_ADC_REG_ADSAME); in ingenic_adc_buffer_disable()
717 writew(0, adc->base + JZ_ADC_REG_ADWAIT); in ingenic_adc_buffer_disable()
718 clk_disable(adc->clk); in ingenic_adc_buffer_disable()
731 struct ingenic_adc *adc = iio_priv(iio_dev); in ingenic_adc_irq() local
732 unsigned long mask = iio_dev->active_scan_mask[0]; in ingenic_adc_irq()
738 tdat[i] = readl(adc->base + JZ_ADC_REG_ADTCH); in ingenic_adc_irq()
744 writeb(JZ_ADC_IRQ_TOUCH, adc->base + JZ_ADC_REG_STATUS); in ingenic_adc_irq()
751 struct device *dev = &pdev->dev; in ingenic_adc_probe()
753 struct ingenic_adc *adc; in ingenic_adc_probe() local
759 return -EINVAL; in ingenic_adc_probe()
761 iio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); in ingenic_adc_probe()
763 return -ENOMEM; in ingenic_adc_probe()
765 adc = iio_priv(iio_dev); in ingenic_adc_probe()
766 mutex_init(&adc->lock); in ingenic_adc_probe()
767 mutex_init(&adc->aux_lock); in ingenic_adc_probe()
768 adc->soc_data = soc_data; in ingenic_adc_probe()
781 adc->base = devm_platform_ioremap_resource(pdev, 0); in ingenic_adc_probe()
782 if (IS_ERR(adc->base)) in ingenic_adc_probe()
783 return PTR_ERR(adc->base); in ingenic_adc_probe()
785 adc->clk = devm_clk_get(dev, "adc"); in ingenic_adc_probe()
786 if (IS_ERR(adc->clk)) { in ingenic_adc_probe()
788 return PTR_ERR(adc->clk); in ingenic_adc_probe()
791 ret = clk_prepare_enable(adc->clk); in ingenic_adc_probe()
798 if (soc_data->init_clk_div) { in ingenic_adc_probe()
799 ret = soc_data->init_clk_div(dev, adc); in ingenic_adc_probe()
801 clk_disable_unprepare(adc->clk); in ingenic_adc_probe()
807 writeb(0x00, adc->base + JZ_ADC_REG_ENABLE); in ingenic_adc_probe()
808 writeb(0xff, adc->base + JZ_ADC_REG_CTRL); in ingenic_adc_probe()
810 clk_disable(adc->clk); in ingenic_adc_probe()
812 ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk); in ingenic_adc_probe()
818 iio_dev->name = "jz-adc"; in ingenic_adc_probe()
819 iio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; in ingenic_adc_probe()
820 iio_dev->setup_ops = &ingenic_buffer_setup_ops; in ingenic_adc_probe()
821 iio_dev->channels = soc_data->channels; in ingenic_adc_probe()
822 iio_dev->num_channels = soc_data->num_channels; in ingenic_adc_probe()
823 iio_dev->info = &ingenic_adc_info; in ingenic_adc_probe()
833 { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
834 { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
835 { .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
842 .name = "ingenic-adc",