Hi, this is looking quite good now. A few small comments below still. On 23/05/2022 09:23, LI Qingwu wrote: > Prepare the way for multiple chips and additional channels: > - Modify the driver to read the device ID and load the corresponding > sensor information from the table to support multiple chips > - Add prepares for the addition of extra channels > - Prepare for handling the operation modes for multiple chips > > Signed-off-by: LI Qingwu <Qing-wu.Li@xxxxxxxxxxxxxxxxxxxxxxx> > --- > drivers/iio/accel/sca3300.c | 198 ++++++++++++++++++++++++++++-------- > 1 file changed, 157 insertions(+), 41 deletions(-) > > diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c > index ff16d2cc8c70..6463d12a9ab9 100644 > --- a/drivers/iio/accel/sca3300.c > +++ b/drivers/iio/accel/sca3300.c > @@ -93,19 +93,40 @@ static const struct iio_chan_spec sca3300_channels[] = { > IIO_CHAN_SOFT_TIMESTAMP(4), > }; > > -static const int sca3300_lp_freq[] = {70, 70, 70, 10}; > -static const int sca3300_accel_scale[][2] = {{0, 370}, {0, 741}, {0, 185}, {0, 185}}; > +static const int sca3300_lp_freq[] = {70, 10}; > +static const int sca3300_lp_freq_map[] = {0, 0, 0, 1}; > > +static const int sca3300_accel_scale[][2] = {{0, 370}, {0, 741}, {0, 185}}; > +static const int sca3300_accel_scale_map[] = {0, 1, 2, 2}; > + > +static const int sca3300_avail_modes_map[] = {0, 1, 2, 3}; > static const unsigned long sca3300_scan_masks[] = { > BIT(SCA3300_ACC_X) | BIT(SCA3300_ACC_Y) | BIT(SCA3300_ACC_Z) | > BIT(SCA3300_TEMP), > 0 > }; > > +struct sca3300_chip_info { > + const char *name; > + const unsigned long *scan_masks; > + const struct iio_chan_spec *channels; > + u8 num_channels; > + u8 num_accel_scales; > + const int (*accel_scale)[2]; > + const int *accel_scale_map; > + u8 num_freqs; > + const int *freq_table; > + const int *freq_map; > + const int *avail_modes_table; > + u8 num_avail_modes; > + u8 chip_id; > +}; > + > /** > * struct sca3300_data - device data > * @spi: SPI device structure > * @lock: Data buffer lock > + * @chip: Sensor chip specific information > * @scan: Triggered buffer. Four channel 16-bit data + 64-bit timestamp > * @txbuf: Transmit buffer > * @rxbuf: Receive buffer > @@ -113,6 +134,7 @@ static const unsigned long sca3300_scan_masks[] = { > struct sca3300_data { > struct spi_device *spi; > struct mutex lock; > + const struct sca3300_chip_info *chip; > struct { > s16 channels[4]; > s64 ts __aligned(sizeof(s64)); > @@ -121,6 +143,24 @@ struct sca3300_data { > u8 rxbuf[4]; > }; > > +static const struct sca3300_chip_info sca3300_chip_tbl[] = { > + { > + .name = "sca3300", > + .scan_masks = sca3300_scan_masks, > + .channels = sca3300_channels, > + .num_channels = ARRAY_SIZE(sca3300_channels), > + .num_accel_scales = ARRAY_SIZE(sca3300_accel_scale)*2, > + .accel_scale = sca3300_accel_scale, > + .accel_scale_map = sca3300_accel_scale_map, > + .num_freqs = ARRAY_SIZE(sca3300_lp_freq), > + .freq_table = sca3300_lp_freq, > + .freq_map = sca3300_lp_freq_map, > + .avail_modes_table = sca3300_avail_modes_map, > + .num_avail_modes = 4, > + .chip_id = SCA3300_WHOAMI_ID, > + }, > +}; > + > DECLARE_CRC8_TABLE(sca3300_crc_table); > > static int sca3300_transfer(struct sca3300_data *sca_data, int *val) > @@ -227,36 +267,92 @@ static int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val) > return sca3300_error_handler(sca_data); > } > > +static int sca3300_set_op_mode(struct sca3300_data *sca_data, int index) > +{ > + if ((index < 0) || (index >= sca_data->chip->num_avail_modes)) > + return -EINVAL; > + > + return sca3300_write_reg(sca_data, SCA3300_REG_MODE, > + sca_data->chip->avail_modes_table[index]); > +} > + > +static int sca3300_get_op_mode(struct sca3300_data *sca_data, int *index) > +{ > + int reg_val; > + int ret; > + int i; > + > + ret = sca3300_read_reg(sca_data, SCA3300_REG_MODE, ®_val); > + if (ret) > + return ret; > + > + reg_val &= GENMASK(1, 0); This silently assumes that mode register has always max 4 modes, yet there is a parameter for this in chip_info (num_avail_modes). Wondering why this masking was added, I cannot see mention about this in datasheet that register REG_MODE would contain other bits that the actual mode number. Was there some specific case in mind for adding this masking? > + for (i = 0; i < sca_data->chip->num_avail_modes; i++) { > + if (sca_data->chip->avail_modes_table[i] == reg_val) > + break; > + } > + if (i == sca_data->chip->num_avail_modes) > + return -EINVAL; > + > + *index = i; > + return 0; > +} > + > +static int sca3300_set_frequency(struct sca3300_data *data, int val) > +{ > + const struct sca3300_chip_info *chip = data->chip; > + unsigned int index; > + int *opmode_scale; > + int *new_scale; > + unsigned int i; > + > + if (sca3300_get_op_mode(data, &index)) > + return -EINVAL; Suggest not hiding return code from get_op_mode() here, instead use ret = sca3300_get_op_mode(data, &index) if (ret) return ret; Thanks, Tomas > + > + /* > + * Find a mode in which the requested sampling frequency is available > + * and the scaling currently set is retained. > + */ > + opmode_scale = (int *)chip->accel_scale[chip->accel_scale_map[index]]; > + for (i = 0; i < chip->num_avail_modes; i++) { > + new_scale = (int *)chip->accel_scale[chip->accel_scale_map[i]]; > + if ((val == chip->freq_table[chip->freq_map[i]]) && > + (opmode_scale[1] == new_scale[1]) && > + (opmode_scale[0] == new_scale[0])) > + break; > + } > + if (i == chip->num_avail_modes) > + return -EINVAL; > + > + return sca3300_set_op_mode(data, i); > +} > + > static int sca3300_write_raw(struct iio_dev *indio_dev, > struct iio_chan_spec const *chan, > int val, int val2, long mask) > { > struct sca3300_data *data = iio_priv(indio_dev); > - int reg_val; > - int ret; > + int index; > int i; > > switch (mask) { > case IIO_CHAN_INFO_SCALE: > - if (val) > + if (chan->type != IIO_ACCEL) > return -EINVAL; > - > - for (i = 0; i < ARRAY_SIZE(sca3300_accel_scale); i++) { > - if (val2 == sca3300_accel_scale[i][1]) > - return sca3300_write_reg(data, SCA3300_REG_MODE, i); > + /* > + * Letting scale take priority over sampling frequency. > + * That makes sense given we can only ever end up increasing > + * the sampling frequency which is unlikely to be a problem. > + */ > + for (i = 0; i < data->chip->num_avail_modes; i++) { > + index = data->chip->accel_scale_map[i]; > + if ((val == data->chip->accel_scale[index][0]) && > + (val2 == data->chip->accel_scale[index][1])) > + return sca3300_set_op_mode(data, i); > } > return -EINVAL; > - > case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: > - ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val); > - if (ret) > - return ret; > - /* freq. change is possible only for mode 3 and 4 */ > - if (reg_val == 2 && val == sca3300_lp_freq[3]) > - return sca3300_write_reg(data, SCA3300_REG_MODE, 3); > - if (reg_val == 3 && val == sca3300_lp_freq[2]) > - return sca3300_write_reg(data, SCA3300_REG_MODE, 2); > - return -EINVAL; > + return sca3300_set_frequency(data, val); > default: > return -EINVAL; > } > @@ -267,8 +363,8 @@ static int sca3300_read_raw(struct iio_dev *indio_dev, > int *val, int *val2, long mask) > { > struct sca3300_data *data = iio_priv(indio_dev); > + int index; > int ret; > - int reg_val; > > switch (mask) { > case IIO_CHAN_INFO_RAW: > @@ -277,17 +373,24 @@ static int sca3300_read_raw(struct iio_dev *indio_dev, > return ret; > return IIO_VAL_INT; > case IIO_CHAN_INFO_SCALE: > - ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val); > + ret = sca3300_get_op_mode(data, &index); > if (ret) > return ret; > - *val = 0; > - *val2 = sca3300_accel_scale[reg_val][1]; > - return IIO_VAL_INT_PLUS_MICRO; > + switch (chan->type) { > + case IIO_ACCEL: > + index = data->chip->accel_scale_map[index]; > + *val = data->chip->accel_scale[index][0]; > + *val2 = data->chip->accel_scale[index][1]; > + return IIO_VAL_INT_PLUS_MICRO; > + default: > + return -EINVAL; > + } > case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: > - ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val); > + ret = sca3300_get_op_mode(data, &index); > if (ret) > return ret; > - *val = sca3300_lp_freq[reg_val]; > + index = data->chip->freq_map[index]; > + *val = data->chip->freq_table[index]; > return IIO_VAL_INT; > default: > return -EINVAL; > @@ -331,6 +434,7 @@ static int sca3300_init(struct sca3300_data *sca_data, > { > int value = 0; > int ret; > + int i; > > ret = sca3300_write_reg(sca_data, SCA3300_REG_MODE, > SCA3300_MODE_SW_RESET); > @@ -347,12 +451,17 @@ static int sca3300_init(struct sca3300_data *sca_data, > if (ret) > return ret; > > - if (value != SCA3300_WHOAMI_ID) { > - dev_err(&sca_data->spi->dev, > - "device id not expected value, %d != %u\n", > - value, SCA3300_WHOAMI_ID); > + for (i = 0; i < ARRAY_SIZE(sca3300_chip_tbl); i++) { > + if (sca3300_chip_tbl[i].chip_id == value) > + break; > + } > + if (i == ARRAY_SIZE(sca3300_chip_tbl)) { > + dev_err(&sca_data->spi->dev, "unknown chip id %x\n", value); > return -ENODEV; > } > + > + sca_data->chip = &sca3300_chip_tbl[i]; > + > return 0; > } > > @@ -384,15 +493,21 @@ static int sca3300_read_avail(struct iio_dev *indio_dev, > const int **vals, int *type, int *length, > long mask) > { > + struct sca3300_data *data = iio_priv(indio_dev); > switch (mask) { > case IIO_CHAN_INFO_SCALE: > - *vals = (const int *)sca3300_accel_scale; > - *length = ARRAY_SIZE(sca3300_accel_scale) * 2 - 2; > - *type = IIO_VAL_INT_PLUS_MICRO; > - return IIO_AVAIL_LIST; > + switch (chan->type) { > + case IIO_ACCEL: > + *vals = (const int *)data->chip->accel_scale; > + *length = data->chip->num_accel_scales; > + *type = IIO_VAL_INT_PLUS_MICRO; > + return IIO_AVAIL_LIST; > + default: > + return -EINVAL; > + } > case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: > - *vals = &sca3300_lp_freq[2]; > - *length = 2; > + *vals = (const int *)data->chip->freq_table; > + *length = data->chip->num_freqs; > *type = IIO_VAL_INT; > return IIO_AVAIL_LIST; > default: > @@ -424,11 +539,6 @@ static int sca3300_probe(struct spi_device *spi) > crc8_populate_msb(sca3300_crc_table, SCA3300_CRC8_POLYNOMIAL); > > indio_dev->info = &sca3300_info; > - indio_dev->name = SCA3300_ALIAS; > - indio_dev->modes = INDIO_DIRECT_MODE; > - indio_dev->channels = sca3300_channels; > - indio_dev->num_channels = ARRAY_SIZE(sca3300_channels); > - indio_dev->available_scan_masks = sca3300_scan_masks; > > ret = sca3300_init(sca_data, indio_dev); > if (ret) { > @@ -436,6 +546,12 @@ static int sca3300_probe(struct spi_device *spi) > return ret; > } > > + indio_dev->name = sca_data->chip->name; > + indio_dev->modes = INDIO_DIRECT_MODE; > + indio_dev->channels = sca_data->chip->channels; > + indio_dev->num_channels = sca_data->chip->num_channels; > + indio_dev->available_scan_masks = sca_data->chip->scan_masks; > + > ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, > iio_pollfunc_store_time, > sca3300_trigger_handler, NULL);