Skip to content

Commit 570010b

Browse files
committed
Add low power hibernation support to cs35l41
Merge series from Charles Keepax <[email protected]>: 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.
2 parents a319cb3 + ba23563 commit 570010b

File tree

7 files changed

+63
-72
lines changed

7 files changed

+63
-72
lines changed

drivers/firmware/cirrus/cs_dsp.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,10 +2744,16 @@ EXPORT_SYMBOL_GPL(cs_dsp_stop);
27442744

27452745
static int cs_dsp_halo_start_core(struct cs_dsp *dsp)
27462746
{
2747-
return regmap_update_bits(dsp->regmap,
2748-
dsp->base + HALO_CCM_CORE_CONTROL,
2749-
HALO_CORE_RESET | HALO_CORE_EN,
2750-
HALO_CORE_RESET | HALO_CORE_EN);
2747+
int ret;
2748+
2749+
ret = regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2750+
HALO_CORE_RESET | HALO_CORE_EN,
2751+
HALO_CORE_RESET | HALO_CORE_EN);
2752+
if (ret)
2753+
return ret;
2754+
2755+
return regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
2756+
HALO_CORE_RESET, 0);
27512757
}
27522758

27532759
static void cs_dsp_halo_stop_core(struct cs_dsp *dsp)

sound/soc/codecs/cs35l41-i2c.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
static const struct i2c_device_id cs35l41_id_i2c[] = {
2323
{ "cs35l40", 0 },
2424
{ "cs35l41", 0 },
25+
{ "cs35l51", 0 },
26+
{ "cs35l53", 0 },
2527
{}
2628
};
2729

sound/soc/codecs/cs35l41-lib.c

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ static const struct reg_default cs35l41_reg[] = {
2020
{ CS35L41_PWR_CTRL2, 0x00000000 },
2121
{ CS35L41_PWR_CTRL3, 0x01000010 },
2222
{ CS35L41_GPIO_PAD_CONTROL, 0x00000000 },
23+
{ CS35L41_GLOBAL_CLK_CTRL, 0x00000003 },
24+
{ CS35L41_TST_FS_MON0, 0x00020016 },
25+
{ CS35L41_BSTCVRT_COEFF, 0x00002424 },
26+
{ CS35L41_BSTCVRT_SLOPE_LBST, 0x00007500 },
27+
{ CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A },
2328
{ CS35L41_SP_ENABLES, 0x00000000 },
2429
{ CS35L41_SP_RATE_CTRL, 0x00000028 },
2530
{ CS35L41_SP_FORMAT, 0x18180200 },
@@ -48,11 +53,16 @@ static const struct reg_default cs35l41_reg[] = {
4853
{ CS35L41_WKFET_CFG, 0x00000111 },
4954
{ CS35L41_NG_CFG, 0x00000033 },
5055
{ CS35L41_AMP_GAIN_CTRL, 0x00000000 },
56+
{ CS35L41_IRQ1_MASK1, 0xFFFFFFFF },
57+
{ CS35L41_IRQ1_MASK2, 0xFFFFFFFF },
58+
{ CS35L41_IRQ1_MASK3, 0xFFFF87FF },
59+
{ CS35L41_IRQ1_MASK4, 0xFEFFFFFF },
5160
{ CS35L41_GPIO1_CTRL1, 0xE1000001 },
5261
{ CS35L41_GPIO2_CTRL1, 0xE1000001 },
5362
{ CS35L41_MIXER_NGATE_CFG, 0x00000000 },
5463
{ CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 },
5564
{ CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 },
65+
{ CS35L41_DSP1_CCM_CORE_CTRL, 0x00000101 },
5666
};
5767

5868
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)
8494
case CS35L41_DSP_CLK_CTRL:
8595
case CS35L41_GLOBAL_CLK_CTRL:
8696
case CS35L41_DATA_FS_SEL:
97+
case CS35L41_TST_FS_MON0:
8798
case CS35L41_MDSYNC_EN:
8899
case CS35L41_MDSYNC_TX_ID:
89100
case CS35L41_MDSYNC_PWR_CTRL:
@@ -342,7 +353,10 @@ static bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
342353
static bool cs35l41_precious_reg(struct device *dev, unsigned int reg)
343354
{
344355
switch (reg) {
356+
case CS35L41_TEST_KEY_CTL:
357+
case CS35L41_USER_KEY_CTL:
345358
case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
359+
case CS35L41_TST_FS_MON0:
346360
case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:
347361
case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:
348362
case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:
@@ -359,6 +373,9 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
359373
case CS35L41_SFT_RESET:
360374
case CS35L41_FABID:
361375
case CS35L41_REVID:
376+
case CS35L41_OTPID:
377+
case CS35L41_TEST_KEY_CTL:
378+
case CS35L41_USER_KEY_CTL:
362379
case CS35L41_DTEMP_EN:
363380
case CS35L41_IRQ1_STATUS:
364381
case CS35L41_IRQ1_STATUS1:
@@ -369,17 +386,6 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
369386
case CS35L41_IRQ1_RAW_STATUS2:
370387
case CS35L41_IRQ1_RAW_STATUS3:
371388
case CS35L41_IRQ1_RAW_STATUS4:
372-
case CS35L41_IRQ1_FRC1:
373-
case CS35L41_IRQ1_FRC2:
374-
case CS35L41_IRQ1_FRC3:
375-
case CS35L41_IRQ1_FRC4:
376-
case CS35L41_IRQ1_EDGE1:
377-
case CS35L41_IRQ1_EDGE4:
378-
case CS35L41_IRQ1_POL1:
379-
case CS35L41_IRQ1_POL2:
380-
case CS35L41_IRQ1_POL3:
381-
case CS35L41_IRQ1_POL4:
382-
case CS35L41_IRQ1_DB3:
383389
case CS35L41_IRQ2_STATUS:
384390
case CS35L41_IRQ2_STATUS1:
385391
case CS35L41_IRQ2_STATUS2:
@@ -389,54 +395,7 @@ static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
389395
case CS35L41_IRQ2_RAW_STATUS2:
390396
case CS35L41_IRQ2_RAW_STATUS3:
391397
case CS35L41_IRQ2_RAW_STATUS4:
392-
case CS35L41_IRQ2_FRC1:
393-
case CS35L41_IRQ2_FRC2:
394-
case CS35L41_IRQ2_FRC3:
395-
case CS35L41_IRQ2_FRC4:
396-
case CS35L41_IRQ2_EDGE1:
397-
case CS35L41_IRQ2_EDGE4:
398-
case CS35L41_IRQ2_POL1:
399-
case CS35L41_IRQ2_POL2:
400-
case CS35L41_IRQ2_POL3:
401-
case CS35L41_IRQ2_POL4:
402-
case CS35L41_IRQ2_DB3:
403398
case CS35L41_GPIO_STATUS1:
404-
case CS35L41_OTP_TRIM_1:
405-
case CS35L41_OTP_TRIM_2:
406-
case CS35L41_OTP_TRIM_3:
407-
case CS35L41_OTP_TRIM_4:
408-
case CS35L41_OTP_TRIM_5:
409-
case CS35L41_OTP_TRIM_6:
410-
case CS35L41_OTP_TRIM_7:
411-
case CS35L41_OTP_TRIM_8:
412-
case CS35L41_OTP_TRIM_9:
413-
case CS35L41_OTP_TRIM_10:
414-
case CS35L41_OTP_TRIM_11:
415-
case CS35L41_OTP_TRIM_12:
416-
case CS35L41_OTP_TRIM_13:
417-
case CS35L41_OTP_TRIM_14:
418-
case CS35L41_OTP_TRIM_15:
419-
case CS35L41_OTP_TRIM_16:
420-
case CS35L41_OTP_TRIM_17:
421-
case CS35L41_OTP_TRIM_18:
422-
case CS35L41_OTP_TRIM_19:
423-
case CS35L41_OTP_TRIM_20:
424-
case CS35L41_OTP_TRIM_21:
425-
case CS35L41_OTP_TRIM_22:
426-
case CS35L41_OTP_TRIM_23:
427-
case CS35L41_OTP_TRIM_24:
428-
case CS35L41_OTP_TRIM_25:
429-
case CS35L41_OTP_TRIM_26:
430-
case CS35L41_OTP_TRIM_27:
431-
case CS35L41_OTP_TRIM_28:
432-
case CS35L41_OTP_TRIM_29:
433-
case CS35L41_OTP_TRIM_30:
434-
case CS35L41_OTP_TRIM_31:
435-
case CS35L41_OTP_TRIM_32:
436-
case CS35L41_OTP_TRIM_33:
437-
case CS35L41_OTP_TRIM_34:
438-
case CS35L41_OTP_TRIM_35:
439-
case CS35L41_OTP_TRIM_36:
440399
case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8:
441400
case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:
442401
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)
445404
case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022:
446405
case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045:
447406
case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:
448-
case CS35L41_DSP1_CCM_CORE_CTRL ... CS35L41_DSP1_WDT_STATUS:
407+
case CS35L41_DSP1_SCRATCH1:
408+
case CS35L41_DSP1_SCRATCH2:
409+
case CS35L41_DSP1_SCRATCH3:
410+
case CS35L41_DSP1_SCRATCH4:
411+
case CS35L41_DSP1_CCM_CLK_OVERRIDE ... CS35L41_DSP1_WDT_STATUS:
449412
case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
450413
return true;
451414
default:

sound/soc/codecs/cs35l41-spi.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
static const struct spi_device_id cs35l41_id_spi[] = {
2121
{ "cs35l40", 0 },
2222
{ "cs35l41", 0 },
23+
{ "cs35l51", 0 },
24+
{ "cs35l53", 0 },
2325
{}
2426
};
2527

sound/soc/codecs/cs35l41.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,21 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp,
181181
static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w,
182182
struct snd_kcontrol *kcontrol, int event)
183183
{
184+
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
185+
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
184186
int ret;
185187

186188
switch (event) {
187189
case SND_SOC_DAPM_PRE_PMU:
188190
return wm_adsp_early_event(w, kcontrol, event);
189191
case SND_SOC_DAPM_PRE_PMD:
190-
ret = wm_adsp_early_event(w, kcontrol, event);
191-
if (ret)
192-
return ret;
192+
if (cs35l41->dsp.cs_dsp.running) {
193+
ret = wm_adsp_event(w, kcontrol, event);
194+
if (ret)
195+
return ret;
196+
}
193197

194-
return wm_adsp_event(w, kcontrol, event);
198+
return wm_adsp_early_event(w, kcontrol, event);
195199
default:
196200
return 0;
197201
}
@@ -1338,8 +1342,6 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
13381342
ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, cs35l41_irq,
13391343
IRQF_ONESHOT | IRQF_SHARED | irq_pol,
13401344
"cs35l41", cs35l41);
1341-
1342-
/* CS35L41 needs INT for PDN_DONE */
13431345
if (ret != 0) {
13441346
dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", ret);
13451347
goto err;

sound/soc/codecs/wm_adsp.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -896,11 +896,12 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
896896
struct wm_adsp *dsp = &dsps[mc->shift - 1];
897897
char preload[32];
898898

899-
snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
899+
if (dsp->preloaded == ucontrol->value.integer.value[0])
900+
return 0;
900901

901-
dsp->preloaded = ucontrol->value.integer.value[0];
902+
snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->cs_dsp.name);
902903

903-
if (ucontrol->value.integer.value[0])
904+
if (ucontrol->value.integer.value[0] || dsp->toggle_preload)
904905
snd_soc_component_force_enable_pin(component, preload);
905906
else
906907
snd_soc_component_disable_pin(component, preload);
@@ -909,6 +910,13 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
909910

910911
flush_work(&dsp->boot_work);
911912

913+
dsp->preloaded = ucontrol->value.integer.value[0];
914+
915+
if (dsp->toggle_preload) {
916+
snd_soc_component_disable_pin(component, preload);
917+
snd_soc_dapm_sync(dapm);
918+
}
919+
912920
return 0;
913921
}
914922
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);

sound/soc/codecs/wm_adsp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ struct wm_adsp {
4141

4242
struct list_head compr_list;
4343
struct list_head buffer_list;
44+
45+
/*
46+
* Flag indicating the preloader widget only needs power toggled
47+
* on state change rather than held on for the duration of the
48+
* preload, useful for devices that can retain firmware memory
49+
* across power down.
50+
*/
51+
bool toggle_preload;
4452
};
4553

4654
#define WM_ADSP1(wname, num) \

0 commit comments

Comments
 (0)