diff options
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r-- | drivers/iio/adc/ad7791.c | 87 | ||||
-rw-r--r-- | drivers/iio/adc/imx7d_adc.c | 2 | ||||
-rw-r--r-- | drivers/iio/adc/meson_saradc.c | 83 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc-core.c | 66 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc.c | 47 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-dfsdm-adc.c | 17 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-dfsdm-core.c | 26 | ||||
-rw-r--r-- | drivers/iio/adc/stx104.c | 11 | ||||
-rw-r--r-- | drivers/iio/adc/ti-ads8688.c | 48 |
9 files changed, 279 insertions, 108 deletions
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index 70fbf92f9827..a9ff0695ddf7 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -153,6 +153,17 @@ struct ad7791_state { const struct ad7791_chip_info *info; }; +static const int ad7791_sample_freq_avail[8][2] = { + [AD7791_FILTER_RATE_120] = { 120, 0 }, + [AD7791_FILTER_RATE_100] = { 100, 0 }, + [AD7791_FILTER_RATE_33_3] = { 33, 300000 }, + [AD7791_FILTER_RATE_20] = { 20, 0 }, + [AD7791_FILTER_RATE_16_6] = { 16, 600000 }, + [AD7791_FILTER_RATE_16_7] = { 16, 700000 }, + [AD7791_FILTER_RATE_13_3] = { 13, 300000 }, + [AD7791_FILTER_RATE_9_5] = { 9, 500000 }, +}; + static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd) { return container_of(sd, struct ad7791_state, sd); @@ -202,6 +213,7 @@ static int ad7791_read_raw(struct iio_dev *indio_dev, { struct ad7791_state *st = iio_priv(indio_dev); bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR); + unsigned int rate; switch (info) { case IIO_CHAN_INFO_RAW: @@ -239,63 +251,56 @@ static int ad7791_read_raw(struct iio_dev *indio_dev, *val2 = chan->scan_type.realbits - 1; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + rate = st->filter & AD7791_FILTER_RATE_MASK; + *val = ad7791_sample_freq_avail[rate][0]; + *val2 = ad7791_sample_freq_avail[rate][1]; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } -static const char * const ad7791_sample_freq_avail[] = { - [AD7791_FILTER_RATE_120] = "120", - [AD7791_FILTER_RATE_100] = "100", - [AD7791_FILTER_RATE_33_3] = "33.3", - [AD7791_FILTER_RATE_20] = "20", - [AD7791_FILTER_RATE_16_6] = "16.6", - [AD7791_FILTER_RATE_16_7] = "16.7", - [AD7791_FILTER_RATE_13_3] = "13.3", - [AD7791_FILTER_RATE_9_5] = "9.5", -}; - -static ssize_t ad7791_read_frequency(struct device *dev, - struct device_attribute *attr, char *buf) +static int ad7791_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7791_state *st = iio_priv(indio_dev); - unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK; - - return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]); -} - -static ssize_t ad7791_write_frequency(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7791_state *st = iio_priv(indio_dev); - int i, ret; - - i = sysfs_match_string(ad7791_sample_freq_avail, buf); - if (i < 0) - return i; + int ret, i; ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; - st->filter &= ~AD7791_FILTER_RATE_MASK; - st->filter |= i; - ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, sizeof(st->filter), - st->filter); - iio_device_release_direct_mode(indio_dev); - return len; -} + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) { + if (ad7791_sample_freq_avail[i][0] == val && + ad7791_sample_freq_avail[i][1] == val2) + break; + } + + if (i == ARRAY_SIZE(ad7791_sample_freq_avail)) { + ret = -EINVAL; + break; + } + + st->filter &= ~AD7791_FILTER_RATE_MASK; + st->filter |= i; + ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, + sizeof(st->filter), + st->filter); + break; + default: + ret = -EINVAL; + } -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad7791_read_frequency, - ad7791_write_frequency); + iio_device_release_direct_mode(indio_dev); + return ret; +} static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5"); static struct attribute *ad7791_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL }; @@ -306,12 +311,14 @@ static const struct attribute_group ad7791_attribute_group = { static const struct iio_info ad7791_info = { .read_raw = &ad7791_read_raw, + .write_raw = &ad7791_write_raw, .attrs = &ad7791_attribute_group, .validate_trigger = ad_sd_validate_trigger, }; static const struct iio_info ad7791_no_filter_info = { .read_raw = &ad7791_read_raw, + .write_raw = &ad7791_write_raw, .validate_trigger = ad_sd_validate_trigger, }; diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c index cfab31162845..ad6764fb2a23 100644 --- a/drivers/iio/adc/imx7d_adc.c +++ b/drivers/iio/adc/imx7d_adc.c @@ -604,5 +604,5 @@ static struct platform_driver imx7d_adc_driver = { module_platform_driver(imx7d_adc_driver); MODULE_AUTHOR("Haibo Chen <haibo.chen@freescale.com>"); -MODULE_DESCRIPTION("Freeacale IMX7D ADC driver"); +MODULE_DESCRIPTION("Freescale IMX7D ADC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index ede955d9b2a4..2948909f3ee3 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -219,15 +219,19 @@ enum meson_sar_adc_chan7_mux_sel { CHAN7_MUX_CH7_INPUT = 0x7, }; -struct meson_sar_adc_data { +struct meson_sar_adc_param { bool has_bl30_integration; unsigned long clock_rate; u32 bandgap_reg; unsigned int resolution; - const char *name; const struct regmap_config *regmap_config; }; +struct meson_sar_adc_data { + const struct meson_sar_adc_param *param; + const char *name; +}; + struct meson_sar_adc_priv { struct regmap *regmap; struct regulator *vref; @@ -276,7 +280,7 @@ static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val) /* use val_calib = scale * val_raw + offset calibration function */ tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias; - return clamp(tmp, 0, (1 << priv->data->resolution) - 1); + return clamp(tmp, 0, (1 << priv->data->param->resolution) - 1); } static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev) @@ -328,7 +332,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, } fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval); - fifo_val &= GENMASK(priv->data->resolution - 1, 0); + fifo_val &= GENMASK(priv->data->param->resolution - 1, 0); *val = meson_sar_adc_calib_val(indio_dev, fifo_val); return 0; @@ -447,7 +451,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) mutex_lock(&indio_dev->mlock); - if (priv->data->has_bl30_integration) { + if (priv->data->param->has_bl30_integration) { /* prevent BL30 from using the SAR ADC while we are using it */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, MESON_SAR_ADC_DELAY_KERNEL_BUSY, @@ -475,7 +479,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - if (priv->data->has_bl30_integration) + if (priv->data->param->has_bl30_integration) /* allow BL30 to use the SAR ADC again */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); @@ -559,7 +563,7 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev, } *val = ret / 1000; - *val2 = priv->data->resolution; + *val2 = priv->data->param->resolution; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_CALIBBIAS: @@ -632,7 +636,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) */ meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); - if (priv->data->has_bl30_integration) { + if (priv->data->param->has_bl30_integration) { /* * leave sampling delay and the input clocks as configured by * BL30 to make sure BL30 gets the values it expects when @@ -712,7 +716,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) return ret; } - ret = clk_set_rate(priv->adc_clk, priv->data->clock_rate); + ret = clk_set_rate(priv->adc_clk, priv->data->param->clock_rate); if (ret) { dev_err(indio_dev->dev.parent, "failed to set adc clock rate\n"); @@ -725,14 +729,15 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + const struct meson_sar_adc_param *param = priv->data->param; u32 enable_mask; - if (priv->data->bandgap_reg == MESON_SAR_ADC_REG11) + if (param->bandgap_reg == MESON_SAR_ADC_REG11) enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN; else enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN; - regmap_update_bits(priv->regmap, priv->data->bandgap_reg, enable_mask, + regmap_update_bits(priv->regmap, param->bandgap_reg, enable_mask, on_off ? enable_mask : 0); } @@ -844,8 +849,8 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev) int ret, nominal0, nominal1, value0, value1; /* use points 25% and 75% for calibration */ - nominal0 = (1 << priv->data->resolution) / 4; - nominal1 = (1 << priv->data->resolution) * 3 / 4; + nominal0 = (1 << priv->data->param->resolution) / 4; + nominal1 = (1 << priv->data->param->resolution) * 3 / 4; meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4); usleep_range(10, 20); @@ -883,51 +888,60 @@ static const struct iio_info meson_sar_adc_iio_info = { .read_raw = meson_sar_adc_iio_info_read_raw, }; -static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { - .has_bl30_integration = false, - .clock_rate = 1150000, - .bandgap_reg = MESON_SAR_ADC_DELTA_10, - .regmap_config = &meson_sar_adc_regmap_config_meson8, - .resolution = 10, - .name = "meson-meson8-saradc", -}; - -static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { +static const struct meson_sar_adc_param meson_sar_adc_meson8_param = { .has_bl30_integration = false, .clock_rate = 1150000, .bandgap_reg = MESON_SAR_ADC_DELTA_10, .regmap_config = &meson_sar_adc_regmap_config_meson8, .resolution = 10, - .name = "meson-meson8b-saradc", }; -static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { +static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = { .has_bl30_integration = true, .clock_rate = 1200000, .bandgap_reg = MESON_SAR_ADC_REG11, .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 10, - .name = "meson-gxbb-saradc", }; -static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { +static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { .has_bl30_integration = true, .clock_rate = 1200000, .bandgap_reg = MESON_SAR_ADC_REG11, .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 12, +}; + +static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { + .param = &meson_sar_adc_meson8_param, + .name = "meson-meson8-saradc", +}; + +static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { + .param = &meson_sar_adc_meson8_param, + .name = "meson-meson8b-saradc", +}; + +static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { + .param = &meson_sar_adc_gxbb_param, + .name = "meson-gxbb-saradc", +}; + +static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { + .param = &meson_sar_adc_gxl_param, .name = "meson-gxl-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { - .has_bl30_integration = true, - .clock_rate = 1200000, - .bandgap_reg = MESON_SAR_ADC_REG11, - .regmap_config = &meson_sar_adc_regmap_config_gxbb, - .resolution = 12, + .param = &meson_sar_adc_gxl_param, .name = "meson-gxm-saradc", }; +static const struct meson_sar_adc_data meson_sar_adc_axg_data = { + .param = &meson_sar_adc_gxl_param, + .name = "meson-axg-saradc", +}; + static const struct of_device_id meson_sar_adc_of_match[] = { { .compatible = "amlogic,meson8-saradc", @@ -946,6 +960,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { }, { .compatible = "amlogic,meson-gxm-saradc", .data = &meson_sar_adc_gxm_data, + }, { + .compatible = "amlogic,meson-axg-saradc", + .data = &meson_sar_adc_axg_data, }, {}, }; @@ -1001,7 +1018,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) return ret; priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, - priv->data->regmap_config); + priv->data->param->regmap_config); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 40be7d9fadbf..ca432e7b6ff1 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -34,9 +34,6 @@ #define STM32F4_ADC_ADCPRE_SHIFT 16 #define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16) -/* STM32 F4 maximum analog clock rate (from datasheet) */ -#define STM32F4_ADC_MAX_CLK_RATE 36000000 - /* STM32H7 - common registers for all ADC instances */ #define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) #define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) @@ -51,9 +48,6 @@ #define STM32H7_CKMODE_SHIFT 16 #define STM32H7_CKMODE_MASK GENMASK(17, 16) -/* STM32 H7 maximum analog clock rate (from datasheet) */ -#define STM32H7_ADC_MAX_CLK_RATE 36000000 - /** * stm32_adc_common_regs - stm32 common registers, compatible dependent data * @csr: common status register offset @@ -74,15 +68,17 @@ struct stm32_adc_priv; * stm32_adc_priv_cfg - stm32 core compatible configuration data * @regs: common registers for all instances * @clk_sel: clock selection routine + * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) */ struct stm32_adc_priv_cfg { const struct stm32_adc_common_regs *regs; int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); + u32 max_clk_rate_hz; }; /** * struct stm32_adc_priv - stm32 ADC core private data - * @irq: irq for ADC block + * @irq: irq(s) for ADC block * @domain: irq domain reference * @aclk: clock reference for the analog circuitry * @bclk: bus clock common for all ADCs, depends on part used @@ -91,7 +87,7 @@ struct stm32_adc_priv_cfg { * @common: common data for all ADC instances */ struct stm32_adc_priv { - int irq; + int irq[STM32_ADC_MAX_ADCS]; struct irq_domain *domain; struct clk *aclk; struct clk *bclk; @@ -133,7 +129,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, } for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { - if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE) + if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz) break; } if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { @@ -222,7 +218,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (ckmode) continue; - if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) + if ((rate / div) <= priv->cfg->max_clk_rate_hz) goto out; } } @@ -242,7 +238,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (!ckmode) continue; - if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) + if ((rate / div) <= priv->cfg->max_clk_rate_hz) goto out; } @@ -328,11 +324,24 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, struct stm32_adc_priv *priv) { struct device_node *np = pdev->dev.of_node; + unsigned int i; + + for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { + priv->irq[i] = platform_get_irq(pdev, i); + if (priv->irq[i] < 0) { + /* + * At least one interrupt must be provided, make others + * optional: + * - stm32f4/h7 shares a common interrupt. + * - stm32mp1, has one line per ADC (either for ADC1, + * ADC2 or both). + */ + if (i && priv->irq[i] == -ENXIO) + continue; + dev_err(&pdev->dev, "failed to get irq\n"); - priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); - return priv->irq; + return priv->irq[i]; + } } priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0, @@ -343,8 +352,12 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, return -ENOMEM; } - irq_set_chained_handler(priv->irq, stm32_adc_irq_handler); - irq_set_handler_data(priv->irq, priv); + for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { + if (priv->irq[i] < 0) + continue; + irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler); + irq_set_handler_data(priv->irq[i], priv); + } return 0; } @@ -353,11 +366,17 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, struct stm32_adc_priv *priv) { int hwirq; + unsigned int i; for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++) irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); irq_domain_remove(priv->domain); - irq_set_chained_handler(priv->irq, NULL); + + for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { + if (priv->irq[i] < 0) + continue; + irq_set_chained_handler(priv->irq[i], NULL); + } } static int stm32_adc_probe(struct platform_device *pdev) @@ -497,11 +516,19 @@ static int stm32_adc_remove(struct platform_device *pdev) static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { .regs = &stm32f4_adc_common_regs, .clk_sel = stm32f4_adc_clk_sel, + .max_clk_rate_hz = 36000000, }; static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { .regs = &stm32h7_adc_common_regs, .clk_sel = stm32h7_adc_clk_sel, + .max_clk_rate_hz = 36000000, +}; + +static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { + .regs = &stm32h7_adc_common_regs, + .clk_sel = stm32h7_adc_clk_sel, + .max_clk_rate_hz = 40000000, }; static const struct of_device_id stm32_adc_of_match[] = { @@ -512,6 +539,9 @@ static const struct of_device_id stm32_adc_of_match[] = { .compatible = "st,stm32h7-adc-core", .data = (void *)&stm32h7_adc_priv_cfg }, { + .compatible = "st,stm32mp1-adc-core", + .data = (void *)&stm32mp1_adc_priv_cfg + }, { }, }; MODULE_DEVICE_TABLE(of, stm32_adc_of_match); diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 9a2583caedaa..378411853d75 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -84,6 +84,7 @@ #define STM32H7_ADC_CALFACT2 0xC8 /* STM32H7_ADC_ISR - bit fields */ +#define STM32MP1_VREGREADY BIT(12) #define STM32H7_EOC BIT(2) #define STM32H7_ADRDY BIT(0) @@ -249,6 +250,7 @@ struct stm32_adc; * @adc_info: per instance input channels definitions * @trigs: external trigger sources * @clk_required: clock is required + * @has_vregready: vregready status flag presence * @selfcalib: optional routine for self-calibration * @prepare: optional prepare routine (power-up, enable) * @start_conv: routine to start conversions @@ -261,6 +263,7 @@ struct stm32_adc_cfg { const struct stm32_adc_info *adc_info; struct stm32_adc_trig_info *trigs; bool clk_required; + bool has_vregready; int (*selfcalib)(struct stm32_adc *); int (*prepare)(struct stm32_adc *); void (*start_conv)(struct stm32_adc *, bool dma); @@ -695,8 +698,12 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK); } -static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) +static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) { + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + int ret; + u32 val; + /* Exit deep power down, then enable ADC voltage regulator */ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD); stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN); @@ -705,7 +712,20 @@ static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST); /* Wait for startup time */ - usleep_range(10, 20); + if (!adc->cfg->has_vregready) { + usleep_range(10, 20); + return 0; + } + + ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_ISR, val, + val & STM32MP1_VREGREADY, 100, + STM32_ADC_TIMEOUT_US); + if (ret) { + stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD); + dev_err(&indio_dev->dev, "Failed to exit power down\n"); + } + + return ret; } static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc) @@ -888,7 +908,9 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) int ret; u32 val; - stm32h7_adc_exit_pwr_down(adc); + ret = stm32h7_adc_exit_pwr_down(adc); + if (ret) + return ret; /* * Select calibration mode: @@ -952,7 +974,10 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) { int ret; - stm32h7_adc_exit_pwr_down(adc); + ret = stm32h7_adc_exit_pwr_down(adc); + if (ret) + return ret; + stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); ret = stm32h7_adc_enable(adc); @@ -1944,9 +1969,23 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .smp_cycles = stm32h7_adc_smp_cycles, }; +static const struct stm32_adc_cfg stm32mp1_adc_cfg = { + .regs = &stm32h7_adc_regspec, + .adc_info = &stm32h7_adc_info, + .trigs = stm32h7_adc_trigs, + .has_vregready = true, + .selfcalib = stm32h7_adc_selfcalib, + .start_conv = stm32h7_adc_start_conv, + .stop_conv = stm32h7_adc_stop_conv, + .prepare = stm32h7_adc_prepare, + .unprepare = stm32h7_adc_unprepare, + .smp_cycles = stm32h7_adc_smp_cycles, +}; + static const struct of_device_id stm32_adc_of_match[] = { { .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg }, { .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg }, + { .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg }, {}, }; MODULE_DEVICE_TABLE(of, stm32_adc_of_match); diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index b28a716a23b2..fcd4a1c00ca0 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -8,11 +8,11 @@ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> -#include <linux/interrupt.h> +#include <linux/iio/adc/stm32-dfsdm-adc.h> #include <linux/iio/buffer.h> #include <linux/iio/hw-consumer.h> -#include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> @@ -254,7 +254,8 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, DFSDM_CR1_RSWSTART(1)); } -static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, unsigned int fl_id) +static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, + unsigned int fl_id) { /* Disable conversion */ regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), @@ -338,7 +339,7 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, "st,adc-channel-types", chan_idx, &of_str); if (!ret) { - val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type); + val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type); if (val < 0) return val; } else { @@ -350,7 +351,7 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, "st,adc-channel-clk-src", chan_idx, &of_str); if (!ret) { - val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src); + val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src); if (val < 0) return val; } else { @@ -1104,7 +1105,6 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) char *name; int ret, irq, val; - dev_data = of_device_get_match_data(dev); iio = devm_iio_device_alloc(dev, sizeof(*adc)); if (!iio) { @@ -1122,8 +1122,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adc); ret = of_property_read_u32(dev->of_node, "reg", &adc->fl_id); - if (ret != 0) { - dev_err(dev, "Missing reg property\n"); + if (ret != 0 || adc->fl_id >= adc->dfsdm->num_fls) { + dev_err(dev, "Missing or bad reg property\n"); return -EINVAL; } @@ -1172,7 +1172,6 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) if (ret < 0) goto err_cleanup; - dev_err(dev, "of_platform_populate\n"); if (dev_data->type == DFSDM_AUDIO) { ret = of_platform_populate(np, NULL, NULL, dev); if (ret < 0) { diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index e50efdcc41ff..bf089f5d6225 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -25,6 +25,8 @@ struct stm32_dfsdm_dev_data { #define STM32H7_DFSDM_NUM_FILTERS 4 #define STM32H7_DFSDM_NUM_CHANNELS 8 +#define STM32MP1_DFSDM_NUM_FILTERS 6 +#define STM32MP1_DFSDM_NUM_CHANNELS 8 static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) { @@ -61,6 +63,21 @@ static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_data = { .regmap_cfg = &stm32h7_dfsdm_regmap_cfg, }; +static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = 0x7fc, + .volatile_reg = stm32_dfsdm_volatile_reg, + .fast_io = true, +}; + +static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = { + .num_filters = STM32MP1_DFSDM_NUM_FILTERS, + .num_channels = STM32MP1_DFSDM_NUM_CHANNELS, + .regmap_cfg = &stm32mp1_dfsdm_regmap_cfg, +}; + struct dfsdm_priv { struct platform_device *pdev; /* platform device */ @@ -227,6 +244,11 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, } priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; + if (!priv->spi_clk_out_div) { + /* spi_clk_out_div == 0 means ckout is OFF */ + dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); + return -EINVAL; + } priv->dfsdm.spi_master_freq = spi_freq; if (rem) { @@ -243,6 +265,10 @@ static const struct of_device_id stm32_dfsdm_of_match[] = { .compatible = "st,stm32h7-dfsdm", .data = &stm32h7_dfsdm_data, }, + { + .compatible = "st,stm32mp1-dfsdm", + .data = &stm32mp1_dfsdm_data, + }, {} }; MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c index 17b021f33180..0662ca199eb0 100644 --- a/drivers/iio/adc/stx104.c +++ b/drivers/iio/adc/stx104.c @@ -233,6 +233,16 @@ static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!(inb(stx104gpio->base) & BIT(offset)); } +static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + + *bits = inb(stx104gpio->base); + + return 0; +} + static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { @@ -342,6 +352,7 @@ static int stx104_probe(struct device *dev, unsigned int id) stx104gpio->chip.direction_input = stx104_gpio_direction_input; stx104gpio->chip.direction_output = stx104_gpio_direction_output; stx104gpio->chip.get = stx104_gpio_get; + stx104gpio->chip.get_multiple = stx104_gpio_get_multiple; stx104gpio->chip.set = stx104_gpio_set; stx104gpio->chip.set_multiple = stx104_gpio_set_multiple; stx104gpio->base = base[id] + 3; diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index 079f133144b0..184d686ebd99 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -17,6 +17,9 @@ #include <linux/of.h> #include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include <linux/iio/sysfs.h> #define ADS8688_CMD_REG(x) (x << 8) @@ -155,6 +158,13 @@ static const struct attribute_group ads8688_attribute_group = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ | BIT(IIO_CHAN_INFO_SCALE) \ | BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ } static const struct iio_chan_spec ads8684_channels[] = { @@ -371,6 +381,28 @@ static const struct iio_info ads8688_info = { .attrs = &ads8688_attribute_group, }; +static irqreturn_t ads8688_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + u16 buffer[8]; + int i, j = 0; + + for (i = 0; i < indio_dev->masklength; i++) { + if (!test_bit(i, indio_dev->active_scan_mask)) + continue; + buffer[j] = ads8688_read(indio_dev, i); + j++; + } + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + pf->timestamp); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static const struct ads8688_chip_info ads8688_chip_info_tbl[] = { [ID_ADS8684] = { .channels = ads8684_channels, @@ -402,7 +434,7 @@ static int ads8688_probe(struct spi_device *spi) ret = regulator_get_voltage(st->reg); if (ret < 0) - goto error_out; + goto err_regulator_disable; st->vref_mv = ret / 1000; } else { @@ -430,13 +462,22 @@ static int ads8688_probe(struct spi_device *spi) mutex_init(&st->lock); + ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL); + if (ret < 0) { + dev_err(&spi->dev, "iio triggered buffer setup failed\n"); + goto err_regulator_disable; + } + ret = iio_device_register(indio_dev); if (ret) - goto error_out; + goto err_buffer_cleanup; return 0; -error_out: +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + +err_regulator_disable: if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -449,6 +490,7 @@ static int ads8688_remove(struct spi_device *spi) struct ads8688_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); if (!IS_ERR(st->reg)) regulator_disable(st->reg); |