diff options
author | Olivier Moysan <olivier.moysan@foss.st.com> | 2021-10-14 16:12:24 +0300 |
---|---|---|
committer | Jonathan Cameron <Jonathan.Cameron@huawei.com> | 2021-10-20 16:43:54 +0300 |
commit | 45571a361c09fe89ebdefe533b3800d89d5934e3 (patch) | |
tree | 6f3aae6054e766aa6dec4974f195d69bb72a4ce8 /drivers/iio | |
parent | 6cd4ed8eb89348fa5cf0b87bb420fe39531c9b59 (diff) | |
download | linux-45571a361c09fe89ebdefe533b3800d89d5934e3.tar.xz |
iio: adc: stm32-adc: split channel init into several routines
Split stm32_adc_chan_of_init channel initialization function into
several routines to increase readability and prepare channel
generic binding handling.
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/20211014131228.4692-4-olivier.moysan@foss.st.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/adc/stm32-adc.c | 131 |
1 files changed, 87 insertions, 44 deletions
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 5088de835bb1..2f137d14f141 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -194,6 +194,7 @@ struct stm32_adc_cfg { * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) * @cal: optional calibration data on some devices * @chan_name: channel name array + * @num_diff: number of differential channels */ struct stm32_adc { struct stm32_adc_common *common; @@ -217,6 +218,7 @@ struct stm32_adc { u32 smpr_val[2]; struct stm32_adc_calib cal; char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ]; + u32 num_diff; }; struct stm32_adc_diff_channel { @@ -1706,17 +1708,11 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, } } -static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping) +static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm32_adc *adc) { struct device_node *node = indio_dev->dev.of_node; - struct stm32_adc *adc = iio_priv(indio_dev); const struct stm32_adc_info *adc_info = adc->cfg->adc_info; - struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; - struct property *prop; - const __be32 *cur; - struct iio_chan_spec *channels; - int scan_index = 0, num_channels = 0, num_diff = 0, ret, i; - u32 val, smp = 0; + int num_channels = 0, ret; ret = of_property_count_u32_elems(node, "st,adc-channels"); if (ret > adc_info->max_channels) { @@ -1727,41 +1723,54 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping) } ret = of_property_count_elems_of_size(node, "st,adc-diff-channels", - sizeof(*diff)); + sizeof(struct stm32_adc_diff_channel)); if (ret > adc_info->max_channels) { dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n"); return -EINVAL; } else if (ret > 0) { - int size = ret * sizeof(*diff) / sizeof(u32); - - num_diff = ret; + adc->num_diff = ret; num_channels += ret; + } + + return num_channels; +} + +static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev, + struct stm32_adc *adc, + struct iio_chan_spec *channels) +{ + struct device_node *node = indio_dev->dev.of_node; + const struct stm32_adc_info *adc_info = adc->cfg->adc_info; + struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; + u32 num_diff = adc->num_diff; + int size = num_diff * sizeof(*diff) / sizeof(u32); + int scan_index = 0, val, ret, i; + struct property *prop; + const __be32 *cur; + + if (num_diff) { ret = of_property_read_u32_array(node, "st,adc-diff-channels", (u32 *)diff, size); - if (ret) + if (ret) { + dev_err(&indio_dev->dev, "Failed to get diff channels %d\n", ret); return ret; - } + } - if (!num_channels) { - dev_err(&indio_dev->dev, "No channels configured\n"); - return -ENODATA; - } + 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; + } - /* 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; + stm32_adc_chan_init_one(indio_dev, &channels[scan_index], + diff[i].vinp, diff[i].vinn, + scan_index, true); + scan_index++; + } } - if (timestamping) - num_channels++; - - channels = devm_kcalloc(&indio_dev->dev, num_channels, - sizeof(struct iio_chan_spec), GFP_KERNEL); - if (!channels) - return -ENOMEM; - of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) { if (val >= adc_info->max_channels) { dev_err(&indio_dev->dev, "Invalid channel %d\n", val); @@ -1771,8 +1780,7 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping) /* Channel can't be configured both as single-ended & diff */ for (i = 0; i < num_diff; i++) { if (val == diff[i].vinp) { - dev_err(&indio_dev->dev, - "channel %d miss-configured\n", val); + dev_err(&indio_dev->dev, "channel %d misconfigured\n", val); return -EINVAL; } } @@ -1781,19 +1789,54 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping) scan_index++; } - 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++; + return scan_index; +} + +static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping) +{ + struct device_node *node = indio_dev->dev.of_node; + struct stm32_adc *adc = iio_priv(indio_dev); + const struct stm32_adc_info *adc_info = adc->cfg->adc_info; + struct iio_chan_spec *channels; + int scan_index = 0, num_channels = 0, ret, i; + u32 smp = 0; + + ret = stm32_adc_get_legacy_chan_count(indio_dev, adc); + if (ret < 0) + return ret; + num_channels = ret; + + if (!num_channels) { + dev_err(&indio_dev->dev, "No channels configured\n"); + return -ENODATA; } + if (num_channels > adc_info->max_channels) { + dev_err(&indio_dev->dev, "Channel number [%d] exceeds %d\n", + num_channels, adc_info->max_channels); + return -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; + } + + if (timestamping) + num_channels++; + + channels = devm_kcalloc(&indio_dev->dev, num_channels, + sizeof(struct iio_chan_spec), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels); + if (ret < 0) + return ret; + scan_index = ret; + for (i = 0; i < scan_index; i++) { /* * Using of_property_read_u32_index(), smp value will only be |