Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: adc: ad7124: support fractional sampling_frequency

Modify the attribute read/write functions for sampling_frequency and
filter_low_pass_3db_frequency to return fractional values.

These ADCs support output data rates in the single digits, so being
able to specify fractional values is necessary to use all possible
sampling frequencies.

Signed-off-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

David Lechner and committed by
Jonathan Cameron
b2dbba2b d904b8e6

+39 -26
+39 -26
drivers/iio/adc/ad7124.c
··· 166 166 bool buf_negative; 167 167 unsigned int vref_mv; 168 168 unsigned int pga_bits; 169 - unsigned int odr; 170 169 unsigned int odr_sel_bits; 171 170 unsigned int filter_type; 172 171 unsigned int calibration_offset; ··· 284 285 return fclk_hz; 285 286 } 286 287 287 - static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, unsigned int odr) 288 + static u32 ad7124_get_fadc_divisor(struct ad7124_state *st, unsigned int channel) 289 + { 290 + /* 291 + * The output data rate (f_ADC) is f_CLK / divisor. We are returning 292 + * the divisor. 293 + */ 294 + return st->channels[channel].cfg.odr_sel_bits * 32 * 4; 295 + } 296 + 297 + static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel, 298 + unsigned int odr, unsigned int odr_micro) 288 299 { 289 300 unsigned int fclk, factor, odr_sel_bits; 290 301 ··· 309 300 * FS[10:0] can have a value from 1 to 2047 310 301 */ 311 302 factor = 32 * 4; /* N = 4 for default sinc4 filter. */ 312 - odr_sel_bits = clamp(DIV_ROUND_CLOSEST(fclk, odr * factor), 1, 2047); 303 + odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * factor + 304 + odr_micro * factor / MICRO); 305 + odr_sel_bits = clamp(odr_sel_bits, 1, 2047); 313 306 314 307 if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits) 315 308 st->channels[channel].cfg.live = false; 316 309 317 - /* fADC = fCLK / (FS[10:0] x 32) */ 318 - st->channels[channel].cfg.odr = DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 319 - factor); 320 310 st->channels[channel].cfg.odr_sel_bits = odr_sel_bits; 321 311 } 322 312 323 - static int ad7124_get_3db_filter_freq(struct ad7124_state *st, 324 - unsigned int channel) 313 + static int ad7124_get_3db_filter_factor(struct ad7124_state *st, 314 + unsigned int channel) 325 315 { 326 - unsigned int fadc; 327 - 328 - fadc = st->channels[channel].cfg.odr; 329 - 316 + /* 317 + * 3dB point is the f_CLK rate times some factor. This functions returns 318 + * the factor times 1000. 319 + */ 330 320 switch (st->channels[channel].cfg.filter_type) { 331 321 case AD7124_FILTER_FILTER_SINC3: 332 - return DIV_ROUND_CLOSEST(fadc * 272, 1000); 322 + return 272; 333 323 case AD7124_FILTER_FILTER_SINC4: 334 - return DIV_ROUND_CLOSEST(fadc * 230, 1000); 324 + return 230; 335 325 default: 336 326 return -EINVAL; 337 327 } ··· 354 346 bool buf_negative; 355 347 unsigned int vref_mv; 356 348 unsigned int pga_bits; 357 - unsigned int odr; 358 349 unsigned int odr_sel_bits; 359 350 unsigned int filter_type; 360 351 unsigned int calibration_offset; ··· 370 363 cfg->buf_negative == cfg_aux->buf_negative && 371 364 cfg->vref_mv == cfg_aux->vref_mv && 372 365 cfg->pga_bits == cfg_aux->pga_bits && 373 - cfg->odr == cfg_aux->odr && 374 366 cfg->odr_sel_bits == cfg_aux->odr_sel_bits && 375 367 cfg->filter_type == cfg_aux->filter_type && 376 368 cfg->calibration_offset == cfg_aux->calibration_offset && ··· 724 718 725 719 case IIO_CHAN_INFO_SAMP_FREQ: 726 720 mutex_lock(&st->cfgs_lock); 727 - *val = st->channels[chan->address].cfg.odr; 721 + *val = ad7124_get_fclk_hz(st); 722 + *val2 = ad7124_get_fadc_divisor(st, chan->address); 728 723 mutex_unlock(&st->cfgs_lock); 729 724 730 - return IIO_VAL_INT; 731 - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 732 - mutex_lock(&st->cfgs_lock); 733 - *val = ad7124_get_3db_filter_freq(st, chan->scan_index); 734 - mutex_unlock(&st->cfgs_lock); 725 + return IIO_VAL_FRACTIONAL; 726 + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: { 727 + guard(mutex)(&st->cfgs_lock); 735 728 736 - return IIO_VAL_INT; 729 + ret = ad7124_get_3db_filter_factor(st, chan->address); 730 + if (ret < 0) 731 + return ret; 732 + 733 + /* 3dB point is the f_CLK rate times a fractional value */ 734 + *val = ret * ad7124_get_fclk_hz(st); 735 + *val2 = MILLI * ad7124_get_fadc_divisor(st, chan->address); 736 + return IIO_VAL_FRACTIONAL; 737 + } 737 738 default: 738 739 return -EINVAL; 739 740 } ··· 757 744 758 745 switch (info) { 759 746 case IIO_CHAN_INFO_SAMP_FREQ: 760 - if (val2 != 0 || val == 0) 747 + if (val2 < 0 || val < 0 || (val2 == 0 && val == 0)) 761 748 return -EINVAL; 762 749 763 - ad7124_set_channel_odr(st, chan->address, val); 750 + ad7124_set_channel_odr(st, chan->address, val, val2); 764 751 765 752 return 0; 766 753 case IIO_CHAN_INFO_SCALE: ··· 1309 1296 * regardless of the selected power mode. Round it up to 10 and 1310 1297 * set all channels to this default value. 1311 1298 */ 1312 - ad7124_set_channel_odr(st, i, 10); 1299 + ad7124_set_channel_odr(st, i, 10, 0); 1313 1300 } 1314 1301 1315 1302 ad7124_disable_all(&st->sd);