// SPDX-License-Identifier: GPL-2.0 /* * This file is part of STM32 ADC driver * * Copyright (C) 2016, STMicroelectronics - All Rights Reserved * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
*/
/** * struct stm32_adc_info - stm32 ADC, per instance config data * @max_channels: Number of channels * @resolutions: available resolutions * @oversampling: available oversampling ratios * @num_res: number of available resolutions * @num_ovs: number of available oversampling ratios
*/ struct stm32_adc_info { int max_channels; constunsignedint *resolutions; constunsignedint *oversampling; constunsignedint num_res; constunsignedint num_ovs;
};
for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { if (adc->int_ch[i] == STM32_ADC_INT_CH_NONE) continue;
switch (i) { case STM32_ADC_INT_CH_VDDCORE:
stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcore.reg,
adc->cfg->regs->or_vddcore.mask); break; case STM32_ADC_INT_CH_VDDCPU:
stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddcpu.reg,
adc->cfg->regs->or_vddcpu.mask); break; case STM32_ADC_INT_CH_VDDQ_DDR:
stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddq_ddr.reg,
adc->cfg->regs->or_vddq_ddr.mask); break; case STM32_ADC_INT_CH_VREFINT:
stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vref.reg,
adc->cfg->regs->ccr_vref.mask); break; case STM32_ADC_INT_CH_VBAT:
stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vbat.reg,
adc->cfg->regs->ccr_vbat.mask); break;
}
}
}
/** * stm32f4_adc_start_conv() - Start conversions for regular channels. * @indio_dev: IIO device instance * @dma: use dma to transfer conversion result * * Start conversions for regular channels. * Also take care of normal or DMA mode. Circular DMA may be used for regular * conversions, in IIO buffer modes. Otherwise, use ADC interrupt with direct * DR read instead (e.g. read_raw, or triggered buffer mode without DMA).
*/ staticvoid stm32f4_adc_start_conv(struct iio_dev *indio_dev, bool dma)
{ struct stm32_adc *adc = iio_priv(indio_dev);
/* * Only the oversampling ratios corresponding to 2^ovs_idx are exposed in sysfs. * Oversampling ratios [2,3,...,1024] are mapped on OVSR register values [1,2,...,1023]. * OVSR = 2^ovs_idx - 1 * These ratio increase the resolution by ovs_idx bits. Apply a right shift to keep initial * resolution given by "assigned-resolution-bits" property. * OVSS = ovs_idx
*/
ovsr_bits = GENMASK(ovs_idx - 1, 0);
bits = STM32H7_ROVSE | STM32H7_OVSS(ovs_idx) | STM32H7_OVSR(ovsr_bits);
/* * The oversampling ratios [2,4,8,..,256] are mapped on OVSR register values [0,1,...,7]. * OVSR = ovs_idx - 1 * These ratio increase the resolution by ovs_idx bits. Apply a right shift to keep initial * resolution given by "assigned-resolution-bits" property. * OVSS = ovs_idx
*/
bits = STM32H7_ROVSE | STM32MP13_OVSS(ovs_idx); if (ovs_idx - 1)
bits |= STM32MP13_OVSR(ovs_idx - 1);
/* 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);
if (adc->cfg->has_boostmode &&
adc->common->rate > STM32H7_BOOST_CLKRATE)
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Wait for startup time */ 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;
}
staticvoid stm32h7_adc_enter_pwr_down(struct stm32_adc *adc)
{ if (adc->cfg->has_boostmode)
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Poll for ADRDY to be set (after adc startup time) */
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_ISR, val,
val & STM32H7_ADRDY,
100, STM32_ADC_TIMEOUT_US); if (ret) {
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADDIS);
dev_err(&indio_dev->dev, "Failed to enable ADC\n");
} else { /* Clear ADRDY by writing one */
stm32_adc_set_bits(adc, STM32H7_ADC_ISR, STM32H7_ADRDY);
}
if (!(stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_ADEN)) return;
/* Disable ADC and wait until it's effectively disabled */
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADDIS);
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
!(val & STM32H7_ADEN), 100,
STM32_ADC_TIMEOUT_US); if (ret)
dev_warn(&indio_dev->dev, "Failed to disable\n");
}
/** * stm32h7_adc_read_selfcalib() - read calibration shadow regs, save result * @indio_dev: IIO device instance * Note: Must be called once ADC is enabled, so LINCALRDYW[1..6] are writable
*/ staticint stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev)
{ struct stm32_adc *adc = iio_priv(indio_dev); int i, ret;
u32 lincalrdyw_mask, val;
/* Read linearity calibration */
lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { /* Clear STM32H7_LINCALRDYW[6..1]: transfer calib to CALFACT2 */
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, lincalrdyw_mask);
/* Poll: wait calib data to be ready in CALFACT2 register */
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
!(val & lincalrdyw_mask),
100, STM32_ADC_TIMEOUT_US); if (ret) {
dev_err(&indio_dev->dev, "Failed to read calfact\n"); return ret;
}
/** * stm32h7_adc_restore_selfcalib() - Restore saved self-calibration result * @indio_dev: IIO device instance * Note: ADC must be enabled, with no on-going conversions.
*/ staticint stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
{ struct stm32_adc *adc = iio_priv(indio_dev); int i, ret;
u32 lincalrdyw_mask, val;
lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { /* * Write saved calibration data to shadow registers: * Write CALFACT2, and set LINCALRDYW[6..1] bit to trigger * data write. Then poll to wait for complete transfer.
*/
val = adc->cal.lincalfact[i] << STM32H7_LINCALFACT_SHIFT;
stm32_adc_writel(adc, STM32H7_ADC_CALFACT2, val);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, lincalrdyw_mask);
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
val & lincalrdyw_mask,
100, STM32_ADC_TIMEOUT_US); if (ret) {
dev_err(&indio_dev->dev, "Failed to write calfact\n"); return ret;
}
/* * Read back calibration data, has two effects: * - It ensures bits LINCALRDYW[6..1] are kept cleared * for next time calibration needs to be restored. * - BTW, bit clear triggers a read, then check data has been * correctly written.
*/
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, lincalrdyw_mask);
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
!(val & lincalrdyw_mask),
100, STM32_ADC_TIMEOUT_US); if (ret) {
dev_err(&indio_dev->dev, "Failed to read calfact\n"); return ret;
}
val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2); if (val != adc->cal.lincalfact[i] << STM32H7_LINCALFACT_SHIFT) {
dev_err(&indio_dev->dev, "calfact not consistent\n"); return -EIO;
}
lincalrdyw_mask >>= 1;
}
return 0;
}
/* * Fixed timeout value for ADC calibration. * worst cases: * - low clock frequency * - maximum prescalers * Calibration requires: * - 131,072 ADC clock cycle for the linear calibration * - 20 ADC clock cycle for the offset calibration * * Set to 100ms for now
*/ #define STM32H7_ADC_CALIB_TIMEOUT_US 100000
/** * stm32h7_adc_selfcalib() - Procedure to calibrate ADC * @indio_dev: IIO device instance * @do_lincal: linear calibration request flag * Note: Must be called once ADC is out of power down. * * Run offset calibration unconditionally. * Run linear calibration if requested & supported.
*/ staticint stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal)
{ struct stm32_adc *adc = iio_priv(indio_dev); int ret;
u32 msk = STM32H7_ADCALDIF;
u32 val;
if (adc->cfg->has_linearcal && do_lincal)
msk |= STM32H7_ADCALLIN; /* ADC must be disabled for calibration */
stm32h7_adc_disable(indio_dev);
/* * Select calibration mode: * - Offset calibration for single ended inputs * - No linearity calibration (do it later, before reading it)
*/
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, msk);
/* Start calibration, then wait for completion */
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
!(val & STM32H7_ADCAL), 100,
STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) {
dev_err(&indio_dev->dev, "calibration (single-ended) error %d\n", ret); goto out;
}
/* * Select calibration mode, then start calibration: * - Offset calibration for differential input * - Linearity calibration (needs to be done only once for single/diff) * will run simultaneously with offset calibration.
*/
stm32_adc_set_bits(adc, STM32H7_ADC_CR, msk);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
!(val & STM32H7_ADCAL), 100,
STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) {
dev_err(&indio_dev->dev, "calibration (diff%s) error %d\n",
(msk & STM32H7_ADCALLIN) ? "+linear" : "", ret); goto out;
}
/** * stm32h7_adc_check_selfcalib() - Check linear calibration status * @indio_dev: IIO device instance * * Used to check if linear calibration has been done. * Return true if linear calibration factors are already saved in private data * or if a linear calibration has been done at boot stage.
*/ staticint stm32h7_adc_check_selfcalib(struct iio_dev *indio_dev)
{ struct stm32_adc *adc = iio_priv(indio_dev);
u32 val;
if (adc->cal.lincal_saved) returntrue;
/* * Check if linear calibration factors are available in ADC registers, * by checking that all LINCALRDYWx bits are set.
*/
val = stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_LINCALRDYW_MASK; if (val == STM32H7_LINCALRDYW_MASK) returntrue;
returnfalse;
}
/** * stm32h7_adc_prepare() - Leave power down mode to enable ADC. * @indio_dev: IIO device instance * Leave power down mode. * Configure channels as single ended or differential before enabling ADC. * Enable ADC. * Restore calibration data. * Pre-select channels that may be used in PCSEL (required by input MUX / IO): * - Only one input is selected for single ended (e.g. 'vinp') * - Two inputs are selected for differential channels (e.g. 'vinp' & 'vinn')
*/ staticint stm32h7_adc_prepare(struct iio_dev *indio_dev)
{ struct stm32_adc *adc = iio_priv(indio_dev); int lincal_done = false; int ret;
ret = stm32h7_adc_exit_pwr_down(indio_dev); if (ret) return ret;
if (adc->cfg->has_linearcal)
lincal_done = stm32h7_adc_check_selfcalib(indio_dev);
/* Always run offset calibration. Run linear calibration only once */
ret = stm32h7_adc_selfcalib(indio_dev, !lincal_done); if (ret < 0) goto pwr_dwn;
ret = stm32h7_adc_enable(indio_dev); if (ret) goto ch_disable;
if (adc->cfg->has_linearcal) { if (!adc->cal.lincal_saved)
ret = stm32h7_adc_read_selfcalib(indio_dev); else
ret = stm32h7_adc_restore_selfcalib(indio_dev);
if (ret) goto disable;
}
if (adc->cfg->has_presel)
stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
/* lookup triggers registered by stm32 timer trigger driver */ for (i = 0; adc->cfg->trigs[i].name; i++) { /** * Checking both stm32 timer trigger type and trig name * should be safe against arbitrary trigger names.
*/ 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;
}
}
return -EINVAL;
}
/** * stm32_adc_set_trig() - Set a regular trigger * @indio_dev: IIO device * @trig: IIO trigger * * Set trigger source/polarity (e.g. SW, or HW with polarity) : * - if HW trigger disabled (e.g. trig == NULL, conversion launched by sw) * - if HW trigger enabled, set source & polarity
*/ staticint stm32_adc_set_trig(struct iio_dev *indio_dev, struct iio_trigger *trig)
{ struct stm32_adc *adc = iio_priv(indio_dev);
u32 val, extsel = 0, exten = STM32_EXTEN_SWTRIG; unsignedlong flags; int ret;
if (trig) {
ret = stm32_adc_get_trig_extsel(indio_dev, trig); if (ret < 0) return ret;
/* set trigger source and polarity (default to rising edge) */
extsel = ret;
exten = adc->trigger_polarity + STM32_EXTEN_HWTRIG_RISING_EDGE;
}
spin_lock_irqsave(&adc->lock, flags);
val = stm32_adc_readl(adc, adc->cfg->regs->exten.reg);
val &= ~(adc->cfg->regs->exten.mask | adc->cfg->regs->extsel.mask);
val |= exten << adc->cfg->regs->exten.shift;
val |= extsel << adc->cfg->regs->extsel.shift;
stm32_adc_writel(adc, adc->cfg->regs->exten.reg, val);
spin_unlock_irqrestore(&adc->lock, flags);
/** * stm32_adc_single_conv() - Performs a single conversion * @indio_dev: IIO device * @chan: IIO channel * @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.
*/ staticint stm32_adc_single_conv(struct iio_dev *indio_dev, conststruct iio_chan_spec *chan, int *res)
{ struct stm32_adc *adc = iio_priv(indio_dev); struct device *dev = indio_dev->dev.parent; conststruct stm32_adc_regspec *regs = adc->cfg->regs; long time_left;
u32 val; int ret;
reinit_completion(&adc->completion);
adc->bufi = 0;
ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret;
/* Program chan number in regular sequence (SQ1) */
val = stm32_adc_readl(adc, regs->sqr[1].reg);
val &= ~regs->sqr[1].mask;
val |= chan->channel << regs->sqr[1].shift;
stm32_adc_writel(adc, regs->sqr[1].reg, val);
/* Set regular sequence len (0 for 1 conversion) */
stm32_adc_clr_bits(adc, regs->sqr[0].reg, regs->sqr[0].mask);
/* Trigger detection disabled (conversion can be launched in SW) */
stm32_adc_clr_bits(adc, regs->exten.reg, regs->exten.mask);
stm32_adc_conv_irq_enable(adc);
adc->cfg->start_conv(indio_dev, false);
time_left = wait_for_completion_interruptible_timeout(
&adc->completion, STM32_ADC_TIMEOUT); if (time_left == 0) {
ret = -ETIMEDOUT;
} elseif (time_left < 0) {
ret = time_left;
} else {
*res = adc->buffer[0];
ret = IIO_VAL_INT;
}
staticint stm32_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct stm32_adc *adc = iio_priv(indio_dev); int ret;
switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: if (!iio_device_claim_direct(indio_dev)) return -EBUSY; if (chan->type == IIO_VOLTAGE)
ret = stm32_adc_single_conv(indio_dev, chan, val); else
ret = -EINVAL;
/* Check ovr status right now, as ovr mask should be already disabled */ if (status & regs->isr_ovr.mask) { /* * Clear ovr bit to avoid subsequent calls to IRQ handler. * This requires to stop ADC first. OVR bit state in ISR, * is propaged to CSR register by hardware.
*/
adc->cfg->stop_conv(indio_dev);
stm32_adc_irq_clear(indio_dev, regs->isr_ovr.mask);
dev_err(&indio_dev->dev, "Overrun, stopping: restart needed\n"); return IRQ_HANDLED;
}
if (status & regs->isr_ovr.mask) { /* * Overrun occurred on regular conversions: data for wrong * channel may be read. Unconditionally disable interrupts * to stop processing data and print error message. * Restarting the capture can be done by disabling, then * re-enabling it (e.g. write 0, then 1 to buffer/enable).
*/
stm32_adc_ovr_irq_disable(adc);
stm32_adc_conv_irq_disable(adc); return IRQ_WAKE_THREAD;
}
if (status & regs->isr_eoc.mask) { /* Reading DR also clears EOC status flag */
adc->buffer[adc->bufi] = stm32_adc_readw(adc, regs->dr); if (iio_buffer_enabled(indio_dev)) {
adc->bufi++; if (adc->bufi >= adc->num_conv) {
stm32_adc_conv_irq_disable(adc);
iio_trigger_poll(indio_dev->trig);
}
} else {
complete(&adc->completion);
} return IRQ_HANDLED;
}
return IRQ_NONE;
}
/** * stm32_adc_validate_trigger() - validate trigger for stm32 adc * @indio_dev: IIO device * @trig: new trigger * * Returns: 0 if trig matches one of the triggers registered by stm32 adc * driver, -EINVAL otherwise.
*/ staticint stm32_adc_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig)
{ return stm32_adc_get_trig_extsel(indio_dev, trig) < 0 ? -EINVAL : 0;
}
/* * dma cyclic transfers are used, buffer is split into two periods. * There should be : * - always one buffer (period) dma is working on * - one buffer (period) driver can push data.
*/
watermark = min(watermark, val * (unsigned)(sizeof(u16)));
adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv);
status = dmaengine_tx_status(adc->dma_chan,
adc->dma_chan->cookie,
&state); if (status == DMA_IN_PROGRESS) { /* Residue is size in bytes from end of buffer */ unsignedint i = adc->rx_buf_sz - state.residue; unsignedint size;
/* Return available bytes */ if (i >= adc->bufi)
size = i - adc->bufi; else
size = adc->rx_buf_sz + i - adc->bufi;
/* * In DMA mode the trigger services of IIO are not used * (e.g. no call to iio_trigger_poll). * Calling irq handler associated to the hardware trigger is not * relevant as the conversions have already been done. Data * transfers are performed directly in DMA callback instead. * This implementation avoids to call trigger irq handler that * may sleep, in an atomic context (DMA irq handler context).
*/
dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi);
while (residue >= indio_dev->scan_bytes) {
u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi];
if (device_property_read_u32(dev, "assigned-resolution-bits", &res))
res = adc->cfg->adc_info->resolutions[0];
for (i = 0; i < adc->cfg->adc_info->num_res; i++) if (res == adc->cfg->adc_info->resolutions[i]) break; if (i >= adc->cfg->adc_info->num_res) {
dev_err(&indio_dev->dev, "Bad resolution: %u bits\n", res); return -EINVAL;
}
staticvoid stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
{ conststruct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel];
u32 period_ns, shift = smpr->shift, mask = smpr->mask; unsignedint i, smp, r = smpr->reg;
/* * For internal channels, ensure that the sampling time cannot * be lower than the one specified in the datasheet
*/ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) if (channel == adc->int_ch[i] && adc->int_ch[i] != STM32_ADC_INT_CH_NONE)
smp_ns = max(smp_ns, adc->cfg->ts_int_ch[i]);
/* 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;
/* * each st,adc-diff-channels is a group of 2 u32 so we divide @ret * to get the *real* number of channels.
*/
ret = device_property_count_u32(dev, "st,adc-diff-channels"); if (ret > 0) {
ret /= (int)(sizeof(struct stm32_adc_diff_channel) / sizeof(u32)); if (ret > adc_info->max_channels) {
dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n"); return -EINVAL;
} elseif (ret > 0) {
adc->num_diff = ret;
num_channels += ret;
}
}
/* Optional sample time is provided either for each, or all channels */
adc->nsmps = device_property_count_u32(dev, "st,min-sample-time-nsecs"); if (adc->nsmps > 1 && adc->nsmps != num_channels) {
dev_err(&indio_dev->dev, "Invalid st,min-sample-time-nsecs\n"); return -EINVAL;
}
if (num_diff) {
ret = device_property_read_u32_array(dev, "st,adc-diff-channels",
(u32 *)diff, size); if (ret) {
dev_err(&indio_dev->dev, "Failed to get diff channels %d\n", ret); return ret;
}
for (i = 0; i < num_diff; i++) { if (diff[i].vinp >= adc_info->max_channels ||
diff[i].vinn >= adc_info->max_channels) {
dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
diff[i].vinp, diff[i].vinn); return -EINVAL;
}
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
diff[i].vinp, diff[i].vinn,
scan_index, true);
scan_index++;
}
} if (num_se > 0) {
ret = device_property_read_u32_array(dev, "st,adc-channels", chans, num_se); if (ret) {
dev_err(&indio_dev->dev, "Failed to get st,adc-channels %d\n", ret); return ret;
}
for (c = 0; c < num_se; c++) { if (chans[c] >= adc_info->max_channels) {
dev_err(&indio_dev->dev, "Invalid channel %d\n",
chans[c]); return -EINVAL;
}
/* Channel can't be configured both as single-ended & diff */ for (i = 0; i < num_diff; i++) { if (chans[c] == diff[i].vinp) {
dev_err(&indio_dev->dev, "channel %d misconfigured\n",
chans[c]); return -EINVAL;
}
}
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
chans[c], 0, scan_index, false);
scan_index++;
}
}
if (adc->nsmps > 0) {
ret = device_property_read_u32_array(dev, "st,min-sample-time-nsecs",
smps, adc->nsmps); if (ret) return ret;
}
for (i = 0; i < scan_index; i++) { /* * This check is used with the above logic so that 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. The point is to have the same * behavior as 'of_property_read_u32_index()'.
*/ if (i < adc->nsmps)
smp = smps[i];
/* Prepare sampling time settings */
stm32_adc_smpr_init(adc, channels[i].channel, smp);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.