diff options
Diffstat (limited to 'drivers/iio/adc/stm32-adc.c')
-rw-r--r-- | drivers/iio/adc/stm32-adc.c | 156 |
1 files changed, 149 insertions, 7 deletions
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 5bfcc1f13105..4df32cf1650e 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -25,6 +25,7 @@ #include <linux/dmaengine.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> +#include <linux/iio/timer/stm32-lptim-trigger.h> #include <linux/iio/timer/stm32-timer-trigger.h> #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> @@ -83,6 +84,8 @@ #define STM32H7_ADC_IER 0x04 #define STM32H7_ADC_CR 0x08 #define STM32H7_ADC_CFGR 0x0C +#define STM32H7_ADC_SMPR1 0x14 +#define STM32H7_ADC_SMPR2 0x18 #define STM32H7_ADC_PCSEL 0x1C #define STM32H7_ADC_SQR1 0x30 #define STM32H7_ADC_SQR2 0x34 @@ -151,6 +154,7 @@ enum stm32h7_adc_dmngt { #define STM32H7_BOOST_CLKRATE 20000000UL #define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */ +#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ #define STM32_ADC_TIMEOUT_US 100000 #define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) @@ -182,6 +186,11 @@ enum stm32_adc_extsel { STM32_EXT13, STM32_EXT14, STM32_EXT15, + STM32_EXT16, + STM32_EXT17, + STM32_EXT18, + STM32_EXT19, + STM32_EXT20, }; /** @@ -227,6 +236,8 @@ struct stm32_adc_regs { * @exten: trigger control register & bitfield * @extsel: trigger selection register & bitfield * @res: resolution selection register & bitfield + * @smpr: smpr1 & smpr2 registers offset array + * @smp_bits: smpr1 & smpr2 index and bitfields */ struct stm32_adc_regspec { const u32 dr; @@ -236,6 +247,8 @@ struct stm32_adc_regspec { const struct stm32_adc_regs exten; const struct stm32_adc_regs extsel; const struct stm32_adc_regs res; + const u32 smpr[2]; + const struct stm32_adc_regs *smp_bits; }; struct stm32_adc; @@ -251,6 +264,7 @@ struct stm32_adc; * @start_conv: routine to start conversions * @stop_conv: routine to stop conversions * @unprepare: optional unprepare routine (disable, power-down) + * @smp_cycles: programmable sampling time (ADC clock cycles) */ struct stm32_adc_cfg { const struct stm32_adc_regspec *regs; @@ -262,6 +276,7 @@ struct stm32_adc_cfg { void (*start_conv)(struct stm32_adc *, bool dma); void (*stop_conv)(struct stm32_adc *); void (*unprepare)(struct stm32_adc *); + const unsigned int *smp_cycles; }; /** @@ -283,6 +298,7 @@ struct stm32_adc_cfg { * @rx_dma_buf: dma rx buffer bus address * @rx_buf_sz: dma rx buffer size * @pcsel bitmask to preselect channels on some devices + * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) * @cal: optional calibration data on some devices */ struct stm32_adc { @@ -303,6 +319,7 @@ struct stm32_adc { dma_addr_t rx_dma_buf; unsigned int rx_buf_sz; u32 pcsel; + u32 smpr_val[2]; struct stm32_adc_calib cal; }; @@ -431,6 +448,39 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { {}, /* sentinel */ }; +/** + * stm32f4_smp_bits[] - describe sampling time register index & bit fields + * Sorted so it can be indexed by channel number. + */ +static const struct stm32_adc_regs stm32f4_smp_bits[] = { + /* STM32F4_ADC_SMPR2: smpr[] index, mask, shift for SMP0 to SMP9 */ + { 1, GENMASK(2, 0), 0 }, + { 1, GENMASK(5, 3), 3 }, + { 1, GENMASK(8, 6), 6 }, + { 1, GENMASK(11, 9), 9 }, + { 1, GENMASK(14, 12), 12 }, + { 1, GENMASK(17, 15), 15 }, + { 1, GENMASK(20, 18), 18 }, + { 1, GENMASK(23, 21), 21 }, + { 1, GENMASK(26, 24), 24 }, + { 1, GENMASK(29, 27), 27 }, + /* STM32F4_ADC_SMPR1, smpr[] index, mask, shift for SMP10 to SMP18 */ + { 0, GENMASK(2, 0), 0 }, + { 0, GENMASK(5, 3), 3 }, + { 0, GENMASK(8, 6), 6 }, + { 0, GENMASK(11, 9), 9 }, + { 0, GENMASK(14, 12), 12 }, + { 0, GENMASK(17, 15), 15 }, + { 0, GENMASK(20, 18), 18 }, + { 0, GENMASK(23, 21), 21 }, + { 0, GENMASK(26, 24), 24 }, +}; + +/* STM32F4 programmable sampling time (ADC clock cycles) */ +static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { + 3, 15, 28, 56, 84, 112, 144, 480, +}; + static const struct stm32_adc_regspec stm32f4_adc_regspec = { .dr = STM32F4_ADC_DR, .ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE }, @@ -440,6 +490,8 @@ static const struct stm32_adc_regspec stm32f4_adc_regspec = { .extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK, STM32F4_EXTSEL_SHIFT }, .res = { STM32F4_ADC_CR1, STM32F4_RES_MASK, STM32F4_RES_SHIFT }, + .smpr = { STM32F4_ADC_SMPR1, STM32F4_ADC_SMPR2 }, + .smp_bits = stm32f4_smp_bits, }; static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = { @@ -480,9 +532,46 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { { TIM4_TRGO, STM32_EXT12 }, { TIM6_TRGO, STM32_EXT13 }, { TIM3_CH4, STM32_EXT15 }, + { LPTIM1_OUT, STM32_EXT18 }, + { LPTIM2_OUT, STM32_EXT19 }, + { LPTIM3_OUT, STM32_EXT20 }, {}, }; +/** + * stm32h7_smp_bits - describe sampling time register index & bit fields + * Sorted so it can be indexed by channel number. + */ +static const struct stm32_adc_regs stm32h7_smp_bits[] = { + /* STM32H7_ADC_SMPR1, smpr[] index, mask, shift for SMP0 to SMP9 */ + { 0, GENMASK(2, 0), 0 }, + { 0, GENMASK(5, 3), 3 }, + { 0, GENMASK(8, 6), 6 }, + { 0, GENMASK(11, 9), 9 }, + { 0, GENMASK(14, 12), 12 }, + { 0, GENMASK(17, 15), 15 }, + { 0, GENMASK(20, 18), 18 }, + { 0, GENMASK(23, 21), 21 }, + { 0, GENMASK(26, 24), 24 }, + { 0, GENMASK(29, 27), 27 }, + /* STM32H7_ADC_SMPR2, smpr[] index, mask, shift for SMP10 to SMP19 */ + { 1, GENMASK(2, 0), 0 }, + { 1, GENMASK(5, 3), 3 }, + { 1, GENMASK(8, 6), 6 }, + { 1, GENMASK(11, 9), 9 }, + { 1, GENMASK(14, 12), 12 }, + { 1, GENMASK(17, 15), 15 }, + { 1, GENMASK(20, 18), 18 }, + { 1, GENMASK(23, 21), 21 }, + { 1, GENMASK(26, 24), 24 }, + { 1, GENMASK(29, 27), 27 }, +}; + +/* STM32H7 programmable sampling time (ADC clock cycles, rounded down) */ +static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { + 1, 2, 8, 16, 32, 64, 387, 810, +}; + static const struct stm32_adc_regspec stm32h7_adc_regspec = { .dr = STM32H7_ADC_DR, .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE }, @@ -492,6 +581,8 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = { .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK, STM32H7_EXTSEL_SHIFT }, .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, + .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, + .smp_bits = stm32h7_smp_bits, }; /** @@ -933,6 +1024,7 @@ static void stm32h7_adc_unprepare(struct stm32_adc *adc) * @scan_mask: channels to be converted * * Conversion sequence : + * Apply sampling time settings for all channels. * Configure ADC scan sequence based on selected channels in scan_mask. * Add channels to SQR registers, from scan_mask LSB to MSB, then * program sequence len. @@ -946,6 +1038,10 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, u32 val, bit; int i = 0; + /* Apply sampling time settings */ + stm32_adc_writel(adc, adc->cfg->regs->smpr[0], adc->smpr_val[0]); + stm32_adc_writel(adc, adc->cfg->regs->smpr[1], adc->smpr_val[1]); + for_each_set_bit(bit, scan_mask, indio_dev->masklength) { chan = indio_dev->channels + bit; /* @@ -995,7 +1091,8 @@ static int stm32_adc_get_trig_extsel(struct iio_dev *indio_dev, * Checking both stm32 timer trigger type and trig name * should be safe against arbitrary trigger names. */ - if (is_stm32_timer_trigger(trig) && + if ((is_stm32_timer_trigger(trig) || + is_stm32_lptim_trigger(trig)) && !strcmp(adc->cfg->trigs[i].name, trig->name)) { return adc->cfg->trigs[i].extsel; } @@ -1079,6 +1176,7 @@ static const struct iio_enum stm32_adc_trig_pol = { * @res: conversion result * * The function performs a single conversion on a given channel: + * - Apply sampling time settings * - Program sequencer with one channel (e.g. in SQ1 with len = 1) * - Use SW trigger * - Start conversion, then wait for interrupt completion. @@ -1103,6 +1201,10 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, return ret; } + /* Apply sampling time settings */ + stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]); + stm32_adc_writel(adc, regs->smpr[1], adc->smpr_val[1]); + /* Program chan number in regular sequence (SQ1) */ val = stm32_adc_readl(adc, regs->sqr[1].reg); val &= ~regs->sqr[1].mask; @@ -1507,10 +1609,28 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev) return 0; } +static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) +{ + const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel]; + u32 period_ns, shift = smpr->shift, mask = smpr->mask; + unsigned int smp, r = smpr->reg; + + /* Determine sampling time (ADC clock cycles) */ + period_ns = NSEC_PER_SEC / adc->common->rate; + for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++) + if ((period_ns * adc->cfg->smp_cycles[smp]) >= smp_ns) + break; + if (smp > STM32_ADC_MAX_SMP) + smp = STM32_ADC_MAX_SMP; + + /* pre-build sampling time registers (e.g. smpr1, smpr2) */ + adc->smpr_val[r] = (adc->smpr_val[r] & ~mask) | (smp << shift); +} + static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, struct iio_chan_spec *chan, const struct stm32_adc_chan_spec *channel, - int scan_index) + int scan_index, u32 smp) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -1526,6 +1646,9 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, chan->scan_type.storagebits = 16; chan->ext_info = stm32_adc_ext_info; + /* Prepare sampling time settings */ + stm32_adc_smpr_init(adc, chan->channel, smp); + /* pre-build selected channels mask */ adc->pcsel |= BIT(chan->channel); } @@ -1538,16 +1661,23 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) struct property *prop; const __be32 *cur; struct iio_chan_spec *channels; - int scan_index = 0, num_channels; - u32 val; + int scan_index = 0, num_channels, ret; + u32 val, smp = 0; num_channels = of_property_count_u32_elems(node, "st,adc-channels"); if (num_channels < 0 || - num_channels >= adc_info->max_channels) { + num_channels > adc_info->max_channels) { dev_err(&indio_dev->dev, "Bad st,adc-channels?\n"); return num_channels < 0 ? num_channels : -EINVAL; } + /* Optional sample time is provided either for each, or all channels */ + ret = of_property_count_u32_elems(node, "st,min-sample-time-nsecs"); + if (ret > 1 && ret != num_channels) { + dev_err(&indio_dev->dev, "Invalid st,min-sample-time-nsecs\n"); + return -EINVAL; + } + channels = devm_kcalloc(&indio_dev->dev, num_channels, sizeof(struct iio_chan_spec), GFP_KERNEL); if (!channels) @@ -1558,9 +1688,19 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) dev_err(&indio_dev->dev, "Invalid channel %d\n", val); return -EINVAL; } + + /* + * Using of_property_read_u32_index(), smp value will only be + * modified if valid u32 value can be decoded. This allows to + * get either no value, 1 shared value for all indexes, or one + * value per channel. + */ + of_property_read_u32_index(node, "st,min-sample-time-nsecs", + scan_index, &smp); + stm32_adc_chan_init_one(indio_dev, &channels[scan_index], &adc_info->channels[val], - scan_index); + scan_index, smp); scan_index++; } @@ -1634,7 +1774,7 @@ static int stm32_adc_probe(struct platform_device *pdev) indio_dev->dev.parent = &pdev->dev; indio_dev->dev.of_node = pdev->dev.of_node; indio_dev->info = &stm32_adc_iio_info; - indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED; platform_set_drvdata(pdev, adc); @@ -1755,6 +1895,7 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = { .clk_required = true, .start_conv = stm32f4_adc_start_conv, .stop_conv = stm32f4_adc_stop_conv, + .smp_cycles = stm32f4_adc_smp_cycles, }; static const struct stm32_adc_cfg stm32h7_adc_cfg = { @@ -1766,6 +1907,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .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[] = { |