[RFC PATCH 1/2] ASoC: soc-component: add snd_soc_component_read/write_field()
It's often the case that we would write or read a particular field in register. With the current soc_component apis, reading a particular field in register would involve first read the register and then perform shift operations.
Ex: to read from a field mask of 0xf0
val = snd_soc_component_read(component, reg); field = ((val & 0xf0) >> 0x4);
This is sometimes prone to errors and code become less readable!
With this new api we could just do field = snd_soc_component_read_field(component, reg, 0xf0);
this makes it bit simple, easy to write and less error prone!
This also applies to writing!
There are various places in kernel which provides such field interfaces however soc_component seems to be missing this.
This patch is inspired by FIELD_GET/FIELD_PREP macros in include/linux/bitfield.h
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- include/sound/soc-component.h | 6 ++++ sound/soc/soc-component.c | 62 +++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+)
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 0bce41fefd30..5b47768222b7 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -353,6 +353,12 @@ int snd_soc_component_test_bits(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int value);
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component, + unsigned int reg, unsigned int mask); +int snd_soc_component_write_field(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int val); + /* component wide operations */ int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id, int source, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 760523382f3c..6bdfc6f61ed6 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -12,6 +12,7 @@ #include <linux/pm_runtime.h> #include <sound/soc.h>
+#define __soc_component_field_shift(x) (__builtin_ffs(x) - 1) #define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret) static inline int _soc_component_ret(struct snd_soc_component *component, const char *func, int ret) @@ -839,6 +840,67 @@ int snd_soc_component_update_bits_async(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
+/** + * snd_soc_component_read_field() - Read register field value + * @component: Component to read from + * @reg: Register to read + * @mask: mask of the register field + * + * Return: read value of register field. + */ +unsigned int snd_soc_component_read_field(struct snd_soc_component *component, + unsigned int reg, unsigned int mask) +{ + unsigned int val; + + mutex_lock(&component->io_mutex); + val = soc_component_read_no_lock(component, reg); + if (mask) + val = (val & mask) >> __soc_component_field_shift(mask); + mutex_unlock(&component->io_mutex); + + return val; +} +EXPORT_SYMBOL_GPL(snd_soc_component_read_field); + +/** + * snd_soc_component_write_field() - write to register field + * @component: Component to write to + * @reg: Register to write + * @mask: mask of the register field to update + * @val: value of the field to write + * + * Return: 1 for change, otherwise 0. + */ +int snd_soc_component_write_field(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int val) +{ + unsigned int old, new; + int ret = 0; + bool change; + + if (!mask) + return false; + + mutex_lock(&component->io_mutex); + + old = soc_component_read_no_lock(component, reg); + + val = val << __soc_component_field_shift(mask); + + new = (old & ~mask) | (val & mask); + + change = old != new; + if (change) + ret = soc_component_write_no_lock(component, reg, new); + + mutex_unlock(&component->io_mutex); + + return change; +} +EXPORT_SYMBOL_GPL(snd_soc_component_write_field); + /** * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed * @component: Component for which to wait
Make use of snd_soc_component_read_field() to make the code more readable!
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/lpass-wsa-macro.c | 43 ++++++++++++++---------------- 1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 25f1df214ca5..5ebcd935ba89 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -40,9 +40,11 @@ #define CDC_WSA_TOP_I2S_CLK (0x00A4) #define CDC_WSA_TOP_I2S_RESET (0x00A8) #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 (0x0100) -#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK GENMASK(5, 3) -#define CDC_WSA_RX_INTX_2_SEL_MASK GENMASK(2, 0) +#define CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK GENMASK(2, 0) +#define CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK GENMASK(5, 3) #define CDC_WSA_RX_INP_MUX_RX_INT0_CFG1 (0x0104) +#define CDC_WSA_RX_INTX_2_SEL_MASK GENMASK(2, 0) +#define CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK GENMASK(5, 3) #define CDC_WSA_RX_INP_MUX_RX_INT1_CFG0 (0x0108) #define CDC_WSA_RX_INP_MUX_RX_INT1_CFG1 (0x010C) #define CDC_WSA_RX_INP_MUX_RX_MIX_CFG0 (0x0110) @@ -229,8 +231,6 @@ #define NUM_INTERPOLATORS 2 #define WSA_NUM_CLKS_MAX 5 #define WSA_MACRO_MCLK_FREQ 19200000 -#define WSA_MACRO_MUX_INP_SHFT 0x3 -#define WSA_MACRO_MUX_INP_MASK1 0x07 #define WSA_MACRO_MUX_INP_MASK2 0x38 #define WSA_MACRO_MUX_CFG_OFFSET 0x8 #define WSA_MACRO_MUX_CFG1_OFFSET 0x4 @@ -843,7 +843,6 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, u32 j, port; u16 int_mux_cfg0, int_mux_cfg1; u16 int_fs_reg; - u8 int_mux_cfg0_val, int_mux_cfg1_val; u8 inp0_sel, inp1_sel, inp2_sel; struct snd_soc_component *component = dai->component; struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); @@ -865,15 +864,13 @@ static int wsa_macro_set_prim_interpolator_rate(struct snd_soc_dai *dai, */ for (j = 0; j < NUM_INTERPOLATORS; j++) { int_mux_cfg1 = int_mux_cfg0 + WSA_MACRO_MUX_CFG1_OFFSET; - int_mux_cfg0_val = snd_soc_component_read(component, - int_mux_cfg0); - int_mux_cfg1_val = snd_soc_component_read(component, - int_mux_cfg1); - inp0_sel = int_mux_cfg0_val & WSA_MACRO_MUX_INP_MASK1; - inp1_sel = (int_mux_cfg0_val >> WSA_MACRO_MUX_INP_SHFT) & - WSA_MACRO_MUX_INP_MASK1; - inp2_sel = (int_mux_cfg1_val >> WSA_MACRO_MUX_INP_SHFT) & - WSA_MACRO_MUX_INP_MASK1; + inp0_sel = snd_soc_component_read_field(component, int_mux_cfg0, + CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK); + inp1_sel = snd_soc_component_read_field(component, int_mux_cfg0, + CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK); + inp2_sel = snd_soc_component_read_field(component, int_mux_cfg1, + CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK); + if ((inp0_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || (inp1_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0) || (inp2_sel == int_1_mix1_inp + INTn_1_INP_SEL_RX0)) { @@ -912,9 +909,9 @@ static int wsa_macro_set_mix_interpolator_rate(struct snd_soc_dai *dai,
int_mux_cfg1 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG1; for (j = 0; j < NUM_INTERPOLATORS; j++) { - int_mux_cfg1_val = snd_soc_component_read(component, - int_mux_cfg1) & - WSA_MACRO_MUX_INP_MASK1; + int_mux_cfg1_val = snd_soc_component_read_field(component, int_mux_cfg1, + CDC_WSA_RX_INTX_2_SEL_MASK); + if (int_mux_cfg1_val == int_2_inp + INTn_2_INP_SEL_RX0) { int_fs_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL + WSA_MACRO_RX_PATH_OFFSET * j; @@ -1410,25 +1407,25 @@ static bool wsa_macro_adie_lb(struct snd_soc_component *component, int interp_idx) { u16 int_mux_cfg0, int_mux_cfg1; - u8 int_mux_cfg0_val, int_mux_cfg1_val; u8 int_n_inp0, int_n_inp1, int_n_inp2;
int_mux_cfg0 = CDC_WSA_RX_INP_MUX_RX_INT0_CFG0 + interp_idx * 8; int_mux_cfg1 = int_mux_cfg0 + 4; - int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0); - int_mux_cfg1_val = snd_soc_component_read(component, int_mux_cfg1);
- int_n_inp0 = int_mux_cfg0_val & 0x0F; + int_n_inp0 = snd_soc_component_read_field(component, int_mux_cfg0, + CDC_WSA_RX_INTX_1_MIX_INP0_SEL_MASK); if (int_n_inp0 == INTn_1_INP_SEL_DEC0 || int_n_inp0 == INTn_1_INP_SEL_DEC1) return true;
- int_n_inp1 = int_mux_cfg0_val >> 4; + int_n_inp1 = snd_soc_component_read_field(component, int_mux_cfg0, + CDC_WSA_RX_INTX_1_MIX_INP1_SEL_MASK); if (int_n_inp1 == INTn_1_INP_SEL_DEC0 || int_n_inp1 == INTn_1_INP_SEL_DEC1) return true;
- int_n_inp2 = int_mux_cfg1_val >> 4; + int_n_inp2 = snd_soc_component_read_field(component, int_mux_cfg1, + CDC_WSA_RX_INTX_1_MIX_INP2_SEL_MASK); if (int_n_inp2 == INTn_1_INP_SEL_DEC0 || int_n_inp2 == INTn_1_INP_SEL_DEC1) return true;
On Tue, Jan 26, 2021 at 12:20:19PM +0000, Srinivas Kandagatla wrote:
+#define __soc_component_field_shift(x) (__builtin_ffs(x) - 1)
Why not have this be a static inline?
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component,
unsigned int reg, unsigned int mask)
+{
- unsigned int val;
- mutex_lock(&component->io_mutex);
- val = soc_component_read_no_lock(component, reg);
- if (mask)
val = (val & mask) >> __soc_component_field_shift(mask);
I don't understand why this is open coding the locking when it's just a simple read and then shift?
- mutex_lock(&component->io_mutex);
- old = soc_component_read_no_lock(component, reg);
- val = val << __soc_component_field_shift(mask);
- new = (old & ~mask) | (val & mask);
- change = old != new;
- if (change)
ret = soc_component_write_no_lock(component, reg, new);
- mutex_unlock(&component->io_mutex);
This needs the lock as it's a read/modify/write but could also be implemented in terms of the existing update_bits() operation rather than open coding it.
On 26/01/2021 13:36, Mark Brown wrote:
On Tue, Jan 26, 2021 at 12:20:19PM +0000, Srinivas Kandagatla wrote:
+#define __soc_component_field_shift(x) (__builtin_ffs(x) - 1)
Why not have this be a static inline?
Sure, that makes it even better to validate the mask aswell!
+unsigned int snd_soc_component_read_field(struct snd_soc_component *component,
unsigned int reg, unsigned int mask)
+{
- unsigned int val;
- mutex_lock(&component->io_mutex);
- val = soc_component_read_no_lock(component, reg);
- if (mask)
val = (val & mask) >> __soc_component_field_shift(mask);
I don't understand why this is open coding the locking when it's just a simple read and then shift?
I agree! something like this should be good I guess:
unsigned int snd_soc_component_read_field(...) { unsigned int val;
val = snd_soc_component_read(component, reg);
val = (val & mask) >> __soc_component_field_shift(mask);
return val; }
- mutex_lock(&component->io_mutex);
- old = soc_component_read_no_lock(component, reg);
- val = val << __soc_component_field_shift(mask);
- new = (old & ~mask) | (val & mask);
- change = old != new;
- if (change)
ret = soc_component_write_no_lock(component, reg, new);
- mutex_unlock(&component->io_mutex);
This needs the lock as it's a read/modify/write but could also be implemented in terms of the existing update_bits() operation rather than open coding it.
True!, we could simplify this to :
int snd_soc_component_write_field(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int val) { val = (val << __soc_component_field_shift(mask)) & mask;
return snd_soc_component_update_bits(component, reg, mask, val); }
Does that look okay to you?
--srini
participants (2)
-
Mark Brown
-
Srinivas Kandagatla