return 0;
}
+static int stm32_dfsdm_generic_channel_parse_of(struct stm32_dfsdm *dfsdm,
+ struct iio_dev *indio_dev,
+ struct iio_chan_spec *ch,
+ struct fwnode_handle *node)
+{
+ struct stm32_dfsdm_channel *df_ch;
+ const char *of_str;
+ int ret, val;
+
+ ret = fwnode_property_read_u32(node, "reg", &ch->channel);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev, "Missing channel index %d\n", ret);
+ return ret;
+ }
+
+ if (ch->channel >= dfsdm->num_chs) {
+ dev_err(&indio_dev->dev, " Error bad channel number %d (max = %d)\n",
+ ch->channel, dfsdm->num_chs);
+ return -EINVAL;
+ }
+
+ ret = fwnode_property_read_string(node, "label", &ch->datasheet_name);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev,
+ " Error parsing 'label' for idx %d\n", ch->channel);
+ return ret;
+ }
+
+ df_ch = &dfsdm->ch_list[ch->channel];
+ df_ch->id = ch->channel;
+
+ ret = fwnode_property_read_string(node, "st,adc-channel-type", &of_str);
+ if (!ret) {
+ val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type);
+ if (val < 0)
+ return val;
+ } else {
+ val = 0;
+ }
+ df_ch->type = val;
+
+ ret = fwnode_property_read_string(node, "st,adc-channel-clk-src", &of_str);
+ if (!ret) {
+ val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src);
+ if (val < 0)
+ return val;
+ } else {
+ val = 0;
+ }
+ df_ch->src = val;
+
+ ret = fwnode_property_read_u32(node, "st,adc-alt-channel", &df_ch->alt_si);
+ if (ret != -EINVAL)
+ df_ch->alt_si = 0;
+
+ return 0;
+}
+
static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev,
uintptr_t priv,
const struct iio_chan_spec *chan,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
- ret = iio_hw_consumer_enable(adc->hwc);
+ if (adc->hwc)
+ ret = iio_hw_consumer_enable(adc->hwc);
if (ret < 0) {
dev_err(&indio_dev->dev,
"%s: IIO enable failed (channel %d)\n",
return ret;
}
ret = stm32_dfsdm_single_conv(indio_dev, chan, val);
- iio_hw_consumer_disable(adc->hwc);
+ if (adc->hwc)
+ iio_hw_consumer_disable(adc->hwc);
if (ret < 0) {
dev_err(&indio_dev->dev,
"%s: Conversion failed (channel %d)\n",
return 0;
}
-static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
- struct iio_chan_spec *ch)
+static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, struct iio_chan_spec *ch,
+ struct fwnode_handle *child)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
int ret;
- ret = stm32_dfsdm_channel_parse_of(adc->dfsdm, indio_dev, ch);
+ if (child)
+ ret = stm32_dfsdm_generic_channel_parse_of(adc->dfsdm, indio_dev, ch, child);
+ else /* Legacy binding */
+ ret = stm32_dfsdm_channel_parse_of(adc->dfsdm, indio_dev, ch);
if (ret < 0)
- return ret;
+ return dev_err_probe(&indio_dev->dev, ret, "Failed to parse channel\n");
ch->type = IIO_VOLTAGE;
ch->indexed = 1;
if (adc->dev_data->type == DFSDM_AUDIO) {
ch->ext_info = dfsdm_adc_audio_ext_info;
+ ch->scan_index = 0;
} else {
ch->scan_type.shift = 8;
}
&adc->dfsdm->ch_list[ch->channel]);
}
+static int stm32_dfsdm_chan_init(struct iio_dev *indio_dev, struct iio_chan_spec *channels)
+{
+ int num_ch = indio_dev->num_channels;
+ int chan_idx = 0;
+ int ret;
+
+ for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
+ channels[chan_idx].scan_index = chan_idx;
+ ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &channels[chan_idx], NULL);
+ if (ret < 0)
+ return dev_err_probe(&indio_dev->dev, ret, "Channels init failed\n");
+ }
+
+ return 0;
+}
+
+static int stm32_dfsdm_generic_chan_init(struct iio_dev *indio_dev, struct iio_chan_spec *channels)
+{
+ int chan_idx = 0, ret;
+
+ device_for_each_child_node_scoped(&indio_dev->dev, child) {
+ /* Skip DAI node in DFSDM audio nodes */
+ if (fwnode_property_present(child, "compatible"))
+ continue;
+
+ channels[chan_idx].scan_index = chan_idx;
+ ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &channels[chan_idx], child);
+ if (ret < 0)
+ return dev_err_probe(&indio_dev->dev, ret, "Channels init failed\n");
+
+ chan_idx++;
+ }
+
+ return chan_idx;
+}
+
static int stm32_dfsdm_audio_init(struct device *dev, struct iio_dev *indio_dev)
{
struct iio_chan_spec *ch;
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
struct stm32_dfsdm_channel *d_ch;
- int ret;
+ bool legacy = false;
+ int num_ch, ret;
+
+ /* If st,adc-channels is defined legacy binding is used. Else assume generic binding. */
+ num_ch = of_property_count_u32_elems(indio_dev->dev.of_node, "st,adc-channels");
+ if (num_ch == 1)
+ legacy = true;
ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL);
if (!ch)
return -ENOMEM;
- ch->scan_index = 0;
+ indio_dev->num_channels = 1;
+ indio_dev->channels = ch;
+
+ if (legacy)
+ ret = stm32_dfsdm_chan_init(indio_dev, ch);
+ else
+ ret = stm32_dfsdm_generic_chan_init(indio_dev, ch);
- ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch);
if (ret < 0) {
dev_err(&indio_dev->dev, "Channels init failed\n");
return ret;
if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
adc->spi_freq = adc->dfsdm->spi_master_freq;
- indio_dev->num_channels = 1;
- indio_dev->channels = ch;
-
return stm32_dfsdm_dma_request(dev, indio_dev);
}
{
struct iio_chan_spec *ch;
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
- int num_ch;
- int ret, chan_idx;
+ int num_ch, ret;
+ bool legacy = false;
adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING;
ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp);
if (ret < 0)
return ret;
- num_ch = of_property_count_u32_elems(indio_dev->dev.of_node,
- "st,adc-channels");
- if (num_ch < 0 || num_ch > adc->dfsdm->num_chs) {
- dev_err(&indio_dev->dev, "Bad st,adc-channels\n");
- return num_ch < 0 ? num_ch : -EINVAL;
- }
+ num_ch = device_get_child_node_count(&indio_dev->dev);
+ if (!num_ch) {
+ /* No channels nodes found. Assume legacy binding */
+ num_ch = of_property_count_u32_elems(indio_dev->dev.of_node, "st,adc-channels");
+ if (num_ch < 0) {
+ dev_err(&indio_dev->dev, "Bad st,adc-channels\n");
+ return num_ch;
+ }
- /* Bind to SD modulator IIO device */
- adc->hwc = devm_iio_hw_consumer_alloc(&indio_dev->dev);
- if (IS_ERR(adc->hwc))
- return -EPROBE_DEFER;
+ legacy = true;
+ }
- ch = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*ch),
- GFP_KERNEL);
- if (!ch)
- return -ENOMEM;
+ if (num_ch > adc->dfsdm->num_chs) {
+ dev_err(&indio_dev->dev, "Number of channel [%d] exceeds [%d]\n",
+ num_ch, adc->dfsdm->num_chs);
+ return -EINVAL;
+ }
+ indio_dev->num_channels = num_ch;
- for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
- ch[chan_idx].scan_index = chan_idx;
- ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]);
- if (ret < 0) {
- dev_err(&indio_dev->dev, "Channels init failed\n");
- return ret;
- }
+ if (legacy) {
+ /* Bind to SD modulator IIO device. */
+ adc->hwc = devm_iio_hw_consumer_alloc(&indio_dev->dev);
+ if (IS_ERR(adc->hwc))
+ return dev_err_probe(&indio_dev->dev, -EPROBE_DEFER,
+ "waiting for SD modulator\n");
}
- indio_dev->num_channels = num_ch;
+ ch = devm_kcalloc(&indio_dev->dev, num_ch, sizeof(*ch), GFP_KERNEL);
+ if (!ch)
+ return -ENOMEM;
indio_dev->channels = ch;
+ if (legacy)
+ ret = stm32_dfsdm_chan_init(indio_dev, ch);
+ else
+ ret = stm32_dfsdm_generic_chan_init(indio_dev, ch);
+ if (ret < 0)
+ return ret;
+
init_completion(&adc->completion);
/* Optionally request DMA */