> -----Original Message----- > From: Lars-Peter Clausen <lars@xxxxxxxxxx> > Sent: Montag, 16. März 2020 15:27 > To: Sa, Nuno <Nuno.Sa@xxxxxxxxxx>; linux-iio@xxxxxxxxxxxxxxx; > devicetree@xxxxxxxxxxxxxxx > Cc: Jonathan Cameron <jic23@xxxxxxxxxx>; Hartmut Knaack > <knaack.h@xxxxxx>; Peter Meerwald-Stadler <pmeerw@xxxxxxxxxx>; Rob > Herring <robh+dt@xxxxxxxxxx>; Mark Rutland <mark.rutland@xxxxxxx>; > Ardelean, Alexandru <alexandru.Ardelean@xxxxxxxxxx>; Hennerich, Michael > <Michael.Hennerich@xxxxxxxxxx> > Subject: Re: [PATCH v2 5/6] iio: imu: Add support for adis16475 > > On 3/16/20 1:53 PM, Nuno Sá wrote: > > Support ADIS16475 and similar IMU devices. These devices are > > a precision, miniature MEMS inertial measurement unit (IMU) that > > includes a triaxial gyroscope and a triaxial accelerometer. Each > > inertial sensor combines with signal conditioning that optimizes > > dynamic performance. > > > > The driver adds support for the following devices: > > * adis16470, adis16475, adis16477, adis16465, adis16467, adis16500, > > adis16505, adis16507. > > > Looks very good, just a few comments and questions. I like the solution > for the 32-bit registers. > > > +static int adis16475_set_freq(struct adis16475 *st, const u32 freq) > > +{ > > + u16 dec; > > + int ret; > > + > > + if (freq == 0 || freq > st->clk_freq) > > + return -EINVAL; > > Maybe round down if freq is larger the maximum rate. I believe we do > that same for other drivers. Can do that... > > + > > + dec = DIV_ROUND_CLOSEST(st->clk_freq, freq); > > + > > + if (dec) > > + dec--; > > + > > + if (dec > st->info->max_dec) > > + dec = st->info->max_dec; > > + > > + ret = adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec); > > + if (ret) > > + return ret; > > + > > + /* > > + * If decimation is used, then gyro and accel data will have meaningfull > Typo: "meaningful" Ack > > + * bits on the LSB registers. This info is used on the trigger handler. > > + */ > > + if (!dec) > > + clear_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag); > > + else > > + set_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag); > > + > > + return 0; > > +} > > + > > +/* The values are approximated. */ > > +static const u32 adis16475_3db_freqs[] = { > > + [0] = 720, /* Filter disabled, full BW (~720Hz) */ > > + [1] = 360, > > + [2] = 164, > > 164 is the only one that does not follow the pattern of 720 / (2**n). > Not sure if that is on purpose. But either way where did you find the > bandwidths for the different filter settings? I had a quick look at the > datasheet and could not find anything. > So, when I started the driver and looked to other examples I also wondered about this. So, basically I asked (internally) about this table to the Application engineer responsible for this parts and got an excel sheet with this values calculated for a sampling rate of 2khz. > Maybe it also makes sense to consider the clock rate when running in > sync mode as the bandwidth will be a function of the sampling rate. > Hmm, that is true. The sampling rate also contributes to the system bandwidth Need to check if we can calculate this in the kernel though... > > + [3] = 80, > > + [4] = 40, > > + [5] = 20, > > + [6] = 10, > > + [7] = 10, /* not a valid setting */ > > +}; > > + > > +static int adis16475_get_filter(struct adis16475 *st, u32 *filter) > > +{ > > + u16 filter_sz; > > + int ret; > > + const int mask = ADIS16475_FILT_CTRL_MASK; > > + > > + ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FILT_CTRL, > &filter_sz); > > + if (ret) > > + return ret; > > + > > + *filter = adis16475_3db_freqs[filter_sz & mask]; > > + > > + return 0; > > +} > > + > > +static int adis16475_set_filter(struct adis16475 *st, const u32 filter) > > +{ > > + int i; > > + int ret; > > + > > + for (i = ARRAY_SIZE(adis16475_3db_freqs) - 1; i >= 1; i--) { > > + if (adis16475_3db_freqs[i] >= filter) > > + break; > > + } > > If the filter frequency is less or equal to 10, this will pick 7 for i. > But the comment above says that it is an invalid setting. > Good catch! I believe the part will just automatically convert it to 6. Either way, better play safe. > > > > +static u16 adis16475_validate_crc(const u8 *buffer, const u16 crc, > > + const bool burst32) > Return type is u16, but the return value is bool. Also validate kind of > suggests that it returns true if valid, but right now it returns true if > invalid. > > +{ > > + int i; > > + u16 __crc = 0; > > I find having both __crc and crc a bit confusing, maybe give them names > which better describe them. Maybe computed_crc or expected_crc. Or as an > alternative I think also just crc -= buffer[i] in the loop and crc != 0 > at the end should work. > Hmm, I like the alternative... > > > + /* extra 6 elements for low gyro and accel */ > > + const u16 sz = burst32 ? ADIS16475_BURST32_MAX_DATA : > > + ADIS16475_BURST_MAX_DATA; > > + > > + for (i = 0; i < sz - 2; i++) > > + __crc += buffer[i]; > > + > > + return (__crc != crc); > > +} > > + > > +static void adis16475_burst32_check(struct adis16475 *st) > > +{ > > + int ret; > > + struct adis *adis = &st->adis; > > + > > + if (!st->info->has_burst32) > > + return; > > + > > + if (st->lsb_flag && !st->burst32) { > > + const u16 en = ADIS16500_BURST32(1); > > + > > + ret = __adis_update_bits(&st->adis, > ADIS16475_REG_MSG_CTRL, > > + ADIS16500_BURST32_MASK, en); > > + if (ret < 0) > > + return; > > + > > + st->burst32 = true; > > + /* > > + * In 32bit mode we need extra 2 bytes for all gyro > > + * and accel channels. > > + */ > > + adis->burst->extra_len += 6 * sizeof(u16); > > I believe this breaks if you have more than one device instance as > adis->burst points to a global struct that is shared between all > instances. extra_len should probably be part of the adis struct itself > and then make the burst field const. > Ups, definitely a problem! This extra_len is actually something that I don't like. I have some local patches to get rid of this variable. So, burst_len is being calculated like this /* All but the timestamp channel */ burst_length = (indio_dev->num_channels - 1) * sizeof(u16); burst_length += adis->burst->extra_len; This is done in the library which in my opinion is wrong. The library should not assume that a timestamp channel is defined. IMHO, it would be just simpler and direct if users define burst_len directly (replacing extra_len) which is actually constant in a lot of devices... Either way, we still need a variable in the adis struct which can actually change per "instance"... Maybe I just go with your suggestion and leave the replacement of extra_len for a future patch. - Nuno Sá