Lines Matching +full:spmi +full:- +full:vadc
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
10 #include <linux/iio/adc/qcom-vadc-common.h>
22 #include <dt-bindings/iio/qcom,spmi-vadc.h>
24 /* VADC register and bit definitions */
75 * struct vadc_channel_prop - VADC channel property.
98 * struct vadc_priv - VADC private structure.
102 * @nchannels: number of VADC channels.
103 * @chan_props: array of VADC channel properties.
107 * @complete: VADC result notification after interrupt is received.
136 static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data) in vadc_read() argument
138 return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1); in vadc_read()
141 static int vadc_write(struct vadc_priv *vadc, u16 offset, u8 data) in vadc_write() argument
143 return regmap_write(vadc->regmap, vadc->base + offset, data); in vadc_write()
146 static int vadc_reset(struct vadc_priv *vadc) in vadc_reset() argument
151 ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA); in vadc_reset()
155 ret = vadc_read(vadc, VADC_PERH_RESET_CTL3, &data); in vadc_reset()
159 ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA); in vadc_reset()
165 return vadc_write(vadc, VADC_PERH_RESET_CTL3, data); in vadc_reset()
168 static int vadc_set_state(struct vadc_priv *vadc, bool state) in vadc_set_state() argument
170 return vadc_write(vadc, VADC_EN_CTL1, state ? VADC_EN_CTL1_SET : 0); in vadc_set_state()
173 static void vadc_show_status(struct vadc_priv *vadc) in vadc_show_status() argument
178 ret = vadc_read(vadc, VADC_MODE_CTL, &mode); in vadc_show_status()
182 ret = vadc_read(vadc, VADC_ADC_DIG_PARAM, &dig); in vadc_show_status()
186 ret = vadc_read(vadc, VADC_ADC_CH_SEL_CTL, &chan); in vadc_show_status()
190 ret = vadc_read(vadc, VADC_CONV_REQ, &req); in vadc_show_status()
194 ret = vadc_read(vadc, VADC_STATUS1, &sta1); in vadc_show_status()
198 ret = vadc_read(vadc, VADC_EN_CTL1, &en); in vadc_show_status()
202 dev_err(vadc->dev, in vadc_show_status()
207 static int vadc_configure(struct vadc_priv *vadc, in vadc_configure() argument
216 ret = vadc_write(vadc, VADC_MODE_CTL, mode_ctrl); in vadc_configure()
221 ret = vadc_write(vadc, VADC_ADC_CH_SEL_CTL, prop->channel); in vadc_configure()
226 decimation = prop->decimation << VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT; in vadc_configure()
227 ret = vadc_write(vadc, VADC_ADC_DIG_PARAM, decimation); in vadc_configure()
232 ret = vadc_write(vadc, VADC_HW_SETTLE_DELAY, prop->hw_settle_time); in vadc_configure()
236 ret = vadc_write(vadc, VADC_FAST_AVG_CTL, prop->avg_samples); in vadc_configure()
240 if (prop->avg_samples) in vadc_configure()
241 ret = vadc_write(vadc, VADC_FAST_AVG_EN, VADC_FAST_AVG_EN_SET); in vadc_configure()
243 ret = vadc_write(vadc, VADC_FAST_AVG_EN, 0); in vadc_configure()
248 static int vadc_poll_wait_eoc(struct vadc_priv *vadc, unsigned int interval_us) in vadc_poll_wait_eoc() argument
257 ret = vadc_read(vadc, VADC_STATUS1, &sta1); in vadc_poll_wait_eoc()
268 vadc_show_status(vadc); in vadc_poll_wait_eoc()
270 return -ETIMEDOUT; in vadc_poll_wait_eoc()
273 static int vadc_read_result(struct vadc_priv *vadc, u16 *data) in vadc_read_result() argument
277 ret = regmap_bulk_read(vadc->regmap, vadc->base + VADC_DATA, data, 2); in vadc_read_result()
286 static struct vadc_channel_prop *vadc_get_channel(struct vadc_priv *vadc, in vadc_get_channel() argument
291 for (i = 0; i < vadc->nchannels; i++) in vadc_get_channel()
292 if (vadc->chan_props[i].channel == num) in vadc_get_channel()
293 return &vadc->chan_props[i]; in vadc_get_channel()
295 dev_dbg(vadc->dev, "no such channel %02x\n", num); in vadc_get_channel()
300 static int vadc_do_conversion(struct vadc_priv *vadc, in vadc_do_conversion() argument
306 mutex_lock(&vadc->lock); in vadc_do_conversion()
308 ret = vadc_configure(vadc, prop); in vadc_do_conversion()
312 if (!vadc->poll_eoc) in vadc_do_conversion()
313 reinit_completion(&vadc->complete); in vadc_do_conversion()
315 ret = vadc_set_state(vadc, true); in vadc_do_conversion()
319 ret = vadc_write(vadc, VADC_CONV_REQ, VADC_CONV_REQ_SET); in vadc_do_conversion()
323 timeout = BIT(prop->avg_samples) * VADC_CONV_TIME_MIN_US * 2; in vadc_do_conversion()
325 if (vadc->poll_eoc) { in vadc_do_conversion()
326 ret = vadc_poll_wait_eoc(vadc, timeout); in vadc_do_conversion()
328 ret = wait_for_completion_timeout(&vadc->complete, timeout); in vadc_do_conversion()
330 ret = -ETIMEDOUT; in vadc_do_conversion()
335 ret = vadc_poll_wait_eoc(vadc, VADC_CONV_TIME_MIN_US); in vadc_do_conversion()
340 ret = vadc_read_result(vadc, data); in vadc_do_conversion()
343 vadc_set_state(vadc, false); in vadc_do_conversion()
345 dev_err(vadc->dev, "conversion failed\n"); in vadc_do_conversion()
347 mutex_unlock(&vadc->lock); in vadc_do_conversion()
351 static int vadc_measure_ref_points(struct vadc_priv *vadc) in vadc_measure_ref_points() argument
357 vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE; in vadc_measure_ref_points()
358 vadc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV; in vadc_measure_ref_points()
360 prop = vadc_get_channel(vadc, VADC_REF_1250MV); in vadc_measure_ref_points()
361 ret = vadc_do_conversion(vadc, prop, &read_1); in vadc_measure_ref_points()
366 prop = vadc_get_channel(vadc, VADC_SPARE1); in vadc_measure_ref_points()
368 prop = vadc_get_channel(vadc, VADC_REF_625MV); in vadc_measure_ref_points()
370 ret = vadc_do_conversion(vadc, prop, &read_2); in vadc_measure_ref_points()
375 ret = -EINVAL; in vadc_measure_ref_points()
379 vadc->graph[VADC_CALIB_ABSOLUTE].dy = read_1 - read_2; in vadc_measure_ref_points()
380 vadc->graph[VADC_CALIB_ABSOLUTE].gnd = read_2; in vadc_measure_ref_points()
383 prop = vadc_get_channel(vadc, VADC_VDD_VADC); in vadc_measure_ref_points()
384 ret = vadc_do_conversion(vadc, prop, &read_1); in vadc_measure_ref_points()
388 prop = vadc_get_channel(vadc, VADC_GND_REF); in vadc_measure_ref_points()
389 ret = vadc_do_conversion(vadc, prop, &read_2); in vadc_measure_ref_points()
394 ret = -EINVAL; in vadc_measure_ref_points()
398 vadc->graph[VADC_CALIB_RATIOMETRIC].dy = read_1 - read_2; in vadc_measure_ref_points()
399 vadc->graph[VADC_CALIB_RATIOMETRIC].gnd = read_2; in vadc_measure_ref_points()
402 dev_err(vadc->dev, "measure reference points failed\n"); in vadc_measure_ref_points()
417 return -EINVAL; in vadc_prescaling_from_dt()
425 return -EINVAL; in vadc_hw_settle_time_from_dt()
438 return -EINVAL; in vadc_avg_samples_from_dt()
447 struct vadc_priv *vadc = iio_priv(indio_dev); in vadc_read_raw() local
454 prop = &vadc->chan_props[chan->address]; in vadc_read_raw()
455 ret = vadc_do_conversion(vadc, prop, &adc_code); in vadc_read_raw()
459 ret = qcom_vadc_scale(prop->scale_fn_type, in vadc_read_raw()
460 &vadc->graph[prop->calibration], in vadc_read_raw()
461 &vadc_prescale_ratios[prop->prescale], in vadc_read_raw()
462 (prop->calibration == VADC_CALIB_ABSOLUTE), in vadc_read_raw()
469 prop = &vadc->chan_props[chan->address]; in vadc_read_raw()
470 ret = vadc_do_conversion(vadc, prop, &adc_code); in vadc_read_raw()
477 ret = -EINVAL; in vadc_read_raw()
487 struct vadc_priv *vadc = iio_priv(indio_dev); in vadc_of_xlate() local
490 for (i = 0; i < vadc->nchannels; i++) in vadc_of_xlate()
491 if (vadc->iio_chans[i].channel == iiospec->args[0]) in vadc_of_xlate()
494 return -EINVAL; in vadc_of_xlate()
654 const char *name = node->name; in vadc_get_dt_channel_data()
666 return -EINVAL; in vadc_get_dt_channel_data()
670 prop->channel = chan; in vadc_get_dt_channel_data()
680 prop->decimation = ret; in vadc_get_dt_channel_data()
682 prop->decimation = VADC_DEF_DECIMATION; in vadc_get_dt_channel_data()
685 ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2); in vadc_get_dt_channel_data()
689 dev_err(dev, "%02x invalid pre-scaling <%d %d>\n", in vadc_get_dt_channel_data()
693 prop->prescale = ret; in vadc_get_dt_channel_data()
695 prop->prescale = vadc_chans[prop->channel].prescale_index; in vadc_get_dt_channel_data()
698 ret = of_property_read_u32(node, "qcom,hw-settle-time", &value); in vadc_get_dt_channel_data()
702 dev_err(dev, "%02x invalid hw-settle-time %d us\n", in vadc_get_dt_channel_data()
706 prop->hw_settle_time = ret; in vadc_get_dt_channel_data()
708 prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME; in vadc_get_dt_channel_data()
711 ret = of_property_read_u32(node, "qcom,avg-samples", &value); in vadc_get_dt_channel_data()
715 dev_err(dev, "%02x invalid avg-samples %d\n", in vadc_get_dt_channel_data()
719 prop->avg_samples = ret; in vadc_get_dt_channel_data()
721 prop->avg_samples = VADC_DEF_AVG_SAMPLES; in vadc_get_dt_channel_data()
725 prop->calibration = VADC_CALIB_RATIOMETRIC; in vadc_get_dt_channel_data()
727 prop->calibration = VADC_CALIB_ABSOLUTE; in vadc_get_dt_channel_data()
734 static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node) in vadc_get_dt_data() argument
743 vadc->nchannels = of_get_available_child_count(node); in vadc_get_dt_data()
744 if (!vadc->nchannels) in vadc_get_dt_data()
745 return -EINVAL; in vadc_get_dt_data()
747 vadc->iio_chans = devm_kcalloc(vadc->dev, vadc->nchannels, in vadc_get_dt_data()
748 sizeof(*vadc->iio_chans), GFP_KERNEL); in vadc_get_dt_data()
749 if (!vadc->iio_chans) in vadc_get_dt_data()
750 return -ENOMEM; in vadc_get_dt_data()
752 vadc->chan_props = devm_kcalloc(vadc->dev, vadc->nchannels, in vadc_get_dt_data()
753 sizeof(*vadc->chan_props), GFP_KERNEL); in vadc_get_dt_data()
754 if (!vadc->chan_props) in vadc_get_dt_data()
755 return -ENOMEM; in vadc_get_dt_data()
757 iio_chan = vadc->iio_chans; in vadc_get_dt_data()
760 ret = vadc_get_dt_channel_data(vadc->dev, &prop, child); in vadc_get_dt_data()
767 vadc->chan_props[index] = prop; in vadc_get_dt_data()
771 iio_chan->channel = prop.channel; in vadc_get_dt_data()
772 iio_chan->datasheet_name = vadc_chan->datasheet_name; in vadc_get_dt_data()
773 iio_chan->info_mask_separate = vadc_chan->info_mask; in vadc_get_dt_data()
774 iio_chan->type = vadc_chan->type; in vadc_get_dt_data()
775 iio_chan->indexed = 1; in vadc_get_dt_data()
776 iio_chan->address = index++; in vadc_get_dt_data()
782 if (!vadc_get_channel(vadc, VADC_REF_1250MV)) { in vadc_get_dt_data()
783 dev_err(vadc->dev, "Please define 1.25V channel\n"); in vadc_get_dt_data()
784 return -ENODEV; in vadc_get_dt_data()
787 if (!vadc_get_channel(vadc, VADC_REF_625MV)) { in vadc_get_dt_data()
788 dev_err(vadc->dev, "Please define 0.625V channel\n"); in vadc_get_dt_data()
789 return -ENODEV; in vadc_get_dt_data()
792 if (!vadc_get_channel(vadc, VADC_VDD_VADC)) { in vadc_get_dt_data()
793 dev_err(vadc->dev, "Please define VDD channel\n"); in vadc_get_dt_data()
794 return -ENODEV; in vadc_get_dt_data()
797 if (!vadc_get_channel(vadc, VADC_GND_REF)) { in vadc_get_dt_data()
798 dev_err(vadc->dev, "Please define GND channel\n"); in vadc_get_dt_data()
799 return -ENODEV; in vadc_get_dt_data()
807 struct vadc_priv *vadc = dev_id; in vadc_isr() local
809 complete(&vadc->complete); in vadc_isr()
814 static int vadc_check_revision(struct vadc_priv *vadc) in vadc_check_revision() argument
819 ret = vadc_read(vadc, VADC_PERPH_TYPE, &val); in vadc_check_revision()
824 dev_err(vadc->dev, "%d is not ADC\n", val); in vadc_check_revision()
825 return -ENODEV; in vadc_check_revision()
828 ret = vadc_read(vadc, VADC_PERPH_SUBTYPE, &val); in vadc_check_revision()
833 dev_err(vadc->dev, "%d is not VADC\n", val); in vadc_check_revision()
834 return -ENODEV; in vadc_check_revision()
837 ret = vadc_read(vadc, VADC_REVISION2, &val); in vadc_check_revision()
842 dev_err(vadc->dev, "revision %d not supported\n", val); in vadc_check_revision()
843 return -ENODEV; in vadc_check_revision()
851 struct device_node *node = pdev->dev.of_node; in vadc_probe()
852 struct device *dev = &pdev->dev; in vadc_probe()
854 struct vadc_priv *vadc; in vadc_probe() local
859 regmap = dev_get_regmap(dev->parent, NULL); in vadc_probe()
861 return -ENODEV; in vadc_probe()
867 indio_dev = devm_iio_device_alloc(dev, sizeof(*vadc)); in vadc_probe()
869 return -ENOMEM; in vadc_probe()
871 vadc = iio_priv(indio_dev); in vadc_probe()
872 vadc->regmap = regmap; in vadc_probe()
873 vadc->dev = dev; in vadc_probe()
874 vadc->base = reg; in vadc_probe()
875 vadc->are_ref_measured = false; in vadc_probe()
876 init_completion(&vadc->complete); in vadc_probe()
877 mutex_init(&vadc->lock); in vadc_probe()
879 ret = vadc_check_revision(vadc); in vadc_probe()
883 ret = vadc_get_dt_data(vadc, node); in vadc_probe()
889 if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL) in vadc_probe()
891 vadc->poll_eoc = true; in vadc_probe()
894 "spmi-vadc", vadc); in vadc_probe()
899 ret = vadc_reset(vadc); in vadc_probe()
905 ret = vadc_measure_ref_points(vadc); in vadc_probe()
909 indio_dev->name = pdev->name; in vadc_probe()
910 indio_dev->modes = INDIO_DIRECT_MODE; in vadc_probe()
911 indio_dev->info = &vadc_info; in vadc_probe()
912 indio_dev->channels = vadc->iio_chans; in vadc_probe()
913 indio_dev->num_channels = vadc->nchannels; in vadc_probe()
919 { .compatible = "qcom,spmi-vadc" },
926 .name = "qcom-spmi-vadc",
933 MODULE_ALIAS("platform:qcom-spmi-vadc");
934 MODULE_DESCRIPTION("Qualcomm SPMI PMIC voltage ADC driver");
936 MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");
937 MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");