diff options
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r-- | drivers/iio/adc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/iio/adc/ab8500-gpadc.c | 30 | ||||
-rw-r--r-- | drivers/iio/adc/ad7476.c | 6 | ||||
-rw-r--r-- | drivers/iio/adc/qcom-pm8xxx-xoadc.c | 3 | ||||
-rw-r--r-- | drivers/iio/adc/qcom-spmi-adc5.c | 95 | ||||
-rw-r--r-- | drivers/iio/adc/qcom-spmi-vadc.c | 3 | ||||
-rw-r--r-- | drivers/iio/adc/qcom-vadc-common.c | 229 | ||||
-rw-r--r-- | drivers/iio/adc/qcom-vadc-common.h | 177 | ||||
-rw-r--r-- | drivers/iio/adc/sc27xx_adc.c | 2 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc-core.c | 29 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc.c | 14 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-dfsdm-core.c | 3 | ||||
-rw-r--r-- | drivers/iio/adc/xilinx-xadc-core.c | 364 | ||||
-rw-r--r-- | drivers/iio/adc/xilinx-xadc-events.c | 9 | ||||
-rw-r--r-- | drivers/iio/adc/xilinx-xadc.h | 6 |
15 files changed, 434 insertions, 547 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 15587a1bc80d..bf7d22fa4be2 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1228,8 +1228,15 @@ config XILINX_XADC select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to have support for the Xilinx XADC. The driver does support - both the ZYNQ interface to the XADC as well as the AXI-XADC interface. + Say yes here to have support for the Xilinx 7 Series XADC or + UltraScale/UltraScale+ System Management Wizard. + + For the 7 Series the driver does support both the ZYNQ interface + to the XADC as well as the AXI-XADC interface. + + The driver also support the Xilinx System Management Wizard IP core + that can be used to access the System Monitor ADC on the Xilinx + UltraScale and UltraScale+ FPGAs. The driver can also be build as a module. If so, the module will be called xilinx-xadc. diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index 1bb987a4acba..6f9a3e2d5533 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -1108,10 +1108,14 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) return gpadc->irq_sw; } - gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END"); - if (gpadc->irq_hw < 0) { - dev_err(dev, "failed to get platform hw_conv_end irq\n"); - return gpadc->irq_hw; + if (is_ab8500(gpadc->ab8500)) { + gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END"); + if (gpadc->irq_hw < 0) { + dev_err(dev, "failed to get platform hw_conv_end irq\n"); + return gpadc->irq_hw; + } + } else { + gpadc->irq_hw = 0; } /* Initialize completion used to notify completion of conversion */ @@ -1128,14 +1132,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) return ret; } - ret = devm_request_threaded_irq(dev, gpadc->irq_hw, NULL, - ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, - "ab8500-gpadc-hw", gpadc); - if (ret < 0) { - dev_err(dev, - "Failed to request hw conversion irq: %d\n", - gpadc->irq_hw); - return ret; + if (gpadc->irq_hw) { + ret = devm_request_threaded_irq(dev, gpadc->irq_hw, NULL, + ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, + "ab8500-gpadc-hw", gpadc); + if (ret < 0) { + dev_err(dev, + "Failed to request hw conversion irq: %d\n", + gpadc->irq_hw); + return ret; + } } /* The VTVout LDO used to power the AB8500 GPADC */ diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 66c55ae67791..17402714b387 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -67,6 +67,7 @@ enum ad7476_supported_device_ids { ID_ADS7866, ID_ADS7867, ID_ADS7868, + ID_LTC2314_14, }; static void ad7091_convst(struct ad7476_state *st) @@ -250,6 +251,10 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { .channel[0] = ADS786X_CHAN(8), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, + [ID_LTC2314_14] = { + .channel[0] = AD7940_CHAN(14), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + }, }; static const struct iio_info ad7476_info = { @@ -365,6 +370,7 @@ static const struct spi_device_id ad7476_id[] = { {"ads7866", ID_ADS7866}, {"ads7867", ID_ADS7867}, {"ads7868", ID_ADS7868}, + {"ltc2314-14", ID_LTC2314_14}, {} }; MODULE_DEVICE_TABLE(spi, ad7476_id); diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 7e108da7d255..0610bf254771 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -10,6 +10,7 @@ * Author: Linus Walleij <linus.walleij@linaro.org> */ +#include <linux/iio/adc/qcom-vadc-common.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/module.h> @@ -21,8 +22,6 @@ #include <linux/interrupt.h> #include <linux/regulator/consumer.h> -#include "qcom-vadc-common.h" - /* * Definitions for the "user processor" registers lifted from the v3.4 * Qualcomm tree. Their kernel has two out-of-tree drivers for the ADC: diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index c10aa28be70a..87438d1e5c0b 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -7,6 +7,7 @@ #include <linux/completion.h> #include <linux/delay.h> #include <linux/err.h> +#include <linux/iio/adc/qcom-vadc-common.h> #include <linux/iio/iio.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -14,12 +15,12 @@ #include <linux/math64.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/slab.h> #include <dt-bindings/iio/qcom,spmi-vadc.h> -#include "qcom-vadc-common.h" #define ADC5_USR_REVISION1 0x0 #define ADC5_USR_STATUS1 0x8 @@ -154,18 +155,6 @@ struct adc5_chip { const struct adc5_data *data; }; -static const struct vadc_prescale_ratio adc5_prescale_ratios[] = { - {.num = 1, .den = 1}, - {.num = 1, .den = 3}, - {.num = 1, .den = 4}, - {.num = 1, .den = 6}, - {.num = 1, .den = 20}, - {.num = 1, .den = 8}, - {.num = 10, .den = 81}, - {.num = 1, .den = 10}, - {.num = 1, .den = 16} -}; - static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len) { return regmap_bulk_read(adc->regmap, adc->base + offset, data, len); @@ -181,55 +170,6 @@ static int adc5_masked_write(struct adc5_chip *adc, u16 offset, u8 mask, u8 val) return regmap_update_bits(adc->regmap, adc->base + offset, mask, val); } -static int adc5_prescaling_from_dt(u32 num, u32 den) -{ - unsigned int pre; - - for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++) - if (adc5_prescale_ratios[pre].num == num && - adc5_prescale_ratios[pre].den == den) - break; - - if (pre == ARRAY_SIZE(adc5_prescale_ratios)) - return -EINVAL; - - return pre; -} - -static int adc5_hw_settle_time_from_dt(u32 value, - const unsigned int *hw_settle) -{ - unsigned int i; - - for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) { - if (value == hw_settle[i]) - return i; - } - - return -EINVAL; -} - -static int adc5_avg_samples_from_dt(u32 value) -{ - if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX) - return -EINVAL; - - return __ffs(value); -} - -static int adc5_decimation_from_dt(u32 value, - const unsigned int *decimation) -{ - unsigned int i; - - for (i = 0; i < ADC5_DECIMATION_SAMPLES_MAX; i++) { - if (value == decimation[i]) - return i; - } - - return -EINVAL; -} - static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data) { int ret; @@ -511,7 +451,7 @@ static int adc_read_raw_common(struct iio_dev *indio_dev, return ret; ret = qcom_adc5_hw_scale(prop->scale_fn_type, - &adc5_prescale_ratios[prop->prescale], + prop->prescale, adc->data, adc_code_volt, val); if (ret) @@ -717,7 +657,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, ret = of_property_read_u32(node, "qcom,decimation", &value); if (!ret) { - ret = adc5_decimation_from_dt(value, data->decimation); + ret = qcom_adc5_decimation_from_dt(value, data->decimation); if (ret < 0) { dev_err(dev, "%02x invalid decimation %d\n", chan, value); @@ -730,7 +670,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2); if (!ret) { - ret = adc5_prescaling_from_dt(varr[0], varr[1]); + ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]); if (ret < 0) { dev_err(dev, "%02x invalid pre-scaling <%d %d>\n", chan, varr[0], varr[1]); @@ -759,11 +699,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, if ((dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR && dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR) || adc->data->info == &adc7_info) - ret = adc5_hw_settle_time_from_dt(value, - data->hw_settle_2); + ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_2); else - ret = adc5_hw_settle_time_from_dt(value, - data->hw_settle_1); + ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_1); if (ret < 0) { dev_err(dev, "%02x invalid hw-settle-time %d us\n", @@ -777,7 +715,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, ret = of_property_read_u32(node, "qcom,avg-samples", &value); if (!ret) { - ret = adc5_avg_samples_from_dt(value); + ret = qcom_adc5_avg_samples_from_dt(value); if (ret < 0) { dev_err(dev, "%02x invalid avg-samples %d\n", chan, value); @@ -870,8 +808,6 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node) struct adc5_channel_prop prop, *chan_props; struct device_node *child; unsigned int index = 0; - const struct of_device_id *id; - const struct adc5_data *data; int ret; adc->nchannels = of_get_available_child_count(node); @@ -890,24 +826,21 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node) chan_props = adc->chan_props; iio_chan = adc->iio_chans; - id = of_match_node(adc5_match_table, node); - if (id) - data = id->data; - else - data = &adc5_data_pmic; - adc->data = data; + adc->data = of_device_get_match_data(adc->dev); + if (!adc->data) + adc->data = &adc5_data_pmic; for_each_available_child_of_node(node, child) { - ret = adc5_get_dt_channel_data(adc, &prop, child, data); + ret = adc5_get_dt_channel_data(adc, &prop, child, adc->data); if (ret) { of_node_put(child); return ret; } prop.scale_fn_type = - data->adc_chans[prop.channel].scale_fn_type; + adc->data->adc_chans[prop.channel].scale_fn_type; *chan_props = prop; - adc_chan = &data->adc_chans[prop.channel]; + adc_chan = &adc->data->adc_chans[prop.channel]; iio_chan->channel = prop.channel; iio_chan->datasheet_name = prop.datasheet_name; diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index b0388f8a69f4..05ff948372b3 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -7,6 +7,7 @@ #include <linux/completion.h> #include <linux/delay.h> #include <linux/err.h> +#include <linux/iio/adc/qcom-vadc-common.h> #include <linux/iio/iio.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -20,8 +21,6 @@ #include <dt-bindings/iio/qcom,spmi-vadc.h> -#include "qcom-vadc-common.h" - /* VADC register and bit definitions */ #define VADC_REVISION2 0x1 #define VADC_REVISION2_SUPPORTED_VADC 1 diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index 5113aaa6ba67..8682cf1e213f 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -2,50 +2,61 @@ #include <linux/bug.h> #include <linux/kernel.h> #include <linux/bitops.h> +#include <linux/fixp-arith.h> +#include <linux/iio/adc/qcom-vadc-common.h> #include <linux/math64.h> #include <linux/log2.h> #include <linux/err.h> #include <linux/module.h> #include <linux/units.h> -#include "qcom-vadc-common.h" +/** + * struct vadc_map_pt - Map the graph representation for ADC channel + * @x: Represent the ADC digitized code. + * @y: Represent the physical data which can be temperature, voltage, + * resistance. + */ +struct vadc_map_pt { + s32 x; + s32 y; +}; /* Voltage to temperature */ static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = { - {1758, -40}, - {1742, -35}, - {1719, -30}, - {1691, -25}, - {1654, -20}, - {1608, -15}, - {1551, -10}, - {1483, -5}, - {1404, 0}, - {1315, 5}, - {1218, 10}, - {1114, 15}, - {1007, 20}, - {900, 25}, - {795, 30}, - {696, 35}, - {605, 40}, - {522, 45}, - {448, 50}, - {383, 55}, - {327, 60}, - {278, 65}, - {237, 70}, - {202, 75}, - {172, 80}, - {146, 85}, - {125, 90}, - {107, 95}, - {92, 100}, - {79, 105}, - {68, 110}, - {59, 115}, - {51, 120}, - {44, 125} + {1758, -40000 }, + {1742, -35000 }, + {1719, -30000 }, + {1691, -25000 }, + {1654, -20000 }, + {1608, -15000 }, + {1551, -10000 }, + {1483, -5000 }, + {1404, 0 }, + {1315, 5000 }, + {1218, 10000 }, + {1114, 15000 }, + {1007, 20000 }, + {900, 25000 }, + {795, 30000 }, + {696, 35000 }, + {605, 40000 }, + {522, 45000 }, + {448, 50000 }, + {383, 55000 }, + {327, 60000 }, + {278, 65000 }, + {237, 70000 }, + {202, 75000 }, + {172, 80000 }, + {146, 85000 }, + {125, 90000 }, + {107, 95000 }, + {92, 100000 }, + {79, 105000 }, + {68, 110000 }, + {59, 115000 }, + {51, 120000 }, + {44, 125000 } }; /* @@ -90,18 +101,18 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = { }; static const struct vadc_map_pt adcmap7_die_temp[] = { - { 433700, 1967}, - { 473100, 1964}, - { 512400, 1957}, - { 551500, 1949}, - { 590500, 1940}, - { 629300, 1930}, - { 667900, 1921}, - { 706400, 1910}, - { 744600, 1896}, - { 782500, 1878}, - { 820100, 1859}, - { 857300, 0}, + { 857300, 160000 }, + { 820100, 140000 }, + { 782500, 120000 }, + { 744600, 100000 }, + { 706400, 80000 }, + { 667900, 60000 }, + { 629300, 40000 }, + { 590500, 20000 }, + { 551500, 0 }, + { 512400, -20000 }, + { 473100, -40000 }, + { 433700, -60000 }, }; /* @@ -278,6 +289,18 @@ static const struct vadc_map_pt adcmap7_100k[] = { { 2420, 130048 } }; +static const struct vadc_prescale_ratio adc5_prescale_ratios[] = { + {.num = 1, .den = 1}, + {.num = 1, .den = 3}, + {.num = 1, .den = 4}, + {.num = 1, .den = 6}, + {.num = 1, .den = 20}, + {.num = 1, .den = 8}, + {.num = 10, .den = 81}, + {.num = 1, .den = 10}, + {.num = 1, .den = 16} +}; + static int qcom_vadc_scale_hw_calib_volt( const struct vadc_prescale_ratio *prescale, const struct adc5_data *data, @@ -323,43 +346,23 @@ static struct qcom_adc5_scale_type scale_adc5_fn[] = { static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts, u32 tablesize, s32 input, int *output) { - bool descending = 1; u32 i = 0; if (!pts) return -EINVAL; - /* Check if table is descending or ascending */ - if (tablesize > 1) { - if (pts[0].x < pts[1].x) - descending = 0; - } - - while (i < tablesize) { - if ((descending) && (pts[i].x < input)) { - /* table entry is less than measured*/ - /* value and table is descending, stop */ - break; - } else if ((!descending) && - (pts[i].x > input)) { - /* table entry is greater than measured*/ - /*value and table is ascending, stop */ - break; - } + while (i < tablesize && pts[i].x > input) i++; - } if (i == 0) { *output = pts[0].y; } else if (i == tablesize) { *output = pts[tablesize - 1].y; } else { - /* result is between search_index and search_index-1 */ /* interpolate linearly */ - *output = (((s32)((pts[i].y - pts[i - 1].y) * - (input - pts[i - 1].x)) / - (pts[i].x - pts[i - 1].x)) + - pts[i - 1].y); + *output = fixp_linear_interpolate(pts[i - 1].x, pts[i - 1].y, + pts[i].x, pts[i].y, + input); } return 0; @@ -415,8 +418,6 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph, if (ret) return ret; - *result_mdec *= 1000; - return 0; } @@ -563,33 +564,13 @@ static int qcom_vadc7_scale_hw_calib_die_temp( u16 adc_code, int *result_mdec) { - int voltage, vtemp0, temp, i; + int voltage; voltage = qcom_vadc_scale_code_voltage_factor(adc_code, prescale, data, 1); - if (adcmap7_die_temp[0].x > voltage) { - *result_mdec = DIE_TEMP_ADC7_SCALE_1; - return 0; - } - - if (adcmap7_die_temp[ARRAY_SIZE(adcmap7_die_temp) - 1].x <= voltage) { - *result_mdec = DIE_TEMP_ADC7_MAX; - return 0; - } - - for (i = 0; i < ARRAY_SIZE(adcmap7_die_temp); i++) - if (adcmap7_die_temp[i].x > voltage) - break; - - vtemp0 = adcmap7_die_temp[i - 1].x; - voltage = voltage - vtemp0; - temp = div64_s64(voltage * DIE_TEMP_ADC7_SCALE_FACTOR, - adcmap7_die_temp[i - 1].y); - temp += DIE_TEMP_ADC7_SCALE_1 + (DIE_TEMP_ADC7_SCALE_2 * (i - 1)); - *result_mdec = temp; - - return 0; + return qcom_vadc_map_voltage_temp(adcmap7_die_temp, ARRAY_SIZE(adcmap7_die_temp), + voltage, result_mdec); } static int qcom_vadc_scale_hw_smb_temp( @@ -647,10 +628,12 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, EXPORT_SYMBOL(qcom_vadc_scale); int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype, - const struct vadc_prescale_ratio *prescale, + unsigned int prescale_ratio, const struct adc5_data *data, u16 adc_code, int *result) { + const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio]; + if (!(scaletype >= SCALE_HW_CALIB_DEFAULT && scaletype < SCALE_HW_CALIB_INVALID)) { pr_err("Invalid scale type %d\n", scaletype); @@ -662,6 +645,58 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype, } EXPORT_SYMBOL(qcom_adc5_hw_scale); +int qcom_adc5_prescaling_from_dt(u32 num, u32 den) +{ + unsigned int pre; + + for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++) + if (adc5_prescale_ratios[pre].num == num && + adc5_prescale_ratios[pre].den == den) + break; + + if (pre == ARRAY_SIZE(adc5_prescale_ratios)) + return -EINVAL; + + return pre; +} +EXPORT_SYMBOL(qcom_adc5_prescaling_from_dt); + +int qcom_adc5_hw_settle_time_from_dt(u32 value, + const unsigned int *hw_settle) +{ + unsigned int i; + + for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) { + if (value == hw_settle[i]) + return i; + } + + return -EINVAL; +} +EXPORT_SYMBOL(qcom_adc5_hw_settle_time_from_dt); + +int qcom_adc5_avg_samples_from_dt(u32 value) +{ + if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX) + return -EINVAL; + + return __ffs(value); +} +EXPORT_SYMBOL(qcom_adc5_avg_samples_from_dt); + +int qcom_adc5_decimation_from_dt(u32 value, const unsigned int *decimation) +{ + unsigned int i; + + for (i = 0; i < ADC5_DECIMATION_SAMPLES_MAX; i++) { + if (value == decimation[i]) + return i; + } + + return -EINVAL; +} +EXPORT_SYMBOL(qcom_adc5_decimation_from_dt); + int qcom_vadc_decimation_from_dt(u32 value) { if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN || diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h deleted file mode 100644 index 17b2fc4d8bf2..000000000000 --- a/drivers/iio/adc/qcom-vadc-common.h +++ /dev/null @@ -1,177 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Code shared between the different Qualcomm PMIC voltage ADCs - */ - -#ifndef QCOM_VADC_COMMON_H -#define QCOM_VADC_COMMON_H - -#define VADC_CONV_TIME_MIN_US 2000 -#define VADC_CONV_TIME_MAX_US 2100 - -/* Min ADC code represents 0V */ -#define VADC_MIN_ADC_CODE 0x6000 -/* Max ADC code represents full-scale range of 1.8V */ -#define VADC_MAX_ADC_CODE 0xa800 - -#define VADC_ABSOLUTE_RANGE_UV 625000 -#define VADC_RATIOMETRIC_RANGE 1800 - -#define VADC_DEF_PRESCALING 0 /* 1:1 */ -#define VADC_DEF_DECIMATION 0 /* 512 */ -#define VADC_DEF_HW_SETTLE_TIME 0 /* 0 us */ -#define VADC_DEF_AVG_SAMPLES 0 /* 1 sample */ -#define VADC_DEF_CALIB_TYPE VADC_CALIB_ABSOLUTE - -#define VADC_DECIMATION_MIN 512 -#define VADC_DECIMATION_MAX 4096 -#define ADC5_DEF_VBAT_PRESCALING 1 /* 1:3 */ -#define ADC5_DECIMATION_SHORT 250 -#define ADC5_DECIMATION_MEDIUM 420 -#define ADC5_DECIMATION_LONG 840 -/* Default decimation - 1024 for rev2, 840 for pmic5 */ -#define ADC5_DECIMATION_DEFAULT 2 -#define ADC5_DECIMATION_SAMPLES_MAX 3 - -#define VADC_HW_SETTLE_DELAY_MAX 10000 -#define VADC_HW_SETTLE_SAMPLES_MAX 16 -#define VADC_AVG_SAMPLES_MAX 512 -#define ADC5_AVG_SAMPLES_MAX 16 - -#define PMIC5_CHG_TEMP_SCALE_FACTOR 377500 -#define PMIC5_SMB_TEMP_CONSTANT 419400 -#define PMIC5_SMB_TEMP_SCALE_FACTOR 356 - -#define PMI_CHG_SCALE_1 -138890 -#define PMI_CHG_SCALE_2 391750000000LL - -#define VADC5_MAX_CODE 0x7fff -#define ADC5_FULL_SCALE_CODE 0x70e4 -#define ADC5_USR_DATA_CHECK 0x8000 - -#define R_PU_100K 100000 -#define RATIO_MAX_ADC7 BIT(14) - -#define DIE_TEMP_ADC7_SCALE_1 -60000 -#define DIE_TEMP_ADC7_SCALE_2 20000 -#define DIE_TEMP_ADC7_SCALE_FACTOR 1000 -#define DIE_TEMP_ADC7_MAX 160000 - -/** - * struct vadc_map_pt - Map the graph representation for ADC channel - * @x: Represent the ADC digitized code. - * @y: Represent the physical data which can be temperature, voltage, - * resistance. - */ -struct vadc_map_pt { - s32 x; - s32 y; -}; - -/* - * VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels. - * VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for - * calibration. - */ -enum vadc_calibration { - VADC_CALIB_ABSOLUTE = 0, - VADC_CALIB_RATIOMETRIC -}; - -/** - * struct vadc_linear_graph - Represent ADC characteristics. - * @dy: numerator slope to calculate the gain. - * @dx: denominator slope to calculate the gain. - * @gnd: A/D word of the ground reference used for the channel. - * - * Each ADC device has different offset and gain parameters which are - * computed to calibrate the device. - */ -struct vadc_linear_graph { - s32 dy; - s32 dx; - s32 gnd; -}; - -/** - * struct vadc_prescale_ratio - Represent scaling ratio for ADC input. - * @num: the inverse numerator of the gain applied to the input channel. - * @den: the inverse denominator of the gain applied to the input channel. - */ -struct vadc_prescale_ratio { - u32 num; - u32 den; -}; - -/** - * enum vadc_scale_fn_type - Scaling function to convert ADC code to - * physical scaled units for the channel. - * SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV). - * SCALE_THERM_100K_PULLUP: Returns temperature in millidegC. - * Uses a mapping table with 100K pullup. - * SCALE_PMIC_THERM: Returns result in milli degree's Centigrade. - * SCALE_XOTHERM: Returns XO thermistor voltage in millidegC. - * SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp - * SCALE_HW_CALIB_DEFAULT: Default scaling to convert raw adc code to - * voltage (uV) with hardware applied offset/slope values to adc code. - * SCALE_HW_CALIB_THERM_100K_PULLUP: Returns temperature in millidegC using - * lookup table. The hardware applies offset/slope to adc code. - * SCALE_HW_CALIB_XOTHERM: Returns XO thermistor voltage in millidegC using - * 100k pullup. The hardware applies offset/slope to adc code. - * SCALE_HW_CALIB_THERM_100K_PU_PM7: Returns temperature in millidegC using - * lookup table for PMIC7. The hardware applies offset/slope to adc code. - * SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade. - * The hardware applies offset/slope to adc code. - * SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade. - * The hardware applies offset/slope to adc code. This is for PMIC7. - * SCALE_HW_CALIB_PM5_CHG_TEMP: Returns result in millidegrees for PMIC5 - * charger temperature. - * SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5 - * SMB1390 temperature. - */ -enum vadc_scale_fn_type { - SCALE_DEFAULT = 0, - SCALE_THERM_100K_PULLUP, - SCALE_PMIC_THERM, - SCALE_XOTHERM, - SCALE_PMI_CHG_TEMP, - SCALE_HW_CALIB_DEFAULT, - SCALE_HW_CALIB_THERM_100K_PULLUP, - SCALE_HW_CALIB_XOTHERM, - SCALE_HW_CALIB_THERM_100K_PU_PM7, - SCALE_HW_CALIB_PMIC_THERM, - SCALE_HW_CALIB_PMIC_THERM_PM7, - SCALE_HW_CALIB_PM5_CHG_TEMP, - SCALE_HW_CALIB_PM5_SMB_TEMP, - SCALE_HW_CALIB_INVALID, -}; - -struct adc5_data { - const u32 full_scale_code_volt; - const u32 full_scale_code_cur; - const struct adc5_channels *adc_chans; - const struct iio_info *info; - unsigned int *decimation; - unsigned int *hw_settle_1; - unsigned int *hw_settle_2; -}; - -int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, - const struct vadc_linear_graph *calib_graph, - const struct vadc_prescale_ratio *prescale, - bool absolute, - u16 adc_code, int *result_mdec); - -struct qcom_adc5_scale_type { - int (*scale_fn)(const struct vadc_prescale_ratio *prescale, - const struct adc5_data *data, u16 adc_code, int *result); -}; - -int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype, - const struct vadc_prescale_ratio *prescale, - const struct adc5_data *data, - u16 adc_code, int *result_mdec); - -int qcom_vadc_decimation_from_dt(u32 value); - -#endif /* QCOM_VADC_COMMON_H */ diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c index aa32a1f385e2..301cf66de695 100644 --- a/drivers/iio/adc/sc27xx_adc.c +++ b/drivers/iio/adc/sc27xx_adc.c @@ -307,7 +307,7 @@ static int sc27xx_adc_convert_volt(struct sc27xx_adc_data *data, int channel, sc27xx_adc_volt_ratio(data, channel, scale, &numerator, &denominator); - return (volt * denominator + numerator / 2) / numerator; + return DIV_ROUND_CLOSEST(volt * denominator, numerator); } static int sc27xx_adc_read_processed(struct sc27xx_adc_data *data, diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 9d1ad6e38e85..c088cb990193 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -535,20 +535,16 @@ static int stm32_adc_core_hw_start(struct device *dev) goto err_switches_dis; } - if (priv->bclk) { - ret = clk_prepare_enable(priv->bclk); - if (ret < 0) { - dev_err(dev, "bus clk enable failed\n"); - goto err_regulator_disable; - } + ret = clk_prepare_enable(priv->bclk); + if (ret < 0) { + dev_err(dev, "bus clk enable failed\n"); + goto err_regulator_disable; } - if (priv->aclk) { - ret = clk_prepare_enable(priv->aclk); - if (ret < 0) { - dev_err(dev, "adc clk enable failed\n"); - goto err_bclk_disable; - } + ret = clk_prepare_enable(priv->aclk); + if (ret < 0) { + dev_err(dev, "adc clk enable failed\n"); + goto err_bclk_disable; } writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr); @@ -556,8 +552,7 @@ static int stm32_adc_core_hw_start(struct device *dev) return 0; err_bclk_disable: - if (priv->bclk) - clk_disable_unprepare(priv->bclk); + clk_disable_unprepare(priv->bclk); err_regulator_disable: regulator_disable(priv->vref); err_switches_dis: @@ -575,10 +570,8 @@ static void stm32_adc_core_hw_stop(struct device *dev) /* Backup CCR that may be lost (depends on power state to achieve) */ priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr); - if (priv->aclk) - clk_disable_unprepare(priv->aclk); - if (priv->bclk) - clk_disable_unprepare(priv->bclk); + clk_disable_unprepare(priv->aclk); + clk_disable_unprepare(priv->bclk); regulator_disable(priv->vref); stm32_adc_core_switches_supply_dis(priv); regulator_disable(priv->vdda); diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index c067c994dae2..f7c53cea509a 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -546,8 +546,7 @@ static int stm32_adc_hw_stop(struct device *dev) if (adc->cfg->unprepare) adc->cfg->unprepare(indio_dev); - if (adc->clk) - clk_disable_unprepare(adc->clk); + clk_disable_unprepare(adc->clk); return 0; } @@ -558,11 +557,9 @@ static int stm32_adc_hw_start(struct device *dev) struct stm32_adc *adc = iio_priv(indio_dev); int ret; - if (adc->clk) { - ret = clk_prepare_enable(adc->clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(adc->clk); + if (ret) + return ret; stm32_adc_set_res(adc); @@ -575,8 +572,7 @@ static int stm32_adc_hw_start(struct device *dev) return 0; err_clk_dis: - if (adc->clk) - clk_disable_unprepare(adc->clk); + clk_disable_unprepare(adc->clk); return ret; } diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 42a7377704a4..bb925a11c8ae 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -117,8 +117,7 @@ static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm) { struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); - if (priv->aclk) - clk_disable_unprepare(priv->aclk); + clk_disable_unprepare(priv->aclk); clk_disable_unprepare(priv->clk); } diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index f93c34fe5873..34800dccbf69 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/overflow.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/sysfs.h> @@ -92,7 +93,12 @@ static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500; #define XADC_AXI_REG_GIER 0x5c #define XADC_AXI_REG_IPISR 0x60 #define XADC_AXI_REG_IPIER 0x68 -#define XADC_AXI_ADC_REG_OFFSET 0x200 + +/* 7 Series */ +#define XADC_7S_AXI_ADC_REG_OFFSET 0x200 + +/* UltraScale */ +#define XADC_US_AXI_ADC_REG_OFFSET 0x400 #define XADC_AXI_RESET_MAGIC 0xa #define XADC_AXI_GIER_ENABLE BIT(31) @@ -447,6 +453,12 @@ static const struct xadc_ops xadc_zynq_ops = { .get_dclk_rate = xadc_zynq_get_dclk_rate, .interrupt_handler = xadc_zynq_interrupt_handler, .update_alarm = xadc_zynq_update_alarm, + .type = XADC_TYPE_S7, +}; + +static const unsigned int xadc_axi_reg_offsets[] = { + [XADC_TYPE_S7] = XADC_7S_AXI_ADC_REG_OFFSET, + [XADC_TYPE_US] = XADC_US_AXI_ADC_REG_OFFSET, }; static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg, @@ -454,7 +466,8 @@ static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg, { uint32_t val32; - xadc_read_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, &val32); + xadc_read_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4, + &val32); *val = val32 & 0xffff; return 0; @@ -463,7 +476,8 @@ static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg, static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg, uint16_t val) { - xadc_write_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, val); + xadc_write_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4, + val); return 0; } @@ -541,7 +555,7 @@ static unsigned long xadc_axi_get_dclk(struct xadc *xadc) return clk_get_rate(xadc->clk); } -static const struct xadc_ops xadc_axi_ops = { +static const struct xadc_ops xadc_7s_axi_ops = { .read = xadc_axi_read_adc_reg, .write = xadc_axi_write_adc_reg, .setup = xadc_axi_setup, @@ -549,6 +563,18 @@ static const struct xadc_ops xadc_axi_ops = { .update_alarm = xadc_axi_update_alarm, .interrupt_handler = xadc_axi_interrupt_handler, .flags = XADC_FLAGS_BUFFERED, + .type = XADC_TYPE_S7, +}; + +static const struct xadc_ops xadc_us_axi_ops = { + .read = xadc_axi_read_adc_reg, + .write = xadc_axi_write_adc_reg, + .setup = xadc_axi_setup, + .get_dclk_rate = xadc_axi_get_dclk, + .update_alarm = xadc_axi_update_alarm, + .interrupt_handler = xadc_axi_interrupt_handler, + .flags = XADC_FLAGS_BUFFERED, + .type = XADC_TYPE_US, }; static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, @@ -585,15 +611,22 @@ static int xadc_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *mask) { struct xadc *xadc = iio_priv(indio_dev); - unsigned int n; + size_t new_size, n; + void *data; n = bitmap_weight(mask, indio_dev->masklength); - kfree(xadc->data); - xadc->data = kcalloc(n, sizeof(*xadc->data), GFP_KERNEL); - if (!xadc->data) + if (check_mul_overflow(n, sizeof(*xadc->data), &new_size)) + return -ENOMEM; + + data = devm_krealloc(indio_dev->dev.parent, xadc->data, + new_size, GFP_KERNEL); + if (!data) return -ENOMEM; + memset(data, 0, new_size); + xadc->data = data; + return 0; } @@ -705,11 +738,12 @@ static const struct iio_trigger_ops xadc_trigger_ops = { static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, const char *name) { + struct device *dev = indio_dev->dev.parent; struct iio_trigger *trig; int ret; - trig = iio_trigger_alloc("%s%d-%s", indio_dev->name, - indio_dev->id, name); + trig = devm_iio_trigger_alloc(dev, "%s%d-%s", indio_dev->name, + indio_dev->id, name); if (trig == NULL) return ERR_PTR(-ENOMEM); @@ -717,21 +751,26 @@ static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, trig->ops = &xadc_trigger_ops; iio_trigger_set_drvdata(trig, iio_priv(indio_dev)); - ret = iio_trigger_register(trig); + ret = devm_iio_trigger_register(dev, trig); if (ret) - goto error_free_trig; + return ERR_PTR(ret); return trig; - -error_free_trig: - iio_trigger_free(trig); - return ERR_PTR(ret); } static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode) { uint16_t val; + /* + * As per datasheet the power-down bits are don't care in the + * UltraScale, but as per reality setting the power-down bit for the + * non-existing ADC-B powers down the main ADC, so just return and don't + * do anything. + */ + if (xadc->ops->type == XADC_TYPE_US) + return 0; + /* Powerdown the ADC-B when it is not needed. */ switch (seq_mode) { case XADC_CONF1_SEQ_SIMULTANEOUS: @@ -751,6 +790,10 @@ static int xadc_get_seq_mode(struct xadc *xadc, unsigned long scan_mode) { unsigned int aux_scan_mode = scan_mode >> 16; + /* UltraScale has only one ADC and supports only continuous mode */ + if (xadc->ops->type == XADC_TYPE_US) + return XADC_CONF1_SEQ_CONTINUOUS; + if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_DUAL) return XADC_CONF1_SEQ_SIMULTANEOUS; @@ -863,6 +906,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) { struct xadc *xadc = iio_priv(indio_dev); + unsigned int bits = chan->scan_type.realbits; uint16_t val16; int ret; @@ -874,17 +918,17 @@ static int xadc_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - val16 >>= 4; + val16 >>= chan->scan_type.shift; if (chan->scan_type.sign == 'u') *val = val16; else - *val = sign_extend32(val16, 11); + *val = sign_extend32(val16, bits - 1); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: - /* V = (val * 3.0) / 4096 */ + /* V = (val * 3.0) / 2**bits */ switch (chan->address) { case XADC_REG_VCCINT: case XADC_REG_VCCAUX: @@ -900,19 +944,19 @@ static int xadc_read_raw(struct iio_dev *indio_dev, *val = 1000; break; } - *val2 = 12; + *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; case IIO_TEMP: - /* Temp in C = (val * 503.975) / 4096 - 273.15 */ + /* Temp in C = (val * 503.975) / 2**bits - 273.15 */ *val = 503975; - *val2 = 12; + *val2 = bits; return IIO_VAL_FRACTIONAL_LOG2; default: return -EINVAL; } case IIO_CHAN_INFO_OFFSET: /* Only the temperature channel has an offset */ - *val = -((273150 << 12) / 503975); + *val = -((273150 << bits) / 503975); return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: ret = xadc_read_samplerate(xadc); @@ -1001,7 +1045,7 @@ static const struct iio_event_spec xadc_voltage_events[] = { }, }; -#define XADC_CHAN_TEMP(_chan, _scan_index, _addr) { \ +#define XADC_CHAN_TEMP(_chan, _scan_index, _addr, _bits) { \ .type = IIO_TEMP, \ .indexed = 1, \ .channel = (_chan), \ @@ -1015,14 +1059,14 @@ static const struct iio_event_spec xadc_voltage_events[] = { .scan_index = (_scan_index), \ .scan_type = { \ .sign = 'u', \ - .realbits = 12, \ + .realbits = (_bits), \ .storagebits = 16, \ - .shift = 4, \ + .shift = 16 - (_bits), \ .endianness = IIO_CPU, \ }, \ } -#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) { \ +#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _bits, _ext, _alarm) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = (_chan), \ @@ -1035,41 +1079,82 @@ static const struct iio_event_spec xadc_voltage_events[] = { .scan_index = (_scan_index), \ .scan_type = { \ .sign = ((_addr) == XADC_REG_VREFN) ? 's' : 'u', \ - .realbits = 12, \ + .realbits = (_bits), \ .storagebits = 16, \ - .shift = 4, \ + .shift = 16 - (_bits), \ .endianness = IIO_CPU, \ }, \ .extend_name = _ext, \ } -static const struct iio_chan_spec xadc_channels[] = { - XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP), - XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true), - XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true), - XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true), - XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true), - XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true), - XADC_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true), - XADC_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false), - XADC_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false), - XADC_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false), - XADC_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false), - XADC_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false), - XADC_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false), - XADC_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false), - XADC_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false), - XADC_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false), - XADC_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false), - XADC_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false), - XADC_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false), - XADC_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false), - XADC_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false), - XADC_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false), - XADC_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false), - XADC_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false), - XADC_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false), - XADC_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false), +/* 7 Series */ +#define XADC_7S_CHAN_TEMP(_chan, _scan_index, _addr) \ + XADC_CHAN_TEMP(_chan, _scan_index, _addr, 12) +#define XADC_7S_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) \ + XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, 12, _ext, _alarm) + +static const struct iio_chan_spec xadc_7s_channels[] = { + XADC_7S_CHAN_TEMP(0, 8, XADC_REG_TEMP), + XADC_7S_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true), + XADC_7S_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true), + XADC_7S_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true), + XADC_7S_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true), + XADC_7S_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true), + XADC_7S_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true), + XADC_7S_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false), + XADC_7S_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false), + XADC_7S_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false), + XADC_7S_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false), + XADC_7S_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false), + XADC_7S_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false), + XADC_7S_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false), + XADC_7S_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false), + XADC_7S_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false), + XADC_7S_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false), + XADC_7S_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false), + XADC_7S_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false), + XADC_7S_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false), + XADC_7S_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false), + XADC_7S_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false), + XADC_7S_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false), + XADC_7S_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false), + XADC_7S_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false), + XADC_7S_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false), +}; + +/* UltraScale */ +#define XADC_US_CHAN_TEMP(_chan, _scan_index, _addr) \ + XADC_CHAN_TEMP(_chan, _scan_index, _addr, 10) +#define XADC_US_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) \ + XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, 10, _ext, _alarm) + +static const struct iio_chan_spec xadc_us_channels[] = { + XADC_US_CHAN_TEMP(0, 8, XADC_REG_TEMP), + XADC_US_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true), + XADC_US_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true), + XADC_US_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true), + XADC_US_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpsintlp", true), + XADC_US_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpsintfp", true), + XADC_US_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccpsaux", true), + XADC_US_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false), + XADC_US_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false), + XADC_US_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false), + XADC_US_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false), + XADC_US_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false), + XADC_US_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false), + XADC_US_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false), + XADC_US_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false), + XADC_US_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false), + XADC_US_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false), + XADC_US_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false), + XADC_US_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false), + XADC_US_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false), + XADC_US_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false), + XADC_US_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false), + XADC_US_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false), + XADC_US_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false), + XADC_US_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false), + XADC_US_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false), }; static const struct iio_info xadc_info = { @@ -1083,8 +1168,16 @@ static const struct iio_info xadc_info = { }; static const struct of_device_id xadc_of_match_table[] = { - { .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops }, - { .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops }, + { + .compatible = "xlnx,zynq-xadc-1.00.a", + .data = &xadc_zynq_ops + }, { + .compatible = "xlnx,axi-xadc-1.00.a", + .data = &xadc_7s_axi_ops + }, { + .compatible = "xlnx,system-management-wiz-1.3", + .data = &xadc_us_axi_ops + }, { }, }; MODULE_DEVICE_TABLE(of, xadc_of_match_table); @@ -1094,8 +1187,10 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, { struct device *dev = indio_dev->dev.parent; struct xadc *xadc = iio_priv(indio_dev); + const struct iio_chan_spec *channel_templates; struct iio_chan_spec *channels, *chan; struct device_node *chan_node, *child; + unsigned int max_channels; unsigned int num_channels; const char *external_mux; u32 ext_mux_chan; @@ -1136,9 +1231,15 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, *conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan); } - - channels = devm_kmemdup(dev, xadc_channels, - sizeof(xadc_channels), GFP_KERNEL); + if (xadc->ops->type == XADC_TYPE_S7) { + channel_templates = xadc_7s_channels; + max_channels = ARRAY_SIZE(xadc_7s_channels); + } else { + channel_templates = xadc_us_channels; + max_channels = ARRAY_SIZE(xadc_us_channels); + } + channels = devm_kmemdup(dev, channel_templates, + sizeof(channels[0]) * max_channels, GFP_KERNEL); if (!channels) return -ENOMEM; @@ -1148,7 +1249,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, chan_node = of_get_child_by_name(np, "xlnx,channels"); if (chan_node) { for_each_child_of_node(chan_node, child) { - if (num_channels >= ARRAY_SIZE(xadc_channels)) { + if (num_channels >= max_channels) { of_node_put(child); break; } @@ -1184,8 +1285,28 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, return 0; } +static const char * const xadc_type_names[] = { + [XADC_TYPE_S7] = "xadc", + [XADC_TYPE_US] = "xilinx-system-monitor", +}; + +static void xadc_clk_disable_unprepare(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + +static void xadc_cancel_delayed_work(void *data) +{ + struct delayed_work *work = data; + + cancel_delayed_work_sync(work); +} + static int xadc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; const struct of_device_id *id; struct iio_dev *indio_dev; unsigned int bipolar_mask; @@ -1195,10 +1316,10 @@ static int xadc_probe(struct platform_device *pdev) int irq; int i; - if (!pdev->dev.of_node) + if (!dev->of_node) return -ENODEV; - id = of_match_node(xadc_of_match_table, pdev->dev.of_node); + id = of_match_node(xadc_of_match_table, dev->of_node); if (!id) return -EINVAL; @@ -1206,7 +1327,7 @@ static int xadc_probe(struct platform_device *pdev) if (irq <= 0) return -ENXIO; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*xadc)); if (!indio_dev) return -ENOMEM; @@ -1222,43 +1343,44 @@ static int xadc_probe(struct platform_device *pdev) if (IS_ERR(xadc->base)) return PTR_ERR(xadc->base); - indio_dev->name = "xadc"; + indio_dev->name = xadc_type_names[xadc->ops->type]; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &xadc_info; - ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0); + ret = xadc_parse_dt(indio_dev, dev->of_node, &conf0); if (ret) return ret; if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { - ret = iio_triggered_buffer_setup(indio_dev, - &iio_pollfunc_store_time, &xadc_trigger_handler, - &xadc_buffer_ops); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &xadc_trigger_handler, + &xadc_buffer_ops); if (ret) return ret; xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst"); - if (IS_ERR(xadc->convst_trigger)) { - ret = PTR_ERR(xadc->convst_trigger); - goto err_triggered_buffer_cleanup; - } + if (IS_ERR(xadc->convst_trigger)) + return PTR_ERR(xadc->convst_trigger); + xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev, "samplerate"); - if (IS_ERR(xadc->samplerate_trigger)) { - ret = PTR_ERR(xadc->samplerate_trigger); - goto err_free_convst_trigger; - } + if (IS_ERR(xadc->samplerate_trigger)) + return PTR_ERR(xadc->samplerate_trigger); } - xadc->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(xadc->clk)) { - ret = PTR_ERR(xadc->clk); - goto err_free_samplerate_trigger; - } + xadc->clk = devm_clk_get(dev, NULL); + if (IS_ERR(xadc->clk)) + return PTR_ERR(xadc->clk); ret = clk_prepare_enable(xadc->clk); if (ret) - goto err_free_samplerate_trigger; + return ret; + + ret = devm_add_action_or_reset(dev, + xadc_clk_disable_unprepare, xadc->clk); + if (ret) + return ret; /* * Make sure not to exceed the maximum samplerate since otherwise the @@ -1267,22 +1389,28 @@ static int xadc_probe(struct platform_device *pdev) if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { ret = xadc_read_samplerate(xadc); if (ret < 0) - goto err_free_samplerate_trigger; + return ret; + if (ret > XADC_MAX_SAMPLERATE) { ret = xadc_write_samplerate(xadc, XADC_MAX_SAMPLERATE); if (ret < 0) - goto err_free_samplerate_trigger; + return ret; } } - ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0, - dev_name(&pdev->dev), indio_dev); + ret = devm_request_irq(dev, xadc->irq, xadc->ops->interrupt_handler, 0, + dev_name(dev), indio_dev); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, xadc_cancel_delayed_work, + &xadc->zynq_unmask_work); if (ret) - goto err_clk_disable_unprepare; + return ret; ret = xadc->ops->setup(pdev, indio_dev, xadc->irq); if (ret) - goto err_free_irq; + return ret; for (i = 0; i < 16; i++) xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), @@ -1290,7 +1418,7 @@ static int xadc_probe(struct platform_device *pdev) ret = xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0); if (ret) - goto err_free_irq; + return ret; bipolar_mask = 0; for (i = 0; i < indio_dev->num_channels; i++) { @@ -1300,17 +1428,18 @@ static int xadc_probe(struct platform_device *pdev) ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask); if (ret) - goto err_free_irq; + return ret; + ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1), bipolar_mask >> 16); if (ret) - goto err_free_irq; + return ret; /* Disable all alarms */ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, XADC_CONF1_ALARM_MASK); if (ret) - goto err_free_irq; + return ret; /* Set thresholds to min/max */ for (i = 0; i < 16; i++) { @@ -1325,60 +1454,17 @@ static int xadc_probe(struct platform_device *pdev) ret = xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i), xadc->threshold[i]); if (ret) - goto err_free_irq; + return ret; } /* Go to non-buffered mode */ xadc_postdisable(indio_dev); - ret = iio_device_register(indio_dev); - if (ret) - goto err_free_irq; - - platform_set_drvdata(pdev, indio_dev); - - return 0; - -err_free_irq: - free_irq(xadc->irq, indio_dev); - cancel_delayed_work_sync(&xadc->zynq_unmask_work); -err_clk_disable_unprepare: - clk_disable_unprepare(xadc->clk); -err_free_samplerate_trigger: - if (xadc->ops->flags & XADC_FLAGS_BUFFERED) - iio_trigger_free(xadc->samplerate_trigger); -err_free_convst_trigger: - if (xadc->ops->flags & XADC_FLAGS_BUFFERED) - iio_trigger_free(xadc->convst_trigger); -err_triggered_buffer_cleanup: - if (xadc->ops->flags & XADC_FLAGS_BUFFERED) - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int xadc_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - struct xadc *xadc = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { - iio_trigger_free(xadc->samplerate_trigger); - iio_trigger_free(xadc->convst_trigger); - iio_triggered_buffer_cleanup(indio_dev); - } - free_irq(xadc->irq, indio_dev); - cancel_delayed_work_sync(&xadc->zynq_unmask_work); - clk_disable_unprepare(xadc->clk); - kfree(xadc->data); - - return 0; + return devm_iio_device_register(dev, indio_dev); } static struct platform_driver xadc_driver = { .probe = xadc_probe, - .remove = xadc_remove, .driver = { .name = "xadc", .of_match_table = xadc_of_match_table, diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c index 2357f585720a..1bd375fb10e0 100644 --- a/drivers/iio/adc/xilinx-xadc-events.c +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -155,9 +155,6 @@ err_out: return ret; } -/* Register value is msb aligned, the lower 4 bits are ignored */ -#define XADC_THRESHOLD_VALUE_SHIFT 4 - int xadc_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, @@ -177,7 +174,8 @@ int xadc_read_event_value(struct iio_dev *indio_dev, return -EINVAL; } - *val >>= XADC_THRESHOLD_VALUE_SHIFT; + /* MSB aligned */ + *val >>= 16 - chan->scan_type.realbits; return IIO_VAL_INT; } @@ -191,7 +189,8 @@ int xadc_write_event_value(struct iio_dev *indio_dev, struct xadc *xadc = iio_priv(indio_dev); int ret = 0; - val <<= XADC_THRESHOLD_VALUE_SHIFT; + /* MSB aligned */ + val <<= 16 - chan->scan_type.realbits; if (val < 0 || val > 0xffff) return -EINVAL; diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index 25abed9c0285..8b80195725e9 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -70,6 +70,11 @@ struct xadc { int irq; }; +enum xadc_type { + XADC_TYPE_S7, /* Series 7 */ + XADC_TYPE_US, /* UltraScale and UltraScale+ */ +}; + struct xadc_ops { int (*read)(struct xadc *xadc, unsigned int reg, uint16_t *val); int (*write)(struct xadc *xadc, unsigned int reg, uint16_t val); @@ -80,6 +85,7 @@ struct xadc_ops { irqreturn_t (*interrupt_handler)(int irq, void *devid); unsigned int flags; + enum xadc_type type; }; static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg, |