From f31e0d0c2cad23e0cc48731634f85bb2d8707790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 10 Mar 2024 15:38:51 +0100 Subject: ASoC: tlv320adc3xxx: Don't strip remove function when driver is builtin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using __exit for the remove function results in the remove callback being discarded with SND_SOC_TLV320ADC3XXX=y. When such a device gets unbound (e.g. using sysfs or hotplug), the driver is just removed without the cleanup being performed. This results in resource leaks. Fix it by compiling in the remove callback unconditionally. This also fixes a W=1 modpost warning: WARNING: modpost: sound/soc/codecs/snd-soc-tlv320adc3xxx: section mismatch in reference: adc3xxx_i2c_driver+0x10 (section: .data) -> adc3xxx_i2c_remove (section: .exit.text) (which only happens with SND_SOC_TLV320ADC3XXX=m). Fixes: e9a3b57efd28 ("ASoC: codec: tlv320adc3xxx: New codec driver") Signed-off-by: Uwe Kleine-König Reviewed-by: Geert Uytterhoeven Link: https://msgid.link/r/20240310143852.397212-2-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adc3xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index 420bbf588efe..e100cc9f5c19 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -1429,7 +1429,7 @@ err_unprepare_mclk: return ret; } -static void __exit adc3xxx_i2c_remove(struct i2c_client *client) +static void adc3xxx_i2c_remove(struct i2c_client *client) { struct adc3xxx *adc3xxx = i2c_get_clientdata(client); @@ -1452,7 +1452,7 @@ static struct i2c_driver adc3xxx_i2c_driver = { .of_match_table = tlv320adc3xxx_of_match, }, .probe = adc3xxx_i2c_probe, - .remove = __exit_p(adc3xxx_i2c_remove), + .remove = adc3xxx_i2c_remove, .id_table = adc3xxx_i2c_id, }; -- cgit v1.2.3 From db185362fca554b201e2c62beb15a02bb39a064b Mon Sep 17 00:00:00 2001 From: M Cooley Date: Fri, 8 Mar 2024 17:35:40 -0500 Subject: ASoC: amd: yc: Fix non-functional mic on ASUS M7600RE The ASUS M7600RE (Vivobook Pro 16X OLED) needs a quirks-table entry for the internal microphone to function properly. Signed-off-by: Mitch Cooley Link: https://msgid.link/r/CALijGznExWW4fujNWwMzmn_K=wo96sGzV_2VkT7NjvEUdkg7Gw@mail.gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index cc231185d72c..384217c5eeeb 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -304,6 +304,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "E1504FA"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "M7600RE"), + } + }, { .driver_data = &acp6x_card, .matches = { -- cgit v1.2.3 From 9e2ab4b18ebd46813fc3459207335af4d368e323 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Tue, 5 Mar 2024 15:36:28 +0100 Subject: ASoC: rockchip: i2s-tdm: Fix inaccurate sampling rates The sample rates set by the rockchip_i2s_tdm driver in master mode are inaccurate up to 5% in several cases, due to the driver logic to configure clocks and a nasty interaction with the Common Clock Framework. To understand what happens, here is the relevant section of the clock tree (slightly simplified), along with the names used in the driver: vpll0 _OR_ vpll1 "mclk_root" clk_i2s2_8ch_tx_src "mclk_parent" clk_i2s2_8ch_tx_mux clk_i2s2_8ch_tx "mclk" or "mclk_tx" This is what happens when playing back e.g. at 192 kHz using audio-graph-card (when recording the same applies, only s/tx/rx/): 0. at probe, rockchip_i2s_tdm_set_sysclk() stores the passed frequency in i2s_tdm->mclk_tx_freq (*) which is 50176000, and that is never modified afterwards 1. when playback is started, rockchip_i2s_tdm_hw_params() is called and does the following two calls 2. rockchip_i2s_tdm_calibrate_mclk(): 2a. selects mclk_root0 (vpll0) as a parent for mclk_parent (mclk_tx_src), which is OK because the vpll0 rate is a good for 192000 (and sumbultiple) rates 2b. sets the mclk_root frequency based on ppm calibration computations 2c. sets mclk_tx_src to 49152000 (= 256 * 192000), which is also OK as it is a multiple of the required bit clock 3. rockchip_i2s_tdm_set_mclk() 3a. calls clk_set_rate() to set the rate of mclk_tx (clk_i2s2_8ch_tx) to the value of i2s_tdm->mclk_tx_freq (*), i.e. 50176000 which is not a multiple of the sampling frequency -- this is not OK 3a1. clk_set_rate() reacts by reparenting clk_i2s2_8ch_tx_src to vpll1 -- this is not OK because the default vpll1 rate can be divided to get 44.1 kHz and related rates, not 192 kHz The result is that the driver does a lot of ad-hoc decisions about clocks and ends up in using the wrong parent at an unoptimal rate. Step 0 is one part of the problem: unless the card driver calls set_sysclk at each stream start, whatever rate is set in mclk_tx_freq during boot will be taken and used until reboot. Moreover the driver does not care if its value is not a multiple of any audio frequency. Another part of the problem is that the whole reparenting and clock rate setting logic is conflicting with the CCF algorithms to achieve largely the same goal: selecting the best parent and setting the closest clock rate. And it turns out that only calling once clk_set_rate() on clk_i2s2_8ch_tx picks the correct vpll and sets the correct rate. The fix is based on removing the custom logic in the driver to select the parent and set the various clocks, and just let the Clock Framework do it all. As a side effect, the set_sysclk() op becomes useless because we now let the CCF compute the appropriate value for the sampling rate. It also implies that the whole calibration logic is now dead code and so it is removed along with the "PCM Clock Compensation in PPM" kcontrol, which has always been broken anyway. The handling of the 4 optional clocks also becomes dead code and is removed. The actual rates have been tested playing 30 seconds of audio at various sampling rates before and after this change using sox: time play -r -n synth 30 sine 950 gain -3 The time reported in the table below is the 'real' value reported by the 'time' command in the above command line. rate before after --------- ------ ------ 8000 Hz 30.60s 30.63s 11025 Hz 30.45s 30.51s 16000 Hz 30.47s 30.50s 22050 Hz 30.78s 30.41s 32000 Hz 31.02s 30.43s 44100 Hz 30.78s 30.41s 48000 Hz 29.81s 30.45s 88200 Hz 30.78s 30.41s 96000 Hz 29.79s 30.42s 176400 Hz 27.40s 30.41s 192000 Hz 29.79s 30.42s While the tests are running the clock tree confirms that: * without the patch, vpll1 is always used and clk_i2s2_8ch_tx always produces 50176000 Hz, which cannot be divided for most audio rates except the slowest ones, generating inaccurate rates * with the patch: - for 192000 Hz vpll0 is used - for 176400 Hz vpll1 is used - clk_i2s2_8ch_tx always produces (256 * ) Hz Tested on the RK3308 using the internal audio codec. Fixes: 081068fd6414 ("ASoC: rockchip: add support for i2s-tdm controller") Signed-off-by: Luca Ceresoli Link: https://msgid.link/r/20240305-rk3308-audio-codec-v4-1-312acdbe628f@bootlin.com Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s_tdm.c | 352 +--------------------------------- 1 file changed, 6 insertions(+), 346 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 860e66ec85e8..9fa020ef7eab 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -25,8 +25,6 @@ #define DEFAULT_MCLK_FS 256 #define CH_GRP_MAX 4 /* The max channel 8 / 2 */ #define MULTIPLEX_CH_MAX 10 -#define CLK_PPM_MIN -1000 -#define CLK_PPM_MAX 1000 #define TRCM_TXRX 0 #define TRCM_TX 1 @@ -53,20 +51,6 @@ struct rk_i2s_tdm_dev { struct clk *hclk; struct clk *mclk_tx; struct clk *mclk_rx; - /* The mclk_tx_src is parent of mclk_tx */ - struct clk *mclk_tx_src; - /* The mclk_rx_src is parent of mclk_rx */ - struct clk *mclk_rx_src; - /* - * The mclk_root0 and mclk_root1 are root parent and supplies for - * the different FS. - * - * e.g: - * mclk_root0 is VPLL0, used for FS=48000Hz - * mclk_root1 is VPLL1, used for FS=44100Hz - */ - struct clk *mclk_root0; - struct clk *mclk_root1; struct regmap *regmap; struct regmap *grf; struct snd_dmaengine_dai_dma_data capture_dma_data; @@ -76,19 +60,11 @@ struct rk_i2s_tdm_dev { const struct rk_i2s_soc_data *soc_data; bool is_master_mode; bool io_multiplex; - bool mclk_calibrate; bool tdm_mode; - unsigned int mclk_rx_freq; - unsigned int mclk_tx_freq; - unsigned int mclk_root0_freq; - unsigned int mclk_root1_freq; - unsigned int mclk_root0_initial_freq; - unsigned int mclk_root1_initial_freq; unsigned int frame_width; unsigned int clk_trcm; unsigned int i2s_sdis[CH_GRP_MAX]; unsigned int i2s_sdos[CH_GRP_MAX]; - int clk_ppm; int refcount; spinlock_t lock; /* xfer lock */ bool has_playback; @@ -114,12 +90,6 @@ static void i2s_tdm_disable_unprepare_mclk(struct rk_i2s_tdm_dev *i2s_tdm) { clk_disable_unprepare(i2s_tdm->mclk_tx); clk_disable_unprepare(i2s_tdm->mclk_rx); - if (i2s_tdm->mclk_calibrate) { - clk_disable_unprepare(i2s_tdm->mclk_tx_src); - clk_disable_unprepare(i2s_tdm->mclk_rx_src); - clk_disable_unprepare(i2s_tdm->mclk_root0); - clk_disable_unprepare(i2s_tdm->mclk_root1); - } } /** @@ -142,29 +112,9 @@ static int i2s_tdm_prepare_enable_mclk(struct rk_i2s_tdm_dev *i2s_tdm) ret = clk_prepare_enable(i2s_tdm->mclk_rx); if (ret) goto err_mclk_rx; - if (i2s_tdm->mclk_calibrate) { - ret = clk_prepare_enable(i2s_tdm->mclk_tx_src); - if (ret) - goto err_mclk_rx; - ret = clk_prepare_enable(i2s_tdm->mclk_rx_src); - if (ret) - goto err_mclk_rx_src; - ret = clk_prepare_enable(i2s_tdm->mclk_root0); - if (ret) - goto err_mclk_root0; - ret = clk_prepare_enable(i2s_tdm->mclk_root1); - if (ret) - goto err_mclk_root1; - } return 0; -err_mclk_root1: - clk_disable_unprepare(i2s_tdm->mclk_root0); -err_mclk_root0: - clk_disable_unprepare(i2s_tdm->mclk_rx_src); -err_mclk_rx_src: - clk_disable_unprepare(i2s_tdm->mclk_tx_src); err_mclk_rx: clk_disable_unprepare(i2s_tdm->mclk_tx); err_mclk_tx: @@ -564,159 +514,6 @@ static void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream, I2S_XFER_RXS_START); } -static int rockchip_i2s_tdm_clk_set_rate(struct rk_i2s_tdm_dev *i2s_tdm, - struct clk *clk, unsigned long rate, - int ppm) -{ - unsigned long rate_target; - int delta, ret; - - if (ppm == i2s_tdm->clk_ppm) - return 0; - - if (ppm < 0) - delta = -1; - else - delta = 1; - - delta *= (int)div64_u64((u64)rate * (u64)abs(ppm) + 500000, - 1000000); - - rate_target = rate + delta; - - if (!rate_target) - return -EINVAL; - - ret = clk_set_rate(clk, rate_target); - if (ret) - return ret; - - i2s_tdm->clk_ppm = ppm; - - return 0; -} - -static int rockchip_i2s_tdm_calibrate_mclk(struct rk_i2s_tdm_dev *i2s_tdm, - struct snd_pcm_substream *substream, - unsigned int lrck_freq) -{ - struct clk *mclk_root; - struct clk *mclk_parent; - unsigned int mclk_root_freq; - unsigned int mclk_root_initial_freq; - unsigned int mclk_parent_freq; - unsigned int div, delta; - u64 ppm; - int ret; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - mclk_parent = i2s_tdm->mclk_tx_src; - else - mclk_parent = i2s_tdm->mclk_rx_src; - - switch (lrck_freq) { - case 8000: - case 16000: - case 24000: - case 32000: - case 48000: - case 64000: - case 96000: - case 192000: - mclk_root = i2s_tdm->mclk_root0; - mclk_root_freq = i2s_tdm->mclk_root0_freq; - mclk_root_initial_freq = i2s_tdm->mclk_root0_initial_freq; - mclk_parent_freq = DEFAULT_MCLK_FS * 192000; - break; - case 11025: - case 22050: - case 44100: - case 88200: - case 176400: - mclk_root = i2s_tdm->mclk_root1; - mclk_root_freq = i2s_tdm->mclk_root1_freq; - mclk_root_initial_freq = i2s_tdm->mclk_root1_initial_freq; - mclk_parent_freq = DEFAULT_MCLK_FS * 176400; - break; - default: - dev_err(i2s_tdm->dev, "Invalid LRCK frequency: %u Hz\n", - lrck_freq); - return -EINVAL; - } - - ret = clk_set_parent(mclk_parent, mclk_root); - if (ret) - return ret; - - ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, mclk_root, - mclk_root_freq, 0); - if (ret) - return ret; - - delta = abs(mclk_root_freq % mclk_parent_freq - mclk_parent_freq); - ppm = div64_u64((uint64_t)delta * 1000000, (uint64_t)mclk_root_freq); - - if (ppm) { - div = DIV_ROUND_CLOSEST(mclk_root_initial_freq, mclk_parent_freq); - if (!div) - return -EINVAL; - - mclk_root_freq = mclk_parent_freq * round_up(div, 2); - - ret = clk_set_rate(mclk_root, mclk_root_freq); - if (ret) - return ret; - - i2s_tdm->mclk_root0_freq = clk_get_rate(i2s_tdm->mclk_root0); - i2s_tdm->mclk_root1_freq = clk_get_rate(i2s_tdm->mclk_root1); - } - - return clk_set_rate(mclk_parent, mclk_parent_freq); -} - -static int rockchip_i2s_tdm_set_mclk(struct rk_i2s_tdm_dev *i2s_tdm, - struct snd_pcm_substream *substream, - struct clk **mclk) -{ - unsigned int mclk_freq; - int ret; - - if (i2s_tdm->clk_trcm) { - if (i2s_tdm->mclk_tx_freq != i2s_tdm->mclk_rx_freq) { - dev_err(i2s_tdm->dev, - "clk_trcm, tx: %d and rx: %d should be the same\n", - i2s_tdm->mclk_tx_freq, - i2s_tdm->mclk_rx_freq); - return -EINVAL; - } - - ret = clk_set_rate(i2s_tdm->mclk_tx, i2s_tdm->mclk_tx_freq); - if (ret) - return ret; - - ret = clk_set_rate(i2s_tdm->mclk_rx, i2s_tdm->mclk_rx_freq); - if (ret) - return ret; - - /* mclk_rx is also ok. */ - *mclk = i2s_tdm->mclk_tx; - } else { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - *mclk = i2s_tdm->mclk_tx; - mclk_freq = i2s_tdm->mclk_tx_freq; - } else { - *mclk = i2s_tdm->mclk_rx; - mclk_freq = i2s_tdm->mclk_rx_freq; - } - - ret = clk_set_rate(*mclk, mclk_freq); - if (ret) - return ret; - } - - return 0; -} - static int rockchip_i2s_ch_to_io(unsigned int ch, bool substream_capture) { if (substream_capture) { @@ -853,19 +650,17 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); - struct clk *mclk; - int ret = 0; unsigned int val = 0; unsigned int mclk_rate, bclk_rate, div_bclk = 4, div_lrck = 64; + int err; if (i2s_tdm->is_master_mode) { - if (i2s_tdm->mclk_calibrate) - rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream, - params_rate(params)); + struct clk *mclk = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + i2s_tdm->mclk_tx : i2s_tdm->mclk_rx; - ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk); - if (ret) - return ret; + err = clk_set_rate(mclk, DEFAULT_MCLK_FS * params_rate(params)); + if (err) + return err; mclk_rate = clk_get_rate(mclk); bclk_rate = i2s_tdm->frame_width * params_rate(params); @@ -973,96 +768,6 @@ static int rockchip_i2s_tdm_trigger(struct snd_pcm_substream *substream, return 0; } -static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream, - unsigned int freq, int dir) -{ - struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai); - - /* Put set mclk rate into rockchip_i2s_tdm_set_mclk() */ - if (i2s_tdm->clk_trcm) { - i2s_tdm->mclk_tx_freq = freq; - i2s_tdm->mclk_rx_freq = freq; - } else { - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s_tdm->mclk_tx_freq = freq; - else - i2s_tdm->mclk_rx_freq = freq; - } - - dev_dbg(i2s_tdm->dev, "The target mclk_%s freq is: %d\n", - stream ? "rx" : "tx", freq); - - return 0; -} - -static int rockchip_i2s_tdm_clk_compensation_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = CLK_PPM_MIN; - uinfo->value.integer.max = CLK_PPM_MAX; - uinfo->value.integer.step = 1; - - return 0; -} - -static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); - - ucontrol->value.integer.value[0] = i2s_tdm->clk_ppm; - - return 0; -} - -static int rockchip_i2s_tdm_clk_compensation_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); - struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); - int ret = 0, ppm = 0; - int changed = 0; - unsigned long old_rate; - - if (ucontrol->value.integer.value[0] < CLK_PPM_MIN || - ucontrol->value.integer.value[0] > CLK_PPM_MAX) - return -EINVAL; - - ppm = ucontrol->value.integer.value[0]; - - old_rate = clk_get_rate(i2s_tdm->mclk_root0); - ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root0, - i2s_tdm->mclk_root0_freq, ppm); - if (ret) - return ret; - if (old_rate != clk_get_rate(i2s_tdm->mclk_root0)) - changed = 1; - - if (clk_is_match(i2s_tdm->mclk_root0, i2s_tdm->mclk_root1)) - return changed; - - old_rate = clk_get_rate(i2s_tdm->mclk_root1); - ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root1, - i2s_tdm->mclk_root1_freq, ppm); - if (ret) - return ret; - if (old_rate != clk_get_rate(i2s_tdm->mclk_root1)) - changed = 1; - - return changed; -} - -static struct snd_kcontrol_new rockchip_i2s_tdm_compensation_control = { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "PCM Clock Compensation in PPM", - .info = rockchip_i2s_tdm_clk_compensation_info, - .get = rockchip_i2s_tdm_clk_compensation_get, - .put = rockchip_i2s_tdm_clk_compensation_put, -}; - static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai) { struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); @@ -1072,9 +777,6 @@ static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai) if (i2s_tdm->has_playback) snd_soc_dai_dma_data_set_playback(dai, &i2s_tdm->playback_dma_data); - if (i2s_tdm->mclk_calibrate) - snd_soc_add_dai_controls(dai, &rockchip_i2s_tdm_compensation_control, 1); - return 0; } @@ -1115,7 +817,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { .probe = rockchip_i2s_tdm_dai_probe, .hw_params = rockchip_i2s_tdm_hw_params, .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, - .set_sysclk = rockchip_i2s_tdm_set_sysclk, .set_fmt = rockchip_i2s_tdm_set_fmt, .set_tdm_slot = rockchip_dai_tdm_slot, .trigger = rockchip_i2s_tdm_trigger, @@ -1444,35 +1145,6 @@ static void rockchip_i2s_tdm_path_config(struct rk_i2s_tdm_dev *i2s_tdm, rockchip_i2s_tdm_tx_path_config(i2s_tdm, num); } -static int rockchip_i2s_tdm_get_calibrate_mclks(struct rk_i2s_tdm_dev *i2s_tdm) -{ - int num_mclks = 0; - - i2s_tdm->mclk_tx_src = devm_clk_get(i2s_tdm->dev, "mclk_tx_src"); - if (!IS_ERR(i2s_tdm->mclk_tx_src)) - num_mclks++; - - i2s_tdm->mclk_rx_src = devm_clk_get(i2s_tdm->dev, "mclk_rx_src"); - if (!IS_ERR(i2s_tdm->mclk_rx_src)) - num_mclks++; - - i2s_tdm->mclk_root0 = devm_clk_get(i2s_tdm->dev, "mclk_root0"); - if (!IS_ERR(i2s_tdm->mclk_root0)) - num_mclks++; - - i2s_tdm->mclk_root1 = devm_clk_get(i2s_tdm->dev, "mclk_root1"); - if (!IS_ERR(i2s_tdm->mclk_root1)) - num_mclks++; - - if (num_mclks < 4 && num_mclks != 0) - return -ENOENT; - - if (num_mclks == 4) - i2s_tdm->mclk_calibrate = 1; - - return 0; -} - static int rockchip_i2s_tdm_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm, struct device_node *np, bool is_rx_path) @@ -1610,11 +1282,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) i2s_tdm->io_multiplex = of_property_read_bool(node, "rockchip,io-multiplex"); - ret = rockchip_i2s_tdm_get_calibrate_mclks(i2s_tdm); - if (ret) - return dev_err_probe(i2s_tdm->dev, ret, - "mclk-calibrate clocks missing"); - regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) { return dev_err_probe(i2s_tdm->dev, PTR_ERR(regs), @@ -1667,13 +1334,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) goto err_disable_hclk; } - if (i2s_tdm->mclk_calibrate) { - i2s_tdm->mclk_root0_initial_freq = clk_get_rate(i2s_tdm->mclk_root0); - i2s_tdm->mclk_root1_initial_freq = clk_get_rate(i2s_tdm->mclk_root1); - i2s_tdm->mclk_root0_freq = i2s_tdm->mclk_root0_initial_freq; - i2s_tdm->mclk_root1_freq = i2s_tdm->mclk_root1_initial_freq; - } - pm_runtime_enable(&pdev->dev); regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, -- cgit v1.2.3 From 23fb6bc2696119391ec3a92ccaffe50e567c515e Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Tue, 5 Mar 2024 15:56:06 +0900 Subject: ASoC: soc-core.c: Skip dummy codec when adding platforms When pcm_runtime is adding platform components it will scan all registered components. In case of DPCM FE/BE some DAI links will configure dummy platform. However both dummy codec and dummy platform are using "snd-soc-dummy" as component->name. Dummy codec should be skipped when adding platforms otherwise there'll be overflow and UBSAN complains. Reported-by: Zhipeng Wang Signed-off-by: Chancel Liu Link: https://msgid.link/r/20240305065606.3778642-1-chancel.liu@nxp.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1e94edba12eb..2ec13d1634b6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1219,6 +1219,9 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card, if (!snd_soc_is_matching_component(platform, component)) continue; + if (snd_soc_component_is_dummy(component) && component->num_dai) + continue; + snd_soc_rtd_add_component(rtd, component); } } -- cgit v1.2.3 From 861b3415e4dee06cc00cd1754808a7827b9105bf Mon Sep 17 00:00:00 2001 From: Jiawei Wang Date: Wed, 13 Mar 2024 09:58:52 +0800 Subject: ASoC: amd: yc: Revert "Fix non-functional mic on Lenovo 21J2" This reverts commit ed00a6945dc32462c2d3744a3518d2316da66fcc, which added a quirk entry to enable the Yellow Carp (YC) driver for the Lenovo 21J2 laptop. Although the microphone functioned with the YC driver, it resulted in incorrect driver usage. The Lenovo 21J2 is not a Yellow Carp platform, but a Pink Sardine platform, which already has an upstreamed driver. The microphone on the Lenovo 21J2 operates correctly with the CONFIG_SND_SOC_AMD_PS flag enabled and does not require the quirk entry. So this patch removes the quirk entry. Thanks to Mukunda Vijendar [1] for pointing this out. Link: https://lore.kernel.org/linux-sound/023092e1-689c-4b00-b93f-4092c3724fb6@amd.com/ [1] Signed-off-by: Jiawei Wang Link: https://lore.kernel.org/linux-sound/023092e1-689c-4b00-b93f-4092c3724fb6@amd.com/ [1] Link: https://msgid.link/r/20240313015853.3573242-2-me@jwang.link Signed-off-by: Mark Brown --- sound/soc/amd/yc/acp6x-mach.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 1ab69a53174e..69c68d8e7a6b 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -199,13 +199,6 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21HY"), } }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21J2"), - } - }, { .driver_data = &acp6x_card, .matches = { -- cgit v1.2.3 From 37bee1855d0e3b6dbeb8de71895f6f68cad137be Mon Sep 17 00:00:00 2001 From: Jiawei Wang Date: Wed, 13 Mar 2024 09:58:53 +0800 Subject: ASoC: amd: yc: Revert "add new YC platform variant (0x63) support" This reverts commit 316a784839b21b122e1761cdca54677bb19a47fa, that enabled Yellow Carp (YC) driver for PCI revision id 0x63. Mukunda Vijendar [1] points out that revision 0x63 is Pink Sardine platform, not Yellow Carp. The YC driver should not be enabled for this platform. This patch prevents the YC driver from being incorrectly enabled. Link: https://lore.kernel.org/linux-sound/023092e1-689c-4b00-b93f-4092c3724fb6@amd.com/ [1] Signed-off-by: Jiawei Wang Link: https://msgid.link/r/20240313015853.3573242-3-me@jwang.link Signed-off-by: Mark Brown --- sound/soc/amd/yc/pci-acp6x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c index 694b8e313902..7af6a349b1d4 100644 --- a/sound/soc/amd/yc/pci-acp6x.c +++ b/sound/soc/amd/yc/pci-acp6x.c @@ -162,7 +162,6 @@ static int snd_acp6x_probe(struct pci_dev *pci, /* Yellow Carp device check */ switch (pci->revision) { case 0x60: - case 0x63: case 0x6f: break; default: -- cgit v1.2.3 From 33c3d813330718c403a60d220f03fbece0f4fb5c Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 20 Feb 2024 22:16:03 +0200 Subject: ASoC: SOF: amd: Move signed_fw_image to struct acp_quirk_entry The signed_fw_image member of struct sof_amd_acp_desc is used to enable signed firmware support in the driver via the acp_sof_quirk_table. In preparation to support additional use cases of the quirk table (i.e. adding new flags), move signed_fw_image to a new struct acp_quirk_entry and update all references to it accordingly. No functional changes intended. Signed-off-by: Cristian Ciocaltea Link: https://msgid.link/r/20240220201623.438944-2-cristian.ciocaltea@collabora.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-loader.c | 2 +- sound/soc/sof/amd/acp.c | 47 ++++++++++++++++++++++-------------------- sound/soc/sof/amd/acp.h | 6 +++++- sound/soc/sof/amd/vangogh.c | 9 ++++++-- 4 files changed, 38 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index d2d21478399e..aad904839b81 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -173,7 +173,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) adata = sdev->pdata->hw_pdata; - if (adata->signed_fw_image) + if (adata->quirks && adata->quirks->signed_fw_image) size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; else size_fw = adata->fw_bin_size; diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 9b3c26210db3..9d9197fa83ed 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -20,12 +20,14 @@ #include "acp.h" #include "acp-dsp-offset.h" -#define SECURED_FIRMWARE 1 - static bool enable_fw_debug; module_param(enable_fw_debug, bool, 0444); MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); +static struct acp_quirk_entry quirk_valve_galileo = { + .signed_fw_image = true, +}; + const struct dmi_system_id acp_sof_quirk_table[] = { { /* Steam Deck OLED device */ @@ -33,7 +35,7 @@ const struct dmi_system_id acp_sof_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Valve"), DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), }, - .driver_data = (void *)SECURED_FIRMWARE, + .driver_data = &quirk_valve_galileo, }, {} }; @@ -254,7 +256,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } } - if (adata->signed_fw_image) + if (adata->quirks && adata->quirks->signed_fw_image) snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); @@ -738,26 +740,27 @@ skip_soundwire: sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; sdev->debug_box.size = BOX_SIZE_1024; - adata->signed_fw_image = false; dmi_id = dmi_first_match(acp_sof_quirk_table); - if (dmi_id && dmi_id->driver_data) { - adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, - "sof-%s-code.bin", - chip->name); - if (!adata->fw_code_bin) { - ret = -ENOMEM; - goto free_ipc_irq; + if (dmi_id) { + adata->quirks = dmi_id->driver_data; + + if (adata->quirks->signed_fw_image) { + adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-code.bin", + chip->name); + if (!adata->fw_code_bin) { + ret = -ENOMEM; + goto free_ipc_irq; + } + + adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-data.bin", + chip->name); + if (!adata->fw_data_bin) { + ret = -ENOMEM; + goto free_ipc_irq; + } } - - adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, - "sof-%s-data.bin", - chip->name); - if (!adata->fw_data_bin) { - ret = -ENOMEM; - goto free_ipc_irq; - } - - adata->signed_fw_image = dmi_id->driver_data; } adata->enable_fw_debug = enable_fw_debug; diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 947068da39b5..b648ed194b9f 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -207,6 +207,10 @@ struct sof_amd_acp_desc { u64 sdw_acpi_dev_addr; }; +struct acp_quirk_entry { + bool signed_fw_image; +}; + /* Common device data struct for ACP devices */ struct acp_dev_data { struct snd_sof_dev *dev; @@ -236,7 +240,7 @@ struct acp_dev_data { u8 *data_buf; dma_addr_t sram_dma_addr; u8 *sram_data_buf; - bool signed_fw_image; + struct acp_quirk_entry *quirks; struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c index de15d21aa6d9..bc6ffdb5471a 100644 --- a/sound/soc/sof/amd/vangogh.c +++ b/sound/soc/sof/amd/vangogh.c @@ -143,6 +143,7 @@ EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); int sof_vangogh_ops_init(struct snd_sof_dev *sdev) { const struct dmi_system_id *dmi_id; + struct acp_quirk_entry *quirks; /* common defaults */ memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); @@ -151,8 +152,12 @@ int sof_vangogh_ops_init(struct snd_sof_dev *sdev) sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); dmi_id = dmi_first_match(acp_sof_quirk_table); - if (dmi_id && dmi_id->driver_data) - sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; + if (dmi_id) { + quirks = dmi_id->driver_data; + + if (quirks->signed_fw_image) + sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; + } return 0; } -- cgit v1.2.3 From 094d11768f740f11483dad4efcd9bbcffa4ce146 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 20 Feb 2024 22:16:04 +0200 Subject: ASoC: SOF: amd: Skip IRAM/DRAM size modification for Steam Deck OLED The recent introduction of the ACP/PSP communication for IRAM/DRAM fence register modification breaks the audio support on Valve's Steam Deck OLED device. It causes IPC timeout errors when trying to load DSP topology during probing: 1707255557.688176 kernel: snd_sof_amd_vangogh 0000:04:00.5: ipc tx timed out for 0x30100000 (msg/reply size: 48/0) 1707255557.689035 kernel: snd_sof_amd_vangogh 0000:04:00.5: ------------[ IPC dump start ]------------ 1707255557.689421 kernel: snd_sof_amd_vangogh 0000:04:00.5: dsp_msg = 0x0 dsp_ack = 0x91d14f6f host_msg = 0x1 host_ack = 0xead0f1a4 irq_stat > 1707255557.689730 kernel: snd_sof_amd_vangogh 0000:04:00.5: ------------[ IPC dump end ]------------ 1707255557.690074 kernel: snd_sof_amd_vangogh 0000:04:00.5: ------------[ DSP dump start ]------------ 1707255557.690376 kernel: snd_sof_amd_vangogh 0000:04:00.5: IPC timeout 1707255557.690744 kernel: snd_sof_amd_vangogh 0000:04:00.5: fw_state: SOF_FW_BOOT_COMPLETE (7) 1707255557.691037 kernel: snd_sof_amd_vangogh 0000:04:00.5: invalid header size 0xdb43fe7. FW oops is bogus 1707255557.694824 kernel: snd_sof_amd_vangogh 0000:04:00.5: unexpected fault 0x6942d3b3 trace 0x6942d3b3 1707255557.695392 kernel: snd_sof_amd_vangogh 0000:04:00.5: ------------[ DSP dump end ]------------ 1707255557.695755 kernel: snd_sof_amd_vangogh 0000:04:00.5: Failed to setup widget PIPELINE.6.ACPHS1.IN 1707255557.696069 kernel: snd_sof_amd_vangogh 0000:04:00.5: error: tplg component load failed -110 1707255557.696374 kernel: snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22 1707255557.697904 kernel: snd_sof_amd_vangogh 0000:04:00.5: ASoC: error at snd_soc_component_probe on 0000:04:00.5: -22 1707255557.698405 kernel: sof_mach nau8821-max: ASoC: failed to instantiate card -22 1707255557.701061 kernel: sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max) 1707255557.701624 kernel: sof_mach: probe of nau8821-max failed with error -22 Introduce a new member skip_iram_dram_size_mod to struct acp_quirk_entry and use it to skip IRAM/DRAM size modification for Vangogh Galileo device. Fixes: 55d7bbe43346 ("ASoC: SOF: amd: Add acp-psp mailbox interface for iram-dram fence register modification") Signed-off-by: Cristian Ciocaltea Link: https://msgid.link/r/20240220201623.438944-3-cristian.ciocaltea@collabora.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 3 ++- sound/soc/sof/amd/acp.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 9d9197fa83ed..be7dc1e02284 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -26,6 +26,7 @@ MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); static struct acp_quirk_entry quirk_valve_galileo = { .signed_fw_image = true, + .skip_iram_dram_size_mod = true, }; const struct dmi_system_id acp_sof_quirk_table[] = { @@ -280,7 +281,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } /* psp_send_cmd only required for vangogh platform (rev - 5) */ - if (desc->rev == 5) { + if (desc->rev == 5 && !(adata->quirks && adata->quirks->skip_iram_dram_size_mod)) { /* Modify IRAM and DRAM size */ ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | IRAM_DRAM_FENCE_2); if (ret) diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index b648ed194b9f..e229bb6b849d 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -209,6 +209,7 @@ struct sof_amd_acp_desc { struct acp_quirk_entry { bool signed_fw_image; + bool skip_iram_dram_size_mod; }; /* Common device data struct for ACP devices */ -- cgit v1.2.3 From 9a8b202f8cb7ebebc71f1f2a353a21c76d3063a8 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Wed, 6 Mar 2024 16:23:20 +0530 Subject: ASoC: soc-compress: Fix and add DPCM locking We find mising DPCM locking inside soc_compr_set_params_fe before calling dpcm_be_dai_hw_params() and dpcm_be_dai_prepare() which cause lockdep assert for DPCM lock not held in __soc_pcm_hw_params() and __soc_pcm_prepare() Signed-off-by: Shalini Manjunatha Link: https://msgid.link/r/d985beeafdd32316eb45f20811eb7926da7a796e.1709720380.git.quic_c_shalma@quicinc.com Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index a38fee48ee00..e692aa3b8b22 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -385,11 +385,15 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + snd_soc_dpcm_mutex_lock(fe); ret = dpcm_be_dai_hw_params(fe, stream); + snd_soc_dpcm_mutex_unlock(fe); if (ret < 0) goto out; + snd_soc_dpcm_mutex_lock(fe); ret = dpcm_be_dai_prepare(fe, stream); + snd_soc_dpcm_mutex_unlock(fe); if (ret < 0) goto out; -- cgit v1.2.3