/* Decimation rate range for sinc3 filter */ staticconstint ad7768_sinc3_dec_rate_range[3] = {
32, 32, 163840,
};
/* * The AD7768-1 supports three primary filter types: * Sinc5, Sinc3, and Wideband. * However, the filter register values can also encode additional parameters * such as decimation rates and 60Hz rejection. This utility array separates * the filter type from these parameters.
*/ staticconstint ad7768_filter_regval_to_type[] = {
[AD7768_FILTER_REGVAL_SINC5] = AD7768_FILTER_SINC5,
[AD7768_FILTER_REGVAL_SINC5_X8] = AD7768_FILTER_SINC5,
[AD7768_FILTER_REGVAL_SINC5_X16] = AD7768_FILTER_SINC5,
[AD7768_FILTER_REGVAL_SINC3] = AD7768_FILTER_SINC3,
[AD7768_FILTER_REGVAL_WIDEBAND] = AD7768_FILTER_WIDEBAND,
[AD7768_FILTER_REGVAL_SINC3_REJ60] = AD7768_FILTER_SINC3_REJ60,
};
/* * The datasheet specifies a minimum SYNC_IN pulse width of 1.5 × Tmclk, * where Tmclk is the MCLK period. The supported MCLK frequencies range * from 0.6 MHz to 17 MHz, which corresponds to a minimum SYNC_IN pulse * width of approximately 2.5 µs in the worst-case scenario (0.6 MHz). * * Add a delay to ensure the pulse width is always sufficient to * trigger synchronization.
*/
gpiod_set_value_cansleep(st->gpio_sync_in, 1);
fsleep(3);
gpiod_set_value_cansleep(st->gpio_sync_in, 0);
return 0;
}
staticvoid ad7768_fill_samp_freq_tbl(struct ad7768_state *st)
{ unsignedint i, samp_freq_avail, freq_filtered; unsignedint len = 0;
freq_filtered = DIV_ROUND_CLOSEST(st->mclk_freq, st->oversampling_ratio); for (i = 0; i < ARRAY_SIZE(ad7768_mclk_div_rates); i++) {
samp_freq_avail = DIV_ROUND_CLOSEST(freq_filtered, ad7768_mclk_div_rates[i]); /* Sampling frequency cannot be lower than the minimum of 50 SPS */ if (samp_freq_avail < 50) continue;
mclk_div_value = AD7768_PWR_MCLK_DIV(mclk_div); /* * Set power mode based on mclk_div value. * ECO_MODE is only recommended for MCLK_DIV = 16.
*/
mclk_div_value |= mclk_div > AD7768_MCLK_DIV_16 ?
AD7768_PWR_PWRMODE(AD7768_FAST_MODE) :
AD7768_PWR_PWRMODE(AD7768_ECO_MODE);
ret = ad7768_set_mode(st, AD7768_ONE_SHOT); if (ret < 0) return ret;
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(1000)); if (!ret) return -ETIMEDOUT;
ret = regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &readval); if (ret) return ret;
/* * When the decimation rate is set to x8, the ADC data precision is * reduced from 24 bits to 16 bits. Since the AD7768_REG_ADC_DATA * register provides 24-bit data, the precision is reduced by * right-shifting the read value by 8 bits.
*/ if (st->oversampling_ratio == 8)
readval >>= 8;
/* * Any SPI configuration of the AD7768-1 can only be * performed in continuous conversion mode.
*/
ret = ad7768_set_mode(st, AD7768_CONTINUOUS); if (ret < 0) return ret;
/* * Maximum dec_rate is limited by the MCLK_DIV value and by the ODR. * The edge case is for MCLK_DIV = 2, ODR = 50 SPS. * max_dec_rate <= MCLK / (2 * 50)
*/
max_dec_rate = st->mclk_freq / 100;
dec_rate = clamp(dec_rate, 32, max_dec_rate); /* * Calculate the equivalent value to sinc3 decimation ratio * to be written on the SINC3_DEC_RATE register: * Value = (DEC_RATE / 32) - 1
*/
dec_rate = DIV_ROUND_UP(dec_rate, 32) - 1;
/* * The SINC3_DEC_RATE value is a 13-bit value split across two * registers: MSB [12:8] and LSB [7:0]. Prepare the 13-bit value using * FIELD_PREP() and store it with the right endianness in dec_rate_reg.
*/
regval = FIELD_PREP(GENMASK(12, 0), dec_rate);
put_unaligned_be16(regval, dec_rate_reg);
ret = regmap_bulk_write(st->regmap, AD7768_REG_SINC3_DEC_RATE_MSB,
dec_rate_reg, 2); if (ret) return ret;
switch (filter_type) { case AD7768_FILTER_SINC3:
dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3); break; case AD7768_FILTER_SINC3_REJ60:
dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3) |
AD7768_DIG_FIL_EN_60HZ_REJ; break; case AD7768_FILTER_WIDEBAND: /* Skip decimations 8 and 16, not supported by the wideband filter */
dec_rate_idx = find_closest(dec_rate, &ad7768_dec_rate_values[2],
ARRAY_SIZE(ad7768_dec_rate_values) - 2);
dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_WIDEBAND) |
AD7768_DIG_FIL_DEC_RATE(dec_rate_idx); /* Correct the index offset */
dec_rate_idx += 2; break; case AD7768_FILTER_SINC5:
dec_rate_idx = find_closest(dec_rate, ad7768_dec_rate_values,
ARRAY_SIZE(ad7768_dec_rate_values));
/* * Decimations 8 (idx 0) and 16 (idx 1) are set in the * FILTER[6:4] field. The other decimations are set in the * DEC_RATE[2:0] field, and the idx needs to be offsetted by two.
*/ if (dec_rate_idx == 0)
dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X8); elseif (dec_rate_idx == 1)
dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X16); else
dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5) |
AD7768_DIG_FIL_DEC_RATE(dec_rate_idx - 2); break;
}
ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, dig_filter_regval); if (ret) return ret;
st->filter_type = filter_type; /* * The decimation for SINC3 filters are configured in different * registers.
*/ if (filter_type == AD7768_FILTER_SINC3 ||
filter_type == AD7768_FILTER_SINC3_REJ60) {
ret = ad7768_set_sinc3_dec_rate(st, dec_rate); if (ret) return ret;
} else {
st->oversampling_ratio = ad7768_dec_rate_values[dec_rate_idx];
}
ad7768_fill_samp_freq_tbl(st);
/* A sync-in pulse is required after every configuration change */ return ad7768_send_sync_pulse(st);
}
if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &val); if (ret) goto err_release;
/* * If the GPIO is configured as an output, read the current value from * AD7768_REG_GPIO_WRITE. Otherwise, read the input value from * AD7768_REG_GPIO_READ.
*/ if (val & BIT(offset))
ret = regmap_read(st->regmap, AD7768_REG_GPIO_WRITE, &val); else
ret = regmap_read(st->regmap, AD7768_REG_GPIO_READ, &val); if (ret) goto err_release;
ret = !!(val & BIT(offset));
err_release:
iio_device_release_direct(indio_dev);
mclk_div = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio); /* Find the closest match for the desired sampling frequency */
idx = find_closest_descending(mclk_div, ad7768_mclk_div_rates,
ARRAY_SIZE(ad7768_mclk_div_rates)); /* Set both the mclk_div and pwrmode */
ret = ad7768_set_mclk_div(st, idx); if (ret) return ret;
ret = regmap_read(st->regmap, AD7768_REG_DIGITAL_FILTER, &mode); if (ret) return ret;
mask = AD7768_DIG_FIL_EN_60HZ_REJ | AD7768_DIG_FIL_FIL_MSK; /* From the register value, get the corresponding filter type */ return ad7768_filter_regval_to_type[FIELD_GET(mask, mode)];
}
staticint ad7768_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, constint **vals, int *type, int *length, long info)
{ struct ad7768_state *st = iio_priv(indio_dev); unsignedint shift;
switch (info) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: /* * Sinc3 filter allows a wider range of OSR values, so show * the available values in range format.
*/ if (st->filter_type == AD7768_FILTER_SINC3 ||
st->filter_type == AD7768_FILTER_SINC3_REJ60) {
*vals = (int *)ad7768_sinc3_dec_rate_range;
*type = IIO_VAL_INT; return IIO_AVAIL_RANGE;
}
/* * TODO: Support the other cases when we have a trigger subsystem * to reliably handle other types of devices as trigger sources. * * For now, return an error message. For self triggering, omit the * trigger-sources property.
*/ return dev_err_probe(dev, -EOPNOTSUPP, "Invalid synchronization trigger source\n");
}
/* * The AD7768-1 allows two primary methods for driving the SYNC_IN pin * to synchronize one or more devices: * 1. Using an external GPIO. * 2. Using a SPI command, where the SYNC_OUT pin generates a * synchronization pulse that drives the SYNC_IN pin.
*/ if (fwnode_property_present(fwnode, "trigger-sources")) return ad7768_trigger_sources_sync_setup(dev, fwnode, st);
/* * In the absence of trigger-sources property, enable self * synchronization over SPI (SYNC_OUT).
*/
st->en_spi_sync = true;
st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
GPIOD_OUT_HIGH); if (IS_ERR(st->gpio_reset)) return PTR_ERR(st->gpio_reset);
if (st->gpio_reset) {
fsleep(10);
gpiod_set_value_cansleep(st->gpio_reset, 0);
fsleep(200);
} else { /* * Two writes to the SPI_RESET[1:0] bits are required to initiate * a software reset. The bits must first be set to 11, and then * to 10. When the sequence is detected, the reset occurs. * See the datasheet, page 70.
*/
ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x3); if (ret) return ret;
ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x2); if (ret) return ret;
}
/* For backwards compatibility, try the adi,sync-in-gpios property */
st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in",
GPIOD_OUT_LOW); if (IS_ERR(st->gpio_sync_in)) return PTR_ERR(st->gpio_sync_in);
/* * If the synchronization is not defined by adi,sync-in-gpios, try the * trigger-sources.
*/ if (!st->gpio_sync_in) {
ret = ad7768_trigger_sources_get_sync(&st->spi->dev, st); if (ret) return ret;
}
/* Only create a Chip GPIO if flagged for it */ if (device_property_read_bool(&st->spi->dev, "gpio-controller")) {
ret = ad7768_gpio_init(indio_dev); if (ret) return ret;
}
/* * Set Default Digital Filter configuration: * SINC5 filter with x32 Decimation rate
*/
ret = ad7768_configure_dig_fil(indio_dev, AD7768_FILTER_SINC5, 32); if (ret) return ret;
/* Set the default sampling frequency to 32000 kSPS */ return ad7768_set_freq(st, 32000);
}
/* * Write a 1 to the LSB of the INTERFACE_FORMAT register to enter * continuous read mode. Subsequent data reads do not require an * initial 8-bit write to query the ADC_DATA register.
*/ return regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01);
}
/* * To exit continuous read mode, perform a single read of the ADC_DATA * reg (0x2C), which allows further configuration of the device.
*/ return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused);
}
if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
/* To enable, set the last selected output */
regval = AD7768_REG_ANALOG2_VCM(st->vcm_output_sel + 1);
ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
AD7768_REG_ANALOG2_VCM_MSK, regval);
iio_device_release_direct(indio_dev);
/* Disable the regulator before registering it */
ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
AD7768_REG_ANALOG2_VCM_MSK, AD7768_VCM_OFF); if (ret) return ret;
st->vcm_rdev = devm_regulator_register(dev, &vcm_desc, &config); if (IS_ERR(st->vcm_rdev)) return dev_err_probe(dev, PTR_ERR(st->vcm_rdev), "failed to register VCM regulator\n");
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM;
st = iio_priv(indio_dev); /* * Datasheet recommends SDI line to be kept high when data is not being * clocked out of the controller and the spi clock is free running, * to prevent accidental reset. * Since many controllers do not support the SPI_MOSI_IDLE_HIGH flag * yet, only request the MOSI idle state to enable if the controller * supports it.
*/ if (spi->controller->mode_bits & SPI_MOSI_IDLE_HIGH) {
spi->mode |= SPI_MOSI_IDLE_HIGH;
ret = spi_setup(spi); if (ret < 0) return ret;
}
st->spi = spi;
st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config); if (IS_ERR(st->regmap)) return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), "Failed to initialize regmap");
st->regmap24 = devm_regmap_init_spi(spi, &ad7768_regmap24_config); if (IS_ERR(st->regmap24)) return dev_err_probe(&spi->dev, PTR_ERR(st->regmap24), "Failed to initialize regmap24");
st->vref = devm_regulator_get(&spi->dev, "vref"); if (IS_ERR(st->vref)) return PTR_ERR(st->vref);
ret = regulator_enable(st->vref); if (ret) {
dev_err(&spi->dev, "Failed to enable specified vref supply\n"); return ret;
}
ret = devm_add_action_or_reset(&spi->dev, ad7768_regulator_disable, st); if (ret) return ret;
st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); if (IS_ERR(st->mclk)) return PTR_ERR(st->mclk);
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.