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

drivers: iio: filter: admv8818: add bypass mode

Add filter bypass mode, which bypasses the low pass filter, high pass
filter and disables/unregister the clock rate notifier.

Currently a feature like bypassing the filter is not achievable
straightforward and not very deductive. The user has to look through the
code and call the set_lpf_3db_frequency and set_hpf_3db_frequency iio
attributes from the user interface using the corner cases (freq >
largest lpf supported by the part, respectively freq < smallest hpf
supported by the part). Moreover, in such case of bypassing the filter,
the input clock rate change might mess up things so we want to make sure
that it is disabled. Also, the feature will help emphasizing the filter
behavior, therefore adding it in the userspace will ease the
charcaterization of the filter's effects when active/disabled.

It was requested by users of the driver to ease the interaction with
different configuration modes of the device.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
Link: https://lore.kernel.org/r/20230731084928.8302-1-antoniu.miclaus@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Antoniu Miclaus and committed by
Jonathan Cameron
1ed87754 fdb48f9d

+56 -9
+56 -9
drivers/iio/filter/admv8818.c
··· 78 78 enum { 79 79 ADMV8818_AUTO_MODE, 80 80 ADMV8818_MANUAL_MODE, 81 + ADMV8818_BYPASS_MODE, 81 82 }; 82 83 83 84 struct admv8818_state { ··· 115 114 116 115 static const char * const admv8818_modes[] = { 117 116 [0] = "auto", 118 - [1] = "manual" 117 + [1] = "manual", 118 + [2] = "bypass" 119 119 }; 120 120 121 121 static int __admv8818_hpf_select(struct admv8818_state *st, u64 freq) ··· 396 394 return regmap_write(st->regmap, reg, write_val); 397 395 } 398 396 397 + static int admv8818_filter_bypass(struct admv8818_state *st) 398 + { 399 + int ret; 400 + 401 + mutex_lock(&st->lock); 402 + 403 + ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW, 404 + ADMV8818_SW_IN_SET_WR0_MSK | 405 + ADMV8818_SW_IN_WR0_MSK | 406 + ADMV8818_SW_OUT_SET_WR0_MSK | 407 + ADMV8818_SW_OUT_WR0_MSK, 408 + FIELD_PREP(ADMV8818_SW_IN_SET_WR0_MSK, 1) | 409 + FIELD_PREP(ADMV8818_SW_IN_WR0_MSK, 0) | 410 + FIELD_PREP(ADMV8818_SW_OUT_SET_WR0_MSK, 1) | 411 + FIELD_PREP(ADMV8818_SW_OUT_WR0_MSK, 0)); 412 + if (ret) 413 + goto exit; 414 + 415 + ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER, 416 + ADMV8818_HPF_WR0_MSK | 417 + ADMV8818_LPF_WR0_MSK, 418 + FIELD_PREP(ADMV8818_HPF_WR0_MSK, 0) | 419 + FIELD_PREP(ADMV8818_LPF_WR0_MSK, 0)); 420 + 421 + exit: 422 + mutex_unlock(&st->lock); 423 + 424 + return ret; 425 + } 426 + 399 427 static int admv8818_get_mode(struct iio_dev *indio_dev, 400 428 const struct iio_chan_spec *chan) 401 429 { ··· 443 411 444 412 if (!st->clkin) { 445 413 if (mode == ADMV8818_MANUAL_MODE) 446 - return 0; 414 + goto set_mode; 415 + 416 + if (mode == ADMV8818_BYPASS_MODE) { 417 + ret = admv8818_filter_bypass(st); 418 + if (ret) 419 + return ret; 420 + 421 + goto set_mode; 422 + } 447 423 448 424 return -EINVAL; 449 425 } 450 426 451 427 switch (mode) { 452 428 case ADMV8818_AUTO_MODE: 453 - if (!st->filter_mode) 429 + if (st->filter_mode == ADMV8818_AUTO_MODE) 454 430 return 0; 455 431 456 432 ret = clk_prepare_enable(st->clkin); ··· 474 434 475 435 break; 476 436 case ADMV8818_MANUAL_MODE: 477 - if (st->filter_mode) 478 - return 0; 437 + case ADMV8818_BYPASS_MODE: 438 + if (st->filter_mode == ADMV8818_AUTO_MODE) { 439 + clk_disable_unprepare(st->clkin); 479 440 480 - clk_disable_unprepare(st->clkin); 441 + ret = clk_notifier_unregister(st->clkin, &st->nb); 442 + if (ret) 443 + return ret; 444 + } 481 445 482 - ret = clk_notifier_unregister(st->clkin, &st->nb); 483 - if (ret) 484 - return ret; 446 + if (mode == ADMV8818_BYPASS_MODE) { 447 + ret = admv8818_filter_bypass(st); 448 + if (ret) 449 + return ret; 450 + } 485 451 486 452 break; 487 453 default: 488 454 return -EINVAL; 489 455 } 490 456 457 + set_mode: 491 458 st->filter_mode = mode; 492 459 493 460 return ret;