diff options
author | Mark Brown <broonie@kernel.org> | 2022-01-05 16:59:21 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2022-01-05 16:59:21 +0100 |
commit | 570010b82e8a04206eb228da23e4ef0264df7d25 (patch) | |
tree | 2e876bb726658248323fb2dca0795e8c10ba835f /sound | |
parent | ASoC: cs4265: Add a remove() function (diff) | |
parent | ASoC: wm_adsp: Add support for "toggle" preloaders (diff) | |
download | linux-570010b82e8a04206eb228da23e4ef0264df7d25.tar.xz linux-570010b82e8a04206eb228da23e4ef0264df7d25.zip |
Add low power hibernation support to cs35l41
Merge series from Charles Keepax <ckeepax@opensource.cirrus.com>:
This patch series adds support for the low power hibernation feature
on cs35l41. This allows the DSP memory to be retained whilst the
device enters a very low power state.
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/cs35l41-i2c.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/cs35l41-lib.c | 81 | ||||
-rw-r--r-- | sound/soc/codecs/cs35l41-spi.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/cs35l41.c | 14 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 14 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.h | 8 |
6 files changed, 53 insertions, 68 deletions
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-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: 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 }, {} }; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index d9e6e84e64d0..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; } @@ -1338,8 +1342,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; 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) \ |