Re: [PATCH 3/3] iio: imu: Add scale and sampling frequency to BMI270 IMU

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Jonathan Cameron <jic23@xxxxxxxxxx> writes:

> On Fri, 11 Oct 2024 08:37:49 -0700
> Justin Weiss <justin@xxxxxxxxxxxxxxx> wrote:
>
>> Add read and write functions and create _available entries. Use
>> IIO_CHAN_INFO_SAMP_FREQ instead of IIO_CHAN_INFO_FREQUENCY to match
>> the BMI160 / BMI323 drivers.
>
> Ah.  Please break dropping _FREQUENCY change out as a separate fix
> with fixes tag etc and drag it to start of the patch. It was never
> wired to anything anyway
>
> That's a straight forward ABI bug so we want that to land ahead
> of the rest of the series.

Thanks, I'll pull that into its own change and make it the first patch.

> Does this device have a data ready interrupt and if so what affect
> do the different ODRs for each type of sensor have on that?
> If there are separate data ready signals, you probably want to 
> go with a dual buffer setup from the start as it is hard to unwind
> that later.

It has data ready interrupts for both accelerometer and gyroscope and a
FIFO interrupt. I had held off on interrupts to keep this change
simpler, but if it's a better idea to get it in earlier, I can add it
alongside the triggered buffer change.

>
>> 
>> Signed-off-by: Justin Weiss <justin@xxxxxxxxxxxxxxx>
>> ---
>>  drivers/iio/imu/bmi270/bmi270_core.c | 293 ++++++++++++++++++++++++++-
>>  1 file changed, 291 insertions(+), 2 deletions(-)
>> 
>> diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c
>> index f49db5d1bffd..ce7873dc3211 100644
>> --- a/drivers/iio/imu/bmi270/bmi270_core.c
>> +++ b/drivers/iio/imu/bmi270/bmi270_core.c
>> @@ -7,6 +7,7 @@
>>  #include <linux/regmap.h>
>>  
>>  #include <linux/iio/iio.h>
>> +#include <linux/iio/sysfs.h>
>>  #include <linux/iio/triggered_buffer.h>
>>  #include <linux/iio/trigger_consumer.h>
>>  
>> @@ -34,6 +35,9 @@
>>  #define BMI270_ACC_CONF_BWP_NORMAL_MODE			0x02
>>  #define BMI270_ACC_CONF_FILTER_PERF_MSK			BIT(7)
>>  
>> +#define BMI270_ACC_CONF_RANGE_REG			0x41
>> +#define BMI270_ACC_CONF_RANGE_MSK			GENMASK(1, 0)
>> +
>>  #define BMI270_GYR_CONF_REG				0x42
>>  #define BMI270_GYR_CONF_ODR_MSK				GENMASK(3, 0)
>>  #define BMI270_GYR_CONF_ODR_200HZ			0x09
>> @@ -42,6 +46,9 @@
>>  #define BMI270_GYR_CONF_NOISE_PERF_MSK			BIT(6)
>>  #define BMI270_GYR_CONF_FILTER_PERF_MSK			BIT(7)
>>  
>> +#define BMI270_GYR_CONF_RANGE_REG			0x43
>> +#define BMI270_GYR_CONF_RANGE_MSK			GENMASK(2, 0)
>> +
>>  #define BMI270_INIT_CTRL_REG				0x59
>>  #define BMI270_INIT_CTRL_LOAD_DONE_MSK			BIT(0)
>>  
>> @@ -85,6 +92,236 @@ const struct bmi270_chip_info bmi270_chip_info[] = {
>>  };
>>  EXPORT_SYMBOL_NS_GPL(bmi270_chip_info, IIO_BMI270);
>>  
>> +enum bmi270_sensor_type {
>> +	BMI270_ACCEL	= 0,
>> +	BMI270_GYRO,
>> +};
>> +
>> +struct bmi270_scale {
>> +	u8 bits;
>> +	int uscale;
>> +};
>> +
>> +struct bmi270_odr {
>> +	u8 bits;
>> +	int odr;
>> +	int uodr;
>> +};
>> +
>> +static const struct bmi270_scale bmi270_accel_scale[] = {
>> +	{ 0x00, 598},
> 	{ 0x00, 598 },
>
> So space before } for all these.

Will fix in v2.

>> +	{ 0x01, 1197},
>> +	{ 0x02, 2394},
>> +	{ 0x03, 4788},
>> +};
>> +
>> +static const struct bmi270_scale bmi270_gyro_scale[] = {
>> +	{ 0x00, 1065},
>> +	{ 0x01, 532},
>> +	{ 0x02, 266},
>> +	{ 0x03, 133},
>> +	{ 0x04, 66},
>> +};
>> +
>> +struct bmi270_scale_item {
>> +	const struct bmi270_scale *tbl;
>> +	int num;
>> +};
>> +
>> +static const struct bmi270_scale_item bmi270_scale_table[] = {
>> +	[BMI270_ACCEL] = {
>> +		.tbl	= bmi270_accel_scale,
>> +		.num	= ARRAY_SIZE(bmi270_accel_scale),
>> +	},
>> +	[BMI270_GYRO] = {
>> +		.tbl	= bmi270_gyro_scale,
>> +		.num	= ARRAY_SIZE(bmi270_gyro_scale),
>> +	},
>> +};
>> +
>> +static const struct bmi270_odr bmi270_accel_odr[] = {
>> +	{0x01, 0, 781250},
>> +	{0x02, 1, 562500},
>> +	{0x03, 3, 125000},
>> +	{0x04, 6, 250000},
>> +	{0x05, 12, 500000},
>> +	{0x06, 25, 0},
>> +	{0x07, 50, 0},
>> +	{0x08, 100, 0},
>> +	{0x09, 200, 0},
>> +	{0x0A, 400, 0},
>> +	{0x0B, 800, 0},
>> +	{0x0C, 1600, 0},
>> +};
>> +
>> +static const struct bmi270_odr bmi270_gyro_odr[] = {
>> +	{0x06, 25, 0},
>> +	{0x07, 50, 0},
>> +	{0x08, 100, 0},
>> +	{0x09, 200, 0},
>> +	{0x0A, 400, 0},
>> +	{0x0B, 800, 0},
>> +	{0x0C, 1600, 0},
>> +	{0x0D, 3200, 0},
>> +};
>> +
>> +struct bmi270_odr_item {
>> +	const struct bmi270_odr *tbl;
>> +	int num;
>> +};
>> +
>> +static const struct  bmi270_odr_item bmi270_odr_table[] = {
>> +	[BMI270_ACCEL] = {
>> +		.tbl	= bmi270_accel_odr,
>> +		.num	= ARRAY_SIZE(bmi270_accel_odr),
>> +	},
>> +	[BMI270_GYRO] = {
>> +		.tbl	= bmi270_gyro_odr,
>> +		.num	= ARRAY_SIZE(bmi270_gyro_odr),
>> +	},
>> +};
>> +
>> +static int bmi270_set_scale(struct bmi270_data *data,
>> +			    int chan_type, int uscale)
>> +{
>> +	int i;
>> +	int reg;
>> +	struct bmi270_scale_item bmi270_scale_item;
>> +
>> +	switch (chan_type) {
>> +	case IIO_ACCEL:
>> +		reg = BMI270_ACC_CONF_RANGE_REG;
>> +		bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL];
>> +		break;
>> +	case IIO_ANGL_VEL:
>> +		reg = BMI270_GYR_CONF_RANGE_REG;
>> +		bmi270_scale_item = bmi270_scale_table[BMI270_GYRO];
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	for (i = 0; i < bmi270_scale_item.num; i++)
>> +		if (bmi270_scale_item.tbl[i].uscale == uscale)
>> +			break;
>> +
>> +	if (i == bmi270_scale_item.num)
>> +		return -EINVAL;
>> +
>> +	return regmap_write(data->regmap, reg,
>> +			    bmi270_scale_item.tbl[i].bits);
> Maybe do the write in the if above, (or use the continue approach mentioned
> below + do the write in the for loop.
> Then any exit from the loop that isn't a return is a failure and you an save the check.

Thanks for this suggestion, I'll change all of these loops to use continue / return.

>> +}
>> +
>> +static int bmi270_get_scale(struct bmi270_data *bmi270_device,
>> +			    int chan_type, int *uscale)
>> +{
>> +	int i, ret, val;
>> +	int reg;
>> +	struct bmi270_scale_item bmi270_scale_item;
>> +
>> +	switch (chan_type) {
>> +	case IIO_ACCEL:
>> +		reg = BMI270_ACC_CONF_RANGE_REG;
>> +		bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL];
>> +		break;
>> +	case IIO_ANGL_VEL:
>> +		reg = BMI270_GYR_CONF_RANGE_REG;
>> +		bmi270_scale_item = bmi270_scale_table[BMI270_GYRO];
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = regmap_read(bmi270_device->regmap, reg, &val);
>> +	if (ret)
>> +		return ret;
>
> No masking?

Looks like I missed this. I'll fix it in v2.

>
>> +
>> +	for (i = 0; i < bmi270_scale_item.num; i++)
>> +		if (bmi270_scale_item.tbl[i].bits == val) {
> Flip the condition to reduce indent
>
> 		if (bmi270_scale_item.tbl[i].bits != val)
> 			continue;
>
> 		*uscale.
>
>> +			*uscale = bmi270_scale_item.tbl[i].uscale;
>> +			return 0;
>> +		}
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static int bmi270_set_odr(struct bmi270_data *data, int chan_type,
>> +			  int odr, int uodr)
>> +{
>> +	int i;
>> +	int reg, mask;
>> +	struct bmi270_odr_item bmi270_odr_item;
>> +
>> +	switch (chan_type) {
>> +	case IIO_ACCEL:
>> +		reg = BMI270_ACC_CONF_REG;
>> +		mask = BMI270_ACC_CONF_ODR_MSK;
>> +		bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL];
>> +		break;
>> +	case IIO_ANGL_VEL:
>> +		reg = BMI270_GYR_CONF_REG;
>> +		mask = BMI270_GYR_CONF_ODR_MSK;
>> +		bmi270_odr_item = bmi270_odr_table[BMI270_GYRO];
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	for (i = 0; i < bmi270_odr_item.num; i++)
>> +		if (bmi270_odr_item.tbl[i].odr == odr &&
>> +		    bmi270_odr_item.tbl[i].uodr == uodr)
>> +			break;
>> +
>> +	if (i >= bmi270_odr_item.num)
>> +		return -EINVAL;
>> +
>> +	return regmap_update_bits(data->regmap,
>> +				  reg,
>> +				  mask,
>> +				  bmi270_odr_item.tbl[i].bits);
>
> combine parameters on each line to get nearer to 80 char limit.

Will fix in v2.

>
>> +}
>> +
>> +static int bmi270_get_odr(struct bmi270_data *data, int chan_type,
>> +			  int *odr, int *uodr)
>> +{
>> +	int i, val, ret;
>> +	int reg, mask;
>> +	struct bmi270_odr_item bmi270_odr_item;
>> +
>> +	switch (chan_type) {
>> +	case IIO_ACCEL:
>> +		reg = BMI270_ACC_CONF_REG;
>> +		mask = BMI270_ACC_CONF_ODR_MSK;
>> +		bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL];
>> +		break;
>> +	case IIO_ANGL_VEL:
>> +		reg = BMI270_GYR_CONF_REG;
>> +		mask = BMI270_GYR_CONF_ODR_MSK;
>> +		bmi270_odr_item = bmi270_odr_table[BMI270_GYRO];
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = regmap_read(data->regmap, reg, &val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	val &= mask;
>
> I'd just duplicate the regmap_read to allow easy use FIELD_GET etc.
>
>
> 	switch (chan_type) {
> 	case IIO_ACCEL:
> 		ret = regmap_read(data->regmap, BMI270_ACC_CONF_REG, &val);
> 		if (ret)
> 			return ret;		
> 		val = FIELD_GET(val, BMI270_ACC_CONF_ODR_MSK);
> 		bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL];
> 		break;
> 	case IIO_ANGL_VEL:
> 		ret = regmap_read(data->regmap, BMI270_GYR_CONF_REG, &val);
> 		if (ret)
> 			return ret;
> 		val = FIELD_GET(val, BMI270_GYR_CONF_ODR_MSK);
> 		bmi270_odr_item = bmi270_odr_table[BMI270_GYRO];
> 		break;
> 	default:
> 		return -EINVAL;
> 	}

Thanks, that's nicer. I'll fix it in v2.

>> +
>> +	for (i = 0; i < bmi270_odr_item.num; i++)
>> +		if (val == bmi270_odr_item.tbl[i].bits)
>> +			break;
>> +
>> +	if (i >= bmi270_odr_item.num)
>> +		return -EINVAL;
>> +
>> +	*odr = bmi270_odr_item.tbl[i].odr;
>> +	*uodr = bmi270_odr_item.tbl[i].uodr;
>> +
>> +	return 0;
>> +}
>> +
>> +static
>> +IIO_CONST_ATTR(in_accel_sampling_frequency_available,
>> +	       "0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600");
>> +static
>> +IIO_CONST_ATTR(in_anglvel_sampling_frequency_available,
>> +	       "25 50 100 200 400 800 1600 3200");
>> +static
>> +IIO_CONST_ATTR(in_accel_scale_available,
>> +	       "0.000598 0.001197 0.002394 0.004788");
>> +static
>> +IIO_CONST_ATTR(in_anglvel_scale_available,
>> +	       "0.001065 0.000532 0.000266 0.000133 0.000066");
>> +
>> +static struct attribute *bmi270_attrs[] = {
>> +	&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
>> +	&iio_const_attr_in_anglvel_sampling_frequency_available.dev_attr.attr,
>> +	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
>> +	&iio_const_attr_in_anglvel_scale_available.dev_attr.attr,
> Please use the read_avail callback and info_mask_xxx_avail masks to specify
> these exist for all the channels.
>
> Doing this as custom attrs predates that infrastructure and we are
> slowly converting drivers over.  The main advantage beyond enforced
> ABI is that can get to the values from in kernel consumers of the data.
>

Great, I'll remove these and implement read_avail.

>> +	NULL,
> No comma here.

Will fix in v2.

>> +};
>> +
>> +static const struct attribute_group bmi270_attrs_group = {
>> +	.attrs = bmi270_attrs,
>> +};




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux