mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
ASoC: xilinx: formatter_pcm: Fix read-modify-write of AUD_CTRL in hw_params
xlnx_formatter_pcm_hw_params() does a read-modify-write on XLNX_AUD_CTRL
but only ORs in the new data width and active channel values without
clearing the old ones. If hw_params is called more than once on an
open stream, these fields may retain bits from the previous configuration,
resulting in an incorrect sample width or channel count.
Clear both fields before writing the new values, and use FIELD_PREP() so
the values cannot spill into neighbouring bits.
Fixes: 6f6c3c36f0 ("ASoC: xlnx: add pcm formatter platform driver")
Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
Reviewed-by: Gaddipati, Naveen <naveen.gaddipati@amd.com>
Link: https://patch.msgid.link/20261023102818.523331-1-phucduc.bui@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
99203e8d89
commit
3b54e73927
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
// Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -55,8 +56,8 @@
|
|||
#define CFG_S2MM_XFER_SHIFT 29
|
||||
#define CFG_S2MM_PKG_MASK BIT(28)
|
||||
|
||||
#define AUD_CTRL_DATA_WIDTH_SHIFT 16
|
||||
#define AUD_CTRL_ACTIVE_CH_SHIFT 19
|
||||
#define AUD_CTRL_DATA_WIDTH_MASK GENMASK(18, 16)
|
||||
#define AUD_CTRL_ACTIVE_CH_MASK GENMASK(22, 19)
|
||||
#define PERIOD_CFG_PERIODS_SHIFT 16
|
||||
|
||||
#define PERIODS_MIN 2
|
||||
|
|
@ -506,28 +507,29 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
|
|||
writel(high, stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB);
|
||||
|
||||
val = readl(stream_data->mmio + XLNX_AUD_CTRL);
|
||||
val &= ~(AUD_CTRL_DATA_WIDTH_MASK | AUD_CTRL_ACTIVE_CH_MASK);
|
||||
bits_per_sample = params_width(params);
|
||||
switch (bits_per_sample) {
|
||||
case 8:
|
||||
val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_8);
|
||||
break;
|
||||
case 16:
|
||||
val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_16);
|
||||
break;
|
||||
case 20:
|
||||
val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_20);
|
||||
break;
|
||||
case 24:
|
||||
val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_24);
|
||||
break;
|
||||
case 32:
|
||||
val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_32);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT;
|
||||
val |= FIELD_PREP(AUD_CTRL_ACTIVE_CH_MASK, active_ch);
|
||||
writel(val, stream_data->mmio + XLNX_AUD_CTRL);
|
||||
|
||||
val = (params_periods(params) << PERIOD_CFG_PERIODS_SHIFT)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user