From dcf821319474edde7e85b95608a4539703a2b67d Mon Sep 17 00:00:00 2001 From: David Rhodes Date: Wed, 5 Jan 2022 11:30:19 +0000 Subject: ASoC: cs35l41: Add cs35l51/53 IDs Add IDs for the CS35L51/53 variants, the functionality is shared with CS35L41. Signed-off-by: David Rhodes Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220105113026.18955-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l41-i2c.c | 2 ++ sound/soc/codecs/cs35l41-spi.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l41-i2c.c b/sound/soc/codecs/cs35l41-i2c.c index de5c8612f030..eb8dfb6d9c95 100644 --- a/sound/soc/codecs/cs35l41-i2c.c +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -22,6 +22,8 @@ static const struct i2c_device_id cs35l41_id_i2c[] = { { "cs35l40", 0 }, { "cs35l41", 0 }, + { "cs35l51", 0 }, + { "cs35l53", 0 }, {} }; diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c index c157153f28d8..86bbe2fba956 100644 --- a/sound/soc/codecs/cs35l41-spi.c +++ b/sound/soc/codecs/cs35l41-spi.c @@ -20,6 +20,8 @@ static const struct spi_device_id cs35l41_id_spi[] = { { "cs35l40", 0 }, { "cs35l41", 0 }, + { "cs35l51", 0 }, + { "cs35l53", 0 }, {} }; -- cgit v1.2.3 From 4e7c3cd87db8d9350062a25a8476f90fd1cbc4c9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Jan 2022 11:30:20 +0000 Subject: ASoC: cs35l41: Remove incorrect comment The IRQ is not used for the PDN_DONE bit, this is polled during the DAPM sequence, remove the misleading comment. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220105113026.18955-3-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l41.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index d9e6e84e64d0..980294c1bcdb 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1338,8 +1338,6 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, cs35l41_irq, IRQF_ONESHOT | IRQF_SHARED | irq_pol, "cs35l41", cs35l41); - - /* CS35L41 needs INT for PDN_DONE */ if (ret != 0) { dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret); goto err; -- cgit v1.2.3 From 56852cf4b2179fb90068a49538501f31c2de18ea Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Jan 2022 11:30:21 +0000 Subject: ASoC: cs35l41: Correct DSP power down The wm_adsp_event should be called before the early_event on power down, event stops the core running and early_event then powers down the core. Additionally, the core should only be stopped if it was actually running in the first place. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220105113026.18955-4-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l41.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 980294c1bcdb..05839fabf97b 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -181,17 +181,21 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); int ret; switch (event) { case SND_SOC_DAPM_PRE_PMU: return wm_adsp_early_event(w, kcontrol, event); case SND_SOC_DAPM_PRE_PMD: - ret = wm_adsp_early_event(w, kcontrol, event); - if (ret) - return ret; + if (cs35l41->dsp.cs_dsp.running) { + ret = wm_adsp_event(w, kcontrol, event); + if (ret) + return ret; + } - return wm_adsp_event(w, kcontrol, event); + return wm_adsp_early_event(w, kcontrol, event); default: return 0; } -- cgit v1.2.3 From 5f2f539901b0d9bda722637521a11b7f7cf753f1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Jan 2022 11:30:22 +0000 Subject: ASoC: cs35l41: Correct handling of some registers in the cache It makes no sense to cache the test/user key registers, since they require values written at specific times, mark them volatile. It is probably best if they can't be accessed from user-space either, so mark them precious as well. The interrupt force, edge, polarity and debounce are all settings applied to the IRQ rather than status bits and as such should not be volatile. The OTP trim values will require re-application in the event of a cache sync and as such should not be volatile. The OTPID however should be volatile. The DSP scratch registers are used to read back an error/debug code from the DSP on shutdown, as such these should be marked volatile. Finally, add some missing defaults, add TST_FS_MON0, and allow the DSP core control register to be cached. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220105113026.18955-5-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l41-lib.c | 81 ++++++++++++------------------------------ 1 file changed, 22 insertions(+), 59 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index d026c5e3a378..639dcd25b17e 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -20,6 +20,11 @@ static const struct reg_default cs35l41_reg[] = { { CS35L41_PWR_CTRL2, 0x00000000 }, { CS35L41_PWR_CTRL3, 0x01000010 }, { CS35L41_GPIO_PAD_CONTROL, 0x00000000 }, + { CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, + { CS35L41_TST_FS_MON0, 0x00020016 }, + { CS35L41_BSTCVRT_COEFF, 0x00002424 }, + { CS35L41_BSTCVRT_SLOPE_LBST, 0x00007500 }, + { CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A }, { CS35L41_SP_ENABLES, 0x00000000 }, { CS35L41_SP_RATE_CTRL, 0x00000028 }, { CS35L41_SP_FORMAT, 0x18180200 }, @@ -48,11 +53,16 @@ static const struct reg_default cs35l41_reg[] = { { CS35L41_WKFET_CFG, 0x00000111 }, { CS35L41_NG_CFG, 0x00000033 }, { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, + { CS35L41_IRQ1_MASK1, 0xFFFFFFFF }, + { CS35L41_IRQ1_MASK2, 0xFFFFFFFF }, + { CS35L41_IRQ1_MASK3, 0xFFFF87FF }, + { CS35L41_IRQ1_MASK4, 0xFEFFFFFF }, { CS35L41_GPIO1_CTRL1, 0xE1000001 }, { CS35L41_GPIO2_CTRL1, 0xE1000001 }, { CS35L41_MIXER_NGATE_CFG, 0x00000000 }, { CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 }, { CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 }, + { CS35L41_DSP1_CCM_CORE_CTRL, 0x00000101 }, }; static bool cs35l41_readable_reg(struct device *dev, unsigned int reg) @@ -84,6 +94,7 @@ static bool cs35l41_readable_reg(struct device *dev, unsigned int reg) case CS35L41_DSP_CLK_CTRL: case CS35L41_GLOBAL_CLK_CTRL: case CS35L41_DATA_FS_SEL: + case CS35L41_TST_FS_MON0: case CS35L41_MDSYNC_EN: case CS35L41_MDSYNC_TX_ID: case CS35L41_MDSYNC_PWR_CTRL: @@ -342,7 +353,10 @@ static bool cs35l41_readable_reg(struct device *dev, unsigned int reg) static bool cs35l41_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + case CS35L41_TST_FS_MON0: case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: @@ -359,6 +373,9 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) case CS35L41_SFT_RESET: case CS35L41_FABID: case CS35L41_REVID: + case CS35L41_OTPID: + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: case CS35L41_DTEMP_EN: case CS35L41_IRQ1_STATUS: case CS35L41_IRQ1_STATUS1: @@ -369,17 +386,6 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) case CS35L41_IRQ1_RAW_STATUS2: case CS35L41_IRQ1_RAW_STATUS3: case CS35L41_IRQ1_RAW_STATUS4: - case CS35L41_IRQ1_FRC1: - case CS35L41_IRQ1_FRC2: - case CS35L41_IRQ1_FRC3: - case CS35L41_IRQ1_FRC4: - case CS35L41_IRQ1_EDGE1: - case CS35L41_IRQ1_EDGE4: - case CS35L41_IRQ1_POL1: - case CS35L41_IRQ1_POL2: - case CS35L41_IRQ1_POL3: - case CS35L41_IRQ1_POL4: - case CS35L41_IRQ1_DB3: case CS35L41_IRQ2_STATUS: case CS35L41_IRQ2_STATUS1: case CS35L41_IRQ2_STATUS2: @@ -389,54 +395,7 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) case CS35L41_IRQ2_RAW_STATUS2: case CS35L41_IRQ2_RAW_STATUS3: case CS35L41_IRQ2_RAW_STATUS4: - case CS35L41_IRQ2_FRC1: - case CS35L41_IRQ2_FRC2: - case CS35L41_IRQ2_FRC3: - case CS35L41_IRQ2_FRC4: - case CS35L41_IRQ2_EDGE1: - case CS35L41_IRQ2_EDGE4: - case CS35L41_IRQ2_POL1: - case CS35L41_IRQ2_POL2: - case CS35L41_IRQ2_POL3: - case CS35L41_IRQ2_POL4: - case CS35L41_IRQ2_DB3: case CS35L41_GPIO_STATUS1: - case CS35L41_OTP_TRIM_1: - case CS35L41_OTP_TRIM_2: - case CS35L41_OTP_TRIM_3: - case CS35L41_OTP_TRIM_4: - case CS35L41_OTP_TRIM_5: - case CS35L41_OTP_TRIM_6: - case CS35L41_OTP_TRIM_7: - case CS35L41_OTP_TRIM_8: - case CS35L41_OTP_TRIM_9: - case CS35L41_OTP_TRIM_10: - case CS35L41_OTP_TRIM_11: - case CS35L41_OTP_TRIM_12: - case CS35L41_OTP_TRIM_13: - case CS35L41_OTP_TRIM_14: - case CS35L41_OTP_TRIM_15: - case CS35L41_OTP_TRIM_16: - case CS35L41_OTP_TRIM_17: - case CS35L41_OTP_TRIM_18: - case CS35L41_OTP_TRIM_19: - case CS35L41_OTP_TRIM_20: - case CS35L41_OTP_TRIM_21: - case CS35L41_OTP_TRIM_22: - case CS35L41_OTP_TRIM_23: - case CS35L41_OTP_TRIM_24: - case CS35L41_OTP_TRIM_25: - case CS35L41_OTP_TRIM_26: - case CS35L41_OTP_TRIM_27: - case CS35L41_OTP_TRIM_28: - case CS35L41_OTP_TRIM_29: - case CS35L41_OTP_TRIM_30: - case CS35L41_OTP_TRIM_31: - case CS35L41_OTP_TRIM_32: - case CS35L41_OTP_TRIM_33: - case CS35L41_OTP_TRIM_34: - case CS35L41_OTP_TRIM_35: - case CS35L41_OTP_TRIM_36: case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046: @@ -445,7 +404,11 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022: case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045: case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: - case CS35L41_DSP1_CCM_CORE_CTRL ... CS35L41_DSP1_WDT_STATUS: + case CS35L41_DSP1_SCRATCH1: + case CS35L41_DSP1_SCRATCH2: + case CS35L41_DSP1_SCRATCH3: + case CS35L41_DSP1_SCRATCH4: + case CS35L41_DSP1_CCM_CLK_OVERRIDE ... CS35L41_DSP1_WDT_STATUS: case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: return true; default: -- cgit v1.2.3 From ba235634b138cd9d012dbe983e7920481211e132 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Jan 2022 11:30:24 +0000 Subject: ASoC: wm_adsp: Add support for "toggle" preloaders In the case a device can support retaining the firmware memory across low power states it is useful for the preloader widget to only power up whilst actually loading/unloading the core, as opposed to the normal operation where the widget is powered for the entire time a firmware is preloaded onto the core. Add support for this mode and a flag to enable it. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220105113026.18955-7-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 14 +++++++++++--- sound/soc/codecs/wm_adsp.h | 8 ++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index c3112bf23866..f3672e3d1703 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -896,11 +896,12 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, struct wm_adsp *dsp = &dsps[mc->shift - 1]; char preload[32]; - snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name); + if (dsp->preloaded == ucontrol->value.integer.value[0]) + return 0; - dsp->preloaded = ucontrol->value.integer.value[0]; + snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name); - if (ucontrol->value.integer.value[0]) + if (ucontrol->value.integer.value[0] || dsp->toggle_preload) snd_soc_component_force_enable_pin(component, preload); else snd_soc_component_disable_pin(component, preload); @@ -909,6 +910,13 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, flush_work(&dsp->boot_work); + dsp->preloaded = ucontrol->value.integer.value[0]; + + if (dsp->toggle_preload) { + snd_soc_component_disable_pin(component, preload); + snd_soc_dapm_sync(dapm); + } + return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 0e2f113bd342..7f4fabbc6ad3 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -41,6 +41,14 @@ struct wm_adsp { struct list_head compr_list; struct list_head buffer_list; + + /* + * Flag indicating the preloader widget only needs power toggled + * on state change rather than held on for the duration of the + * preload, useful for devices that can retain firmware memory + * across power down. + */ + bool toggle_preload; }; #define WM_ADSP1(wname, num) \ -- cgit v1.2.3