struct ad7944_timing_spec { /* Normal mode max conversion time (t_{CONV}). */ unsignedint conv_ns; /* TURBO mode max conversion time (t_{CONV}). */ unsignedint turbo_conv_ns;
};
enum ad7944_spi_mode { /* datasheet calls this "4-wire mode" */
AD7944_SPI_MODE_DEFAULT, /* datasheet calls this "3-wire mode" (not related to SPI_3WIRE!) */
AD7944_SPI_MODE_SINGLE, /* datasheet calls this "chain mode" */
AD7944_SPI_MODE_CHAIN,
};
/* Then we can read the data during the acquisition phase */
xfers[2].rx_buf = &adc->sample.raw;
xfers[2].len = AD7944_SPI_BYTES(chan->scan_type);
xfers[2].bits_per_word = chan->scan_type.realbits;
/* CNV has to be high for full conversion time before reading data. */
xfers[0].delay.value = adc->timing_spec->conv_ns;
xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS;
/* *CSistiedtoCNVandweneedalowtohightransitiontostartthe *conversion,soplaceCNVlowfort_QUIETtoprepareforthis.
*/
xfers[0].delay.value = AD7944_T_QUIET_NS;
xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; /* CNV has to be high for a minimum time to trigger conversion. */
xfers[0].cs_change = 1;
xfers[0].cs_change_delay.value = AD7944_T_CNVH_NS;
xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
/* Then we can read the previous sample during the conversion phase */
xfers[1].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
xfers[1].len = AD7944_SPI_BYTES(chan->scan_type);
xfers[1].bits_per_word = chan->scan_type.realbits;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); if (!indio_dev) return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
chip_info = spi_get_device_match_data(spi); if (!chip_info) return dev_err_probe(dev, -EINVAL, "no chip info\n");
adc->timing_spec = chip_info->timing_spec;
adc->sample_freq_range[0] = 1; /* min */
adc->sample_freq_range[1] = 1; /* step */
adc->sample_freq_range[2] = chip_info->max_sample_rate_hz; /* max */
ret = device_property_match_property_string(dev, "adi,spi-mode",
ad7944_spi_modes,
ARRAY_SIZE(ad7944_spi_modes)); /* absence of adi,spi-mode property means default mode */ if (ret == -EINVAL)
adc->spi_mode = AD7944_SPI_MODE_DEFAULT; elseif (ret < 0) return dev_err_probe(dev, ret, "getting adi,spi-mode property failed\n"); else
adc->spi_mode = ret;
/* *Somechipsuseunusualwordsizes,sochecknowinsteadofwaiting *forthefirstxfer.
*/ if (!spi_is_bpw_supported(spi, chip_info->channels[0].scan_type.realbits)) return dev_err_probe(dev, -EINVAL, "SPI host does not support %d bits per word\n",
chip_info->channels[0].scan_type.realbits);
ret = devm_regulator_bulk_get_enable(dev,
ARRAY_SIZE(ad7944_power_supplies),
ad7944_power_supplies); if (ret) return dev_err_probe(dev, ret, "failed to get and enable supplies\n");
ret = devm_regulator_get_enable_read_voltage(dev, "ref"); if (ret < 0 && ret != -ENODEV) return dev_err_probe(dev, ret, "failed to get REF voltage\n");
ref_mv = ret == -ENODEV ? 0 : ret / 1000;
ret = devm_regulator_get_enable_optional(dev, "refin"); if (ret < 0 && ret != -ENODEV) return dev_err_probe(dev, ret, "failed to get REFIN voltage\n");
have_refin = ret != -ENODEV;
if (have_refin && ref_mv) return dev_err_probe(dev, -EINVAL, "cannot have both refin and ref supplies\n");
adc->ref_mv = ref_mv ?: AD7944_INTERNAL_REF_MV;
adc->cnv = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_LOW); if (IS_ERR(adc->cnv)) return dev_err_probe(dev, PTR_ERR(adc->cnv), "failed to get CNV GPIO\n");
if (!adc->cnv && adc->spi_mode == AD7944_SPI_MODE_DEFAULT) return dev_err_probe(&spi->dev, -EINVAL, "CNV GPIO is required\n"); if (adc->cnv && adc->spi_mode != AD7944_SPI_MODE_DEFAULT) return dev_err_probe(&spi->dev, -EINVAL, "CNV GPIO in single and chain mode is not currently supported\n");
adc->turbo = devm_gpiod_get_optional(dev, "turbo", GPIOD_OUT_LOW); if (IS_ERR(adc->turbo)) return dev_err_probe(dev, PTR_ERR(adc->turbo), "failed to get TURBO GPIO\n");
if (adc->turbo && adc->always_turbo) return dev_err_probe(dev, -EINVAL, "cannot have both turbo-gpios and adi,always-turbo\n");
if (adc->spi_mode == AD7944_SPI_MODE_CHAIN && adc->always_turbo) return dev_err_probe(dev, -EINVAL, "cannot have both chain mode and always turbo\n");
switch (adc->spi_mode) { case AD7944_SPI_MODE_DEFAULT:
ret = ad7944_4wire_mode_init_msg(dev, adc, &chip_info->channels[0]); if (ret) return ret;
break; case AD7944_SPI_MODE_SINGLE:
ret = ad7944_3wire_cs_mode_init_msg(dev, adc, &chip_info->channels[0]); if (ret) return ret;
break; case AD7944_SPI_MODE_CHAIN:
ret = device_property_read_u32(dev, "#daisy-chained-devices",
&n_chain_dev); if (ret) return dev_err_probe(dev, ret, "failed to get #daisy-chained-devices\n");
ret = ad7944_chain_mode_alloc(dev, chip_info->channels,
n_chain_dev, &chain_chan,
&adc->chain_mode_buf,
&chain_scan_masks); if (ret) return ret;
ret = ad7944_chain_mode_init_msg(dev, adc, &chain_chan[0],
n_chain_dev); if (ret) return ret;
adc->offload = devm_spi_offload_get(dev, spi, &ad7944_offload_config);
ret = PTR_ERR_OR_ZERO(adc->offload); if (ret && ret != -ENODEV) return dev_err_probe(dev, ret, "failed to get offload\n");
/* Fall back to low speed usage when no SPI offload available. */ if (ret == -ENODEV) { if (adc->spi_mode == AD7944_SPI_MODE_CHAIN) {
indio_dev->available_scan_masks = chain_scan_masks;
indio_dev->channels = chain_chan;
indio_dev->num_channels = n_chain_dev + 1;
} else {
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = ARRAY_SIZE(chip_info->channels);
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
ad7944_trigger_handler,
NULL); if (ret) return ret;
} else { struct dma_chan *rx_dma;
if (adc->spi_mode != AD7944_SPI_MODE_SINGLE) return dev_err_probe(dev, -EINVAL, "offload only supported in single mode\n");
adc->offload_trigger = devm_spi_offload_trigger_get(dev,
adc->offload, SPI_OFFLOAD_TRIGGER_PERIODIC); if (IS_ERR(adc->offload_trigger)) return dev_err_probe(dev, PTR_ERR(adc->offload_trigger), "failed to get offload trigger\n");
ret = ad7944_set_sample_freq(adc, 2 * MEGA); if (ret) return dev_err_probe(dev, ret, "failed to init sample rate\n");
rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev,
adc->offload); if (IS_ERR(rx_dma)) return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA\n");
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.