1 // SPDX-License-Identifier: GPL-2.0
3 // cs35l45.c - CS35L45 ALSA SoC audio driver
5 // Copyright 2019-2022 Cirrus Logic, Inc.
7 // Author: James Schulman <james.schulman@cirrus.com>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/property.h>
13 #include <linux/firmware.h>
14 #include <linux/regulator/consumer.h>
15 #include <sound/core.h>
16 #include <sound/pcm.h>
17 #include <sound/pcm_params.h>
18 #include <sound/soc.h>
19 #include <sound/tlv.h>
23 static bool cs35l45_check_cspl_mbox_sts(const enum cs35l45_cspl_mboxcmd cmd
,
24 enum cs35l45_cspl_mboxstate sts
)
27 case CSPL_MBOX_CMD_NONE
:
28 case CSPL_MBOX_CMD_UNKNOWN_CMD
:
30 case CSPL_MBOX_CMD_PAUSE
:
31 case CSPL_MBOX_CMD_OUT_OF_HIBERNATE
:
32 return (sts
== CSPL_MBOX_STS_PAUSED
);
33 case CSPL_MBOX_CMD_RESUME
:
34 return (sts
== CSPL_MBOX_STS_RUNNING
);
35 case CSPL_MBOX_CMD_REINIT
:
36 return (sts
== CSPL_MBOX_STS_RUNNING
);
37 case CSPL_MBOX_CMD_STOP_PRE_REINIT
:
38 return (sts
== CSPL_MBOX_STS_RDY_FOR_REINIT
);
39 case CSPL_MBOX_CMD_HIBERNATE
:
40 return (sts
== CSPL_MBOX_STS_HIBERNATE
);
46 static int cs35l45_set_cspl_mbox_cmd(struct cs35l45_private
*cs35l45
,
47 struct regmap
*regmap
,
48 const enum cs35l45_cspl_mboxcmd cmd
)
50 unsigned int sts
= 0, i
;
53 if (!cs35l45
->dsp
.cs_dsp
.running
) {
54 dev_err(cs35l45
->dev
, "DSP not running\n");
59 ret
= regmap_write(regmap
, CS35L45_DSP_VIRT1_MBOX_1
, cmd
);
61 if (cmd
!= CSPL_MBOX_CMD_OUT_OF_HIBERNATE
)
62 dev_err(cs35l45
->dev
, "Failed to write MBOX: %d\n", ret
);
66 // Read mailbox status and verify it is appropriate for the given cmd
67 for (i
= 0; i
< 5; i
++) {
68 usleep_range(1000, 1100);
70 ret
= regmap_read(regmap
, CS35L45_DSP_MBOX_2
, &sts
);
72 dev_err(cs35l45
->dev
, "Failed to read MBOX STS: %d\n", ret
);
76 if (!cs35l45_check_cspl_mbox_sts(cmd
, sts
))
77 dev_dbg(cs35l45
->dev
, "[%u] cmd %u returned invalid sts %u", i
, cmd
, sts
);
82 if (cmd
!= CSPL_MBOX_CMD_OUT_OF_HIBERNATE
)
83 dev_err(cs35l45
->dev
, "Failed to set mailbox cmd %u (status %u)\n", cmd
, sts
);
88 static int cs35l45_global_en_ev(struct snd_soc_dapm_widget
*w
,
89 struct snd_kcontrol
*kcontrol
, int event
)
91 struct snd_soc_component
*component
= snd_soc_dapm_to_component(w
->dapm
);
92 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(component
);
94 dev_dbg(cs35l45
->dev
, "%s event : %x\n", __func__
, event
);
97 case SND_SOC_DAPM_POST_PMU
:
98 regmap_write(cs35l45
->regmap
, CS35L45_GLOBAL_ENABLES
,
99 CS35L45_GLOBAL_EN_MASK
);
101 usleep_range(CS35L45_POST_GLOBAL_EN_US
, CS35L45_POST_GLOBAL_EN_US
+ 100);
103 case SND_SOC_DAPM_PRE_PMD
:
104 usleep_range(CS35L45_PRE_GLOBAL_DIS_US
, CS35L45_PRE_GLOBAL_DIS_US
+ 100);
106 regmap_write(cs35l45
->regmap
, CS35L45_GLOBAL_ENABLES
, 0);
115 static int cs35l45_dsp_preload_ev(struct snd_soc_dapm_widget
*w
,
116 struct snd_kcontrol
*kcontrol
, int event
)
118 struct snd_soc_component
*component
= snd_soc_dapm_to_component(w
->dapm
);
119 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(component
);
123 case SND_SOC_DAPM_PRE_PMU
:
124 if (cs35l45
->dsp
.cs_dsp
.booted
)
127 return wm_adsp_early_event(w
, kcontrol
, event
);
128 case SND_SOC_DAPM_POST_PMU
:
129 if (cs35l45
->dsp
.cs_dsp
.running
)
132 regmap_set_bits(cs35l45
->regmap
, CS35L45_PWRMGT_CTL
,
133 CS35L45_MEM_RDY_MASK
);
135 return wm_adsp_event(w
, kcontrol
, event
);
136 case SND_SOC_DAPM_PRE_PMD
:
137 if (cs35l45
->dsp
.preloaded
)
140 if (cs35l45
->dsp
.cs_dsp
.running
) {
141 ret
= wm_adsp_event(w
, kcontrol
, event
);
146 return wm_adsp_early_event(w
, kcontrol
, event
);
152 static int cs35l45_dsp_audio_ev(struct snd_soc_dapm_widget
*w
,
153 struct snd_kcontrol
*kcontrol
, int event
)
155 struct snd_soc_component
*component
= snd_soc_dapm_to_component(w
->dapm
);
156 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(component
);
159 case SND_SOC_DAPM_POST_PMU
:
160 return cs35l45_set_cspl_mbox_cmd(cs35l45
, cs35l45
->regmap
,
161 CSPL_MBOX_CMD_RESUME
);
162 case SND_SOC_DAPM_PRE_PMD
:
163 return cs35l45_set_cspl_mbox_cmd(cs35l45
, cs35l45
->regmap
,
164 CSPL_MBOX_CMD_PAUSE
);
172 static int cs35l45_activate_ctl(struct snd_soc_component
*component
,
173 const char *ctl_name
, bool active
)
175 struct snd_card
*card
= component
->card
->snd_card
;
176 struct snd_kcontrol
*kcontrol
;
177 struct snd_kcontrol_volatile
*vd
;
178 unsigned int index_offset
;
180 kcontrol
= snd_soc_component_get_kcontrol(component
, ctl_name
);
182 dev_err(component
->dev
, "Can't find kcontrol %s\n", ctl_name
);
186 index_offset
= snd_ctl_get_ioff(kcontrol
, &kcontrol
->id
);
187 vd
= &kcontrol
->vd
[index_offset
];
189 vd
->access
|= SNDRV_CTL_ELEM_ACCESS_WRITE
;
191 vd
->access
&= ~SNDRV_CTL_ELEM_ACCESS_WRITE
;
193 snd_ctl_notify(card
, SNDRV_CTL_EVENT_MASK_INFO
, &kcontrol
->id
);
198 static int cs35l45_amplifier_mode_get(struct snd_kcontrol
*kcontrol
,
199 struct snd_ctl_elem_value
*ucontrol
)
201 struct snd_soc_component
*component
=
202 snd_soc_kcontrol_component(kcontrol
);
203 struct cs35l45_private
*cs35l45
=
204 snd_soc_component_get_drvdata(component
);
206 ucontrol
->value
.integer
.value
[0] = cs35l45
->amplifier_mode
;
211 static int cs35l45_amplifier_mode_put(struct snd_kcontrol
*kcontrol
,
212 struct snd_ctl_elem_value
*ucontrol
)
214 struct snd_soc_component
*component
=
215 snd_soc_kcontrol_component(kcontrol
);
216 struct cs35l45_private
*cs35l45
=
217 snd_soc_component_get_drvdata(component
);
218 struct snd_soc_dapm_context
*dapm
=
219 snd_soc_component_get_dapm(component
);
220 unsigned int amp_state
;
223 if ((ucontrol
->value
.integer
.value
[0] == cs35l45
->amplifier_mode
) ||
224 (ucontrol
->value
.integer
.value
[0] > AMP_MODE_RCV
))
227 snd_soc_dapm_mutex_lock(dapm
);
229 ret
= regmap_read(cs35l45
->regmap
, CS35L45_BLOCK_ENABLES
, &_state
);
231 dev_err(cs35l45
->dev
, "Failed to read AMP state: %d\n", ret
);
232 snd_soc_dapm_mutex_unlock(dapm
);
236 regmap_clear_bits(cs35l45
->regmap
, CS35L45_BLOCK_ENABLES
,
237 CS35L45_AMP_EN_MASK
);
238 snd_soc_component_disable_pin_unlocked(component
, "SPK");
239 snd_soc_dapm_sync_unlocked(dapm
);
241 if (ucontrol
->value
.integer
.value
[0] == AMP_MODE_SPK
) {
242 regmap_clear_bits(cs35l45
->regmap
, CS35L45_BLOCK_ENABLES
,
243 CS35L45_RCV_EN_MASK
);
245 regmap_update_bits(cs35l45
->regmap
, CS35L45_BLOCK_ENABLES
,
247 CS35L45_BST_ENABLE
<< CS35L45_BST_EN_SHIFT
);
249 regmap_update_bits(cs35l45
->regmap
, CS35L45_HVLV_CONFIG
,
250 CS35L45_HVLV_MODE_MASK
,
251 CS35L45_HVLV_OPERATION
<<
252 CS35L45_HVLV_MODE_SHIFT
);
254 ret
= cs35l45_activate_ctl(component
, "Analog PCM Volume", true);
256 dev_err(cs35l45
->dev
,
257 "Unable to deactivate ctl (%d)\n", ret
);
259 } else /* AMP_MODE_RCV */ {
260 regmap_set_bits(cs35l45
->regmap
, CS35L45_BLOCK_ENABLES
,
261 CS35L45_RCV_EN_MASK
);
263 regmap_update_bits(cs35l45
->regmap
, CS35L45_BLOCK_ENABLES
,
265 CS35L45_BST_DISABLE_FET_OFF
<<
266 CS35L45_BST_EN_SHIFT
);
268 regmap_update_bits(cs35l45
->regmap
, CS35L45_HVLV_CONFIG
,
269 CS35L45_HVLV_MODE_MASK
,
270 CS35L45_FORCE_LV_OPERATION
<<
271 CS35L45_HVLV_MODE_SHIFT
);
273 regmap_clear_bits(cs35l45
->regmap
,
274 CS35L45_BLOCK_ENABLES2
,
275 CS35L45_AMP_DRE_EN_MASK
);
277 regmap_update_bits(cs35l45
->regmap
, CS35L45_AMP_GAIN
,
278 CS35L45_AMP_GAIN_PCM_MASK
,
279 CS35L45_AMP_GAIN_PCM_13DBV
<<
280 CS35L45_AMP_GAIN_PCM_SHIFT
);
282 ret
= cs35l45_activate_ctl(component
, "Analog PCM Volume", false);
284 dev_err(cs35l45
->dev
,
285 "Unable to deactivate ctl (%d)\n", ret
);
288 if (amp_state
& CS35L45_AMP_EN_MASK
)
289 regmap_set_bits(cs35l45
->regmap
, CS35L45_BLOCK_ENABLES
,
290 CS35L45_AMP_EN_MASK
);
292 snd_soc_component_enable_pin_unlocked(component
, "SPK");
293 snd_soc_dapm_sync_unlocked(dapm
);
294 snd_soc_dapm_mutex_unlock(dapm
);
296 cs35l45
->amplifier_mode
= ucontrol
->value
.integer
.value
[0];
301 static const char * const cs35l45_asp_tx_txt
[] = {
302 "Zero", "ASP_RX1", "ASP_RX2",
303 "VMON", "IMON", "ERR_VOL",
304 "VDD_BATTMON", "VDD_BSTMON",
305 "DSP_TX1", "DSP_TX2",
306 "Interpolator", "IL_TARGET",
309 static const unsigned int cs35l45_asp_tx_val
[] = {
310 CS35L45_PCM_SRC_ZERO
, CS35L45_PCM_SRC_ASP_RX1
, CS35L45_PCM_SRC_ASP_RX2
,
311 CS35L45_PCM_SRC_VMON
, CS35L45_PCM_SRC_IMON
, CS35L45_PCM_SRC_ERR_VOL
,
312 CS35L45_PCM_SRC_VDD_BATTMON
, CS35L45_PCM_SRC_VDD_BSTMON
,
313 CS35L45_PCM_SRC_DSP_TX1
, CS35L45_PCM_SRC_DSP_TX2
,
314 CS35L45_PCM_SRC_INTERPOLATOR
, CS35L45_PCM_SRC_IL_TARGET
,
317 static const struct soc_enum cs35l45_asp_tx_enums
[] = {
318 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
319 ARRAY_SIZE(cs35l45_asp_tx_txt
), cs35l45_asp_tx_txt
,
321 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
322 ARRAY_SIZE(cs35l45_asp_tx_txt
), cs35l45_asp_tx_txt
,
324 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX3_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
325 ARRAY_SIZE(cs35l45_asp_tx_txt
), cs35l45_asp_tx_txt
,
327 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
328 ARRAY_SIZE(cs35l45_asp_tx_txt
), cs35l45_asp_tx_txt
,
330 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
331 ARRAY_SIZE(cs35l45_asp_tx_txt
), cs35l45_asp_tx_txt
,
335 static const char * const cs35l45_dsp_rx_txt
[] = {
336 "Zero", "ASP_RX1", "ASP_RX2",
337 "VMON", "IMON", "ERR_VOL",
338 "CLASSH_TGT", "VDD_BATTMON",
339 "VDD_BSTMON", "TEMPMON",
342 static const unsigned int cs35l45_dsp_rx_val
[] = {
343 CS35L45_PCM_SRC_ZERO
, CS35L45_PCM_SRC_ASP_RX1
, CS35L45_PCM_SRC_ASP_RX2
,
344 CS35L45_PCM_SRC_VMON
, CS35L45_PCM_SRC_IMON
, CS35L45_PCM_SRC_ERR_VOL
,
345 CS35L45_PCM_SRC_CLASSH_TGT
, CS35L45_PCM_SRC_VDD_BATTMON
,
346 CS35L45_PCM_SRC_VDD_BSTMON
, CS35L45_PCM_SRC_TEMPMON
,
349 static const struct soc_enum cs35l45_dsp_rx_enums
[] = {
350 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX1_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
351 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
353 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX2_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
354 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
356 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX3_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
357 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
359 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX4_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
360 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
362 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX5_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
363 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
365 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX6_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
366 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
368 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX7_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
369 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
371 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX8_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
372 ARRAY_SIZE(cs35l45_dsp_rx_txt
), cs35l45_dsp_rx_txt
,
376 static const char * const cs35l45_dac_txt
[] = {
377 "Zero", "ASP_RX1", "ASP_RX2", "DSP_TX1", "DSP_TX2"
380 static const unsigned int cs35l45_dac_val
[] = {
381 CS35L45_PCM_SRC_ZERO
, CS35L45_PCM_SRC_ASP_RX1
, CS35L45_PCM_SRC_ASP_RX2
,
382 CS35L45_PCM_SRC_DSP_TX1
, CS35L45_PCM_SRC_DSP_TX2
385 static const struct soc_enum cs35l45_dacpcm_enums
[] = {
386 SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT
, 0, CS35L45_PCM_SRC_MASK
,
387 ARRAY_SIZE(cs35l45_dac_txt
), cs35l45_dac_txt
,
391 static const struct snd_kcontrol_new cs35l45_asp_muxes
[] = {
392 SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums
[0]),
393 SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums
[1]),
394 SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums
[2]),
395 SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums
[3]),
396 SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums
[4]),
399 static const struct snd_kcontrol_new cs35l45_dsp_muxes
[] = {
400 SOC_DAPM_ENUM("DSP_RX1 Source", cs35l45_dsp_rx_enums
[0]),
401 SOC_DAPM_ENUM("DSP_RX2 Source", cs35l45_dsp_rx_enums
[1]),
402 SOC_DAPM_ENUM("DSP_RX3 Source", cs35l45_dsp_rx_enums
[2]),
403 SOC_DAPM_ENUM("DSP_RX4 Source", cs35l45_dsp_rx_enums
[3]),
404 SOC_DAPM_ENUM("DSP_RX5 Source", cs35l45_dsp_rx_enums
[4]),
405 SOC_DAPM_ENUM("DSP_RX6 Source", cs35l45_dsp_rx_enums
[5]),
406 SOC_DAPM_ENUM("DSP_RX7 Source", cs35l45_dsp_rx_enums
[6]),
407 SOC_DAPM_ENUM("DSP_RX8 Source", cs35l45_dsp_rx_enums
[7]),
410 static const struct snd_kcontrol_new cs35l45_dac_muxes
[] = {
411 SOC_DAPM_ENUM("DACPCM Source", cs35l45_dacpcm_enums
[0]),
413 static const struct snd_kcontrol_new amp_en_ctl
=
414 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM
, 0, 1, 0);
416 static const struct snd_soc_dapm_widget cs35l45_dapm_widgets
[] = {
417 SND_SOC_DAPM_SPK("DSP1 Preload", NULL
),
418 SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, SND_SOC_NOPM
, 0, 0,
419 cs35l45_dsp_preload_ev
,
420 SND_SOC_DAPM_PRE_PMU
| SND_SOC_DAPM_POST_PMU
| SND_SOC_DAPM_PRE_PMD
),
421 SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM
, 0, 0, NULL
, 0,
422 cs35l45_dsp_audio_ev
,
423 SND_SOC_DAPM_POST_PMU
| SND_SOC_DAPM_PRE_PMD
),
424 SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM
, 0, 0,
425 cs35l45_global_en_ev
,
426 SND_SOC_DAPM_POST_PMU
| SND_SOC_DAPM_PRE_PMD
),
427 SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2
, CS35L45_ASP_EN_SHIFT
, 0, NULL
, 0),
429 SND_SOC_DAPM_SIGGEN("VMON_SRC"),
430 SND_SOC_DAPM_SIGGEN("IMON_SRC"),
431 SND_SOC_DAPM_SIGGEN("TEMPMON_SRC"),
432 SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"),
433 SND_SOC_DAPM_SIGGEN("VDD_BSTMON_SRC"),
434 SND_SOC_DAPM_SIGGEN("ERR_VOL"),
435 SND_SOC_DAPM_SIGGEN("AMP_INTP"),
436 SND_SOC_DAPM_SIGGEN("IL_TARGET"),
438 SND_SOC_DAPM_SUPPLY("VMON_EN", CS35L45_BLOCK_ENABLES
, CS35L45_VMON_EN_SHIFT
, 0, NULL
, 0),
439 SND_SOC_DAPM_SUPPLY("IMON_EN", CS35L45_BLOCK_ENABLES
, CS35L45_IMON_EN_SHIFT
, 0, NULL
, 0),
440 SND_SOC_DAPM_SUPPLY("TEMPMON_EN", CS35L45_BLOCK_ENABLES
, CS35L45_TEMPMON_EN_SHIFT
, 0, NULL
, 0),
441 SND_SOC_DAPM_SUPPLY("VDD_BATTMON_EN", CS35L45_BLOCK_ENABLES
, CS35L45_VDD_BATTMON_EN_SHIFT
, 0, NULL
, 0),
442 SND_SOC_DAPM_SUPPLY("VDD_BSTMON_EN", CS35L45_BLOCK_ENABLES
, CS35L45_VDD_BSTMON_EN_SHIFT
, 0, NULL
, 0),
444 SND_SOC_DAPM_ADC("VMON", NULL
, SND_SOC_NOPM
, 0, 0),
445 SND_SOC_DAPM_ADC("IMON", NULL
, SND_SOC_NOPM
, 0, 0),
446 SND_SOC_DAPM_ADC("TEMPMON", NULL
, SND_SOC_NOPM
, 0, 0),
447 SND_SOC_DAPM_ADC("VDD_BATTMON", NULL
, SND_SOC_NOPM
, 0, 0),
448 SND_SOC_DAPM_ADC("VDD_BSTMON", NULL
, SND_SOC_NOPM
, 0, 0),
451 SND_SOC_DAPM_AIF_IN("ASP_RX1", NULL
, 0, CS35L45_ASP_ENABLES1
, CS35L45_ASP_RX1_EN_SHIFT
, 0),
452 SND_SOC_DAPM_AIF_IN("ASP_RX2", NULL
, 1, CS35L45_ASP_ENABLES1
, CS35L45_ASP_RX2_EN_SHIFT
, 0),
454 SND_SOC_DAPM_AIF_OUT("ASP_TX1", NULL
, 0, CS35L45_ASP_ENABLES1
, CS35L45_ASP_TX1_EN_SHIFT
, 0),
455 SND_SOC_DAPM_AIF_OUT("ASP_TX2", NULL
, 1, CS35L45_ASP_ENABLES1
, CS35L45_ASP_TX2_EN_SHIFT
, 0),
456 SND_SOC_DAPM_AIF_OUT("ASP_TX3", NULL
, 2, CS35L45_ASP_ENABLES1
, CS35L45_ASP_TX3_EN_SHIFT
, 0),
457 SND_SOC_DAPM_AIF_OUT("ASP_TX4", NULL
, 3, CS35L45_ASP_ENABLES1
, CS35L45_ASP_TX4_EN_SHIFT
, 0),
458 SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL
, 3, CS35L45_ASP_ENABLES1
, CS35L45_ASP_TX5_EN_SHIFT
, 0),
460 SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_asp_muxes
[0]),
461 SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_asp_muxes
[1]),
462 SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_asp_muxes
[2]),
463 SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_asp_muxes
[3]),
464 SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_asp_muxes
[4]),
466 SND_SOC_DAPM_MUX("DSP_RX1 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[0]),
467 SND_SOC_DAPM_MUX("DSP_RX2 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[1]),
468 SND_SOC_DAPM_MUX("DSP_RX3 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[2]),
469 SND_SOC_DAPM_MUX("DSP_RX4 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[3]),
470 SND_SOC_DAPM_MUX("DSP_RX5 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[4]),
471 SND_SOC_DAPM_MUX("DSP_RX6 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[5]),
472 SND_SOC_DAPM_MUX("DSP_RX7 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[6]),
473 SND_SOC_DAPM_MUX("DSP_RX8 Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dsp_muxes
[7]),
475 SND_SOC_DAPM_MUX("DACPCM Source", SND_SOC_NOPM
, 0, 0, &cs35l45_dac_muxes
[0]),
477 SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM
, 0, 0, &_en_ctl
),
479 SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM
, 0, 0, NULL
, 0),
481 SND_SOC_DAPM_OUTPUT("SPK"),
484 #define CS35L45_ASP_MUX_ROUTE(name) \
485 { name" Source", "ASP_RX1", "ASP_RX1" }, \
486 { name" Source", "ASP_RX2", "ASP_RX2" }, \
487 { name" Source", "DSP_TX1", "DSP1" }, \
488 { name" Source", "DSP_TX2", "DSP1" }, \
489 { name" Source", "VMON", "VMON" }, \
490 { name" Source", "IMON", "IMON" }, \
491 { name" Source", "ERR_VOL", "ERR_VOL" }, \
492 { name" Source", "VDD_BATTMON", "VDD_BATTMON" }, \
493 { name" Source", "VDD_BSTMON", "VDD_BSTMON" }, \
494 { name" Source", "Interpolator", "AMP_INTP" }, \
495 { name" Source", "IL_TARGET", "IL_TARGET" }
497 #define CS35L45_DSP_MUX_ROUTE(name) \
498 { name" Source", "ASP_RX1", "ASP_RX1" }, \
499 { name" Source", "ASP_RX2", "ASP_RX2" }
501 #define CS35L45_DAC_MUX_ROUTE(name) \
502 { name" Source", "ASP_RX1", "ASP_RX1" }, \
503 { name" Source", "ASP_RX2", "ASP_RX2" }, \
504 { name" Source", "DSP_TX1", "DSP1" }, \
505 { name" Source", "DSP_TX2", "DSP1" }
507 static const struct snd_soc_dapm_route cs35l45_dapm_routes
[] = {
509 { "VMON", NULL
, "VMON_SRC" },
510 { "IMON", NULL
, "IMON_SRC" },
511 { "TEMPMON", NULL
, "TEMPMON_SRC" },
512 { "VDD_BATTMON", NULL
, "VDD_BATTMON_SRC" },
513 { "VDD_BSTMON", NULL
, "VDD_BSTMON_SRC" },
515 { "VMON", NULL
, "VMON_EN" },
516 { "IMON", NULL
, "IMON_EN" },
517 { "TEMPMON", NULL
, "TEMPMON_EN" },
518 { "VDD_BATTMON", NULL
, "VDD_BATTMON_EN" },
519 { "VDD_BSTMON", NULL
, "VDD_BSTMON_EN" },
521 { "Capture", NULL
, "ASP_TX1"},
522 { "Capture", NULL
, "ASP_TX2"},
523 { "Capture", NULL
, "ASP_TX3"},
524 { "Capture", NULL
, "ASP_TX4"},
525 { "Capture", NULL
, "ASP_TX5"},
526 { "ASP_TX1", NULL
, "ASP_TX1 Source"},
527 { "ASP_TX2", NULL
, "ASP_TX2 Source"},
528 { "ASP_TX3", NULL
, "ASP_TX3 Source"},
529 { "ASP_TX4", NULL
, "ASP_TX4 Source"},
530 { "ASP_TX5", NULL
, "ASP_TX5 Source"},
532 { "ASP_TX1", NULL
, "ASP_EN" },
533 { "ASP_TX2", NULL
, "ASP_EN" },
534 { "ASP_TX3", NULL
, "ASP_EN" },
535 { "ASP_TX4", NULL
, "ASP_EN" },
536 { "ASP_TX1", NULL
, "GLOBAL_EN" },
537 { "ASP_TX2", NULL
, "GLOBAL_EN" },
538 { "ASP_TX3", NULL
, "GLOBAL_EN" },
539 { "ASP_TX4", NULL
, "GLOBAL_EN" },
540 { "ASP_TX5", NULL
, "GLOBAL_EN" },
542 CS35L45_ASP_MUX_ROUTE("ASP_TX1"),
543 CS35L45_ASP_MUX_ROUTE("ASP_TX2"),
544 CS35L45_ASP_MUX_ROUTE("ASP_TX3"),
545 CS35L45_ASP_MUX_ROUTE("ASP_TX4"),
546 CS35L45_ASP_MUX_ROUTE("ASP_TX5"),
549 { "ASP_RX1", NULL
, "Playback" },
550 { "ASP_RX2", NULL
, "Playback" },
551 { "ASP_RX1", NULL
, "ASP_EN" },
552 { "ASP_RX2", NULL
, "ASP_EN" },
554 { "AMP", NULL
, "DACPCM Source"},
555 { "AMP", NULL
, "GLOBAL_EN"},
557 CS35L45_DSP_MUX_ROUTE("DSP_RX1"),
558 CS35L45_DSP_MUX_ROUTE("DSP_RX2"),
559 CS35L45_DSP_MUX_ROUTE("DSP_RX3"),
560 CS35L45_DSP_MUX_ROUTE("DSP_RX4"),
561 CS35L45_DSP_MUX_ROUTE("DSP_RX5"),
562 CS35L45_DSP_MUX_ROUTE("DSP_RX6"),
563 CS35L45_DSP_MUX_ROUTE("DSP_RX7"),
564 CS35L45_DSP_MUX_ROUTE("DSP_RX8"),
566 {"DSP1", NULL
, "DSP_RX1 Source"},
567 {"DSP1", NULL
, "DSP_RX2 Source"},
568 {"DSP1", NULL
, "DSP_RX3 Source"},
569 {"DSP1", NULL
, "DSP_RX4 Source"},
570 {"DSP1", NULL
, "DSP_RX5 Source"},
571 {"DSP1", NULL
, "DSP_RX6 Source"},
572 {"DSP1", NULL
, "DSP_RX7 Source"},
573 {"DSP1", NULL
, "DSP_RX8 Source"},
575 {"DSP1", NULL
, "VMON_EN"},
576 {"DSP1", NULL
, "IMON_EN"},
577 {"DSP1", NULL
, "VDD_BATTMON_EN"},
578 {"DSP1", NULL
, "VDD_BSTMON_EN"},
579 {"DSP1", NULL
, "TEMPMON_EN"},
581 {"DSP1 Preload", NULL
, "DSP1 Preloader"},
582 {"DSP1", NULL
, "DSP1 Preloader"},
584 CS35L45_DAC_MUX_ROUTE("DACPCM"),
586 { "AMP Enable", "Switch", "AMP" },
587 { "SPK", NULL
, "AMP Enable"},
590 static const char * const amplifier_mode_texts
[] = {"SPK", "RCV"};
591 static SOC_ENUM_SINGLE_DECL(amplifier_mode_enum
, SND_SOC_NOPM
, 0,
592 amplifier_mode_texts
);
593 static DECLARE_TLV_DB_SCALE(amp_gain_tlv
, 1000, 300, 0);
594 static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv
, -10225, 25, true);
596 static const struct snd_kcontrol_new cs35l45_controls
[] = {
597 SOC_ENUM_EXT("Amplifier Mode", amplifier_mode_enum
,
598 cs35l45_amplifier_mode_get
, cs35l45_amplifier_mode_put
),
599 SOC_SINGLE_TLV("Analog PCM Volume", CS35L45_AMP_GAIN
,
600 CS35L45_AMP_GAIN_PCM_SHIFT
,
601 CS35L45_AMP_GAIN_PCM_MASK
>> CS35L45_AMP_GAIN_PCM_SHIFT
,
603 /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */
604 SOC_SINGLE_S_TLV("Digital PCM Volume",
605 CS35L45_AMP_PCM_CONTROL
,
606 CS35L45_AMP_VOL_PCM_SHIFT
+ 1,
608 (CS35L45_AMP_VOL_PCM_WIDTH
- 1) - 1,
609 0, cs35l45_dig_pcm_vol_tlv
),
610 WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
611 WM_ADSP_FW_CONTROL("DSP1", 0),
614 static int cs35l45_set_pll(struct cs35l45_private
*cs35l45
, unsigned int freq
)
619 freq_id
= cs35l45_get_clk_freq_id(freq
);
621 dev_err(cs35l45
->dev
, "Invalid freq: %u\n", freq
);
625 regmap_read(cs35l45
->regmap
, CS35L45_REFCLK_INPUT
, &val
);
626 val
= (val
& CS35L45_PLL_REFCLK_FREQ_MASK
) >> CS35L45_PLL_REFCLK_FREQ_SHIFT
;
630 regmap_set_bits(cs35l45
->regmap
, CS35L45_REFCLK_INPUT
, CS35L45_PLL_OPEN_LOOP_MASK
);
631 regmap_update_bits(cs35l45
->regmap
, CS35L45_REFCLK_INPUT
,
632 CS35L45_PLL_REFCLK_FREQ_MASK
,
633 freq_id
<< CS35L45_PLL_REFCLK_FREQ_SHIFT
);
634 regmap_clear_bits(cs35l45
->regmap
, CS35L45_REFCLK_INPUT
, CS35L45_PLL_REFCLK_EN_MASK
);
635 regmap_clear_bits(cs35l45
->regmap
, CS35L45_REFCLK_INPUT
, CS35L45_PLL_OPEN_LOOP_MASK
);
636 regmap_set_bits(cs35l45
->regmap
, CS35L45_REFCLK_INPUT
, CS35L45_PLL_REFCLK_EN_MASK
);
641 static int cs35l45_asp_set_fmt(struct snd_soc_dai
*codec_dai
, unsigned int fmt
)
643 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(codec_dai
->component
);
644 unsigned int asp_fmt
, fsync_inv
, bclk_inv
;
646 switch (fmt
& SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK
) {
647 case SND_SOC_DAIFMT_CBC_CFC
:
650 dev_err(cs35l45
->dev
, "Invalid DAI clocking\n");
654 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
655 case SND_SOC_DAIFMT_DSP_A
:
656 asp_fmt
= CS35l45_ASP_FMT_DSP_A
;
658 case SND_SOC_DAIFMT_I2S
:
659 asp_fmt
= CS35L45_ASP_FMT_I2S
;
662 dev_err(cs35l45
->dev
, "Invalid DAI format\n");
666 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
667 case SND_SOC_DAIFMT_NB_IF
:
671 case SND_SOC_DAIFMT_IB_NF
:
675 case SND_SOC_DAIFMT_IB_IF
:
679 case SND_SOC_DAIFMT_NB_NF
:
684 dev_warn(cs35l45
->dev
, "Invalid DAI clock polarity\n");
688 regmap_update_bits(cs35l45
->regmap
, CS35L45_ASP_CONTROL2
,
689 CS35L45_ASP_FMT_MASK
|
690 CS35L45_ASP_FSYNC_INV_MASK
|
691 CS35L45_ASP_BCLK_INV_MASK
,
692 (asp_fmt
<< CS35L45_ASP_FMT_SHIFT
) |
693 (fsync_inv
<< CS35L45_ASP_FSYNC_INV_SHIFT
) |
694 (bclk_inv
<< CS35L45_ASP_BCLK_INV_SHIFT
));
699 static int cs35l45_asp_hw_params(struct snd_pcm_substream
*substream
,
700 struct snd_pcm_hw_params
*params
,
701 struct snd_soc_dai
*dai
)
703 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(dai
->component
);
704 unsigned int asp_width
, asp_wl
, global_fs
, slot_multiple
, asp_fmt
;
707 switch (params_rate(params
)) {
709 global_fs
= CS35L45_44P100_KHZ
;
712 global_fs
= CS35L45_48P0_KHZ
;
715 global_fs
= CS35L45_88P200_KHZ
;
718 global_fs
= CS35L45_96P0_KHZ
;
721 dev_warn(cs35l45
->dev
, "Unsupported sample rate (%d)\n",
722 params_rate(params
));
726 regmap_update_bits(cs35l45
->regmap
, CS35L45_GLOBAL_SAMPLE_RATE
,
727 CS35L45_GLOBAL_FS_MASK
,
728 global_fs
<< CS35L45_GLOBAL_FS_SHIFT
);
730 asp_wl
= params_width(params
);
732 if (cs35l45
->slot_width
)
733 asp_width
= cs35l45
->slot_width
;
735 asp_width
= params_width(params
);
737 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
738 regmap_update_bits(cs35l45
->regmap
, CS35L45_ASP_CONTROL2
,
739 CS35L45_ASP_WIDTH_RX_MASK
,
740 asp_width
<< CS35L45_ASP_WIDTH_RX_SHIFT
);
742 regmap_update_bits(cs35l45
->regmap
, CS35L45_ASP_DATA_CONTROL5
,
744 asp_wl
<< CS35L45_ASP_WL_SHIFT
);
746 regmap_update_bits(cs35l45
->regmap
, CS35L45_ASP_CONTROL2
,
747 CS35L45_ASP_WIDTH_TX_MASK
,
748 asp_width
<< CS35L45_ASP_WIDTH_TX_SHIFT
);
750 regmap_update_bits(cs35l45
->regmap
, CS35L45_ASP_DATA_CONTROL1
,
752 asp_wl
<< CS35L45_ASP_WL_SHIFT
);
755 if (cs35l45
->sysclk_set
)
758 /* I2S always has an even number of channels */
759 regmap_read(cs35l45
->regmap
, CS35L45_ASP_CONTROL2
, &asp_fmt
);
760 asp_fmt
= (asp_fmt
& CS35L45_ASP_FMT_MASK
) >> CS35L45_ASP_FMT_SHIFT
;
761 if (asp_fmt
== CS35L45_ASP_FMT_I2S
)
766 bclk
= snd_soc_tdm_params_to_bclk(params
, asp_width
,
767 cs35l45
->slot_count
, slot_multiple
);
769 return cs35l45_set_pll(cs35l45
, bclk
);
772 static int cs35l45_asp_set_tdm_slot(struct snd_soc_dai
*dai
,
773 unsigned int tx_mask
, unsigned int rx_mask
,
774 int slots
, int slot_width
)
776 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(dai
->component
);
778 if (slot_width
&& ((slot_width
< 16) || (slot_width
> 128)))
781 cs35l45
->slot_width
= slot_width
;
782 cs35l45
->slot_count
= slots
;
787 static int cs35l45_asp_set_sysclk(struct snd_soc_dai
*dai
,
788 int clk_id
, unsigned int freq
, int dir
)
790 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(dai
->component
);
794 dev_err(cs35l45
->dev
, "Invalid clk_id %d\n", clk_id
);
798 cs35l45
->sysclk_set
= false;
802 ret
= cs35l45_set_pll(cs35l45
, freq
);
806 cs35l45
->sysclk_set
= true;
811 static int cs35l45_mute_stream(struct snd_soc_dai
*dai
, int mute
, int stream
)
813 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(dai
->component
);
814 unsigned int global_fs
, val
, hpf_tune
;
819 regmap_read(cs35l45
->regmap
, CS35L45_GLOBAL_SAMPLE_RATE
, &global_fs
);
820 global_fs
= (global_fs
& CS35L45_GLOBAL_FS_MASK
) >> CS35L45_GLOBAL_FS_SHIFT
;
822 case CS35L45_44P100_KHZ
:
823 hpf_tune
= CS35L45_HPF_44P1
;
825 case CS35L45_88P200_KHZ
:
826 hpf_tune
= CS35L45_HPF_88P2
;
829 hpf_tune
= CS35l45_HPF_DEFAULT
;
833 regmap_read(cs35l45
->regmap
, CS35L45_AMP_PCM_HPF_TST
, &val
);
834 if (val
!= hpf_tune
) {
835 struct reg_sequence hpf_override_seq
[] = {
836 { 0x00000040, 0x00000055 },
837 { 0x00000040, 0x000000AA },
838 { 0x00000044, 0x00000055 },
839 { 0x00000044, 0x000000AA },
840 { CS35L45_AMP_PCM_HPF_TST
, hpf_tune
},
841 { 0x00000040, 0x00000000 },
842 { 0x00000044, 0x00000000 },
844 regmap_multi_reg_write(cs35l45
->regmap
, hpf_override_seq
,
845 ARRAY_SIZE(hpf_override_seq
));
851 static const struct snd_soc_dai_ops cs35l45_asp_dai_ops
= {
852 .set_fmt
= cs35l45_asp_set_fmt
,
853 .hw_params
= cs35l45_asp_hw_params
,
854 .set_tdm_slot
= cs35l45_asp_set_tdm_slot
,
855 .set_sysclk
= cs35l45_asp_set_sysclk
,
856 .mute_stream
= cs35l45_mute_stream
,
859 static struct snd_soc_dai_driver cs35l45_dai
[] = {
863 .stream_name
= "Playback",
866 .rates
= CS35L45_RATES
,
867 .formats
= CS35L45_FORMATS
,
870 .stream_name
= "Capture",
873 .rates
= CS35L45_RATES
,
874 .formats
= CS35L45_FORMATS
,
876 .symmetric_rate
= true,
877 .symmetric_sample_bits
= true,
878 .ops
= &cs35l45_asp_dai_ops
,
882 static int cs35l45_component_probe(struct snd_soc_component
*component
)
884 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(component
);
886 return wm_adsp2_component_probe(&cs35l45
->dsp
, component
);
889 static void cs35l45_component_remove(struct snd_soc_component
*component
)
891 struct cs35l45_private
*cs35l45
= snd_soc_component_get_drvdata(component
);
893 wm_adsp2_component_remove(&cs35l45
->dsp
, component
);
896 static const struct snd_soc_component_driver cs35l45_component
= {
897 .probe
= cs35l45_component_probe
,
898 .remove
= cs35l45_component_remove
,
900 .dapm_widgets
= cs35l45_dapm_widgets
,
901 .num_dapm_widgets
= ARRAY_SIZE(cs35l45_dapm_widgets
),
903 .dapm_routes
= cs35l45_dapm_routes
,
904 .num_dapm_routes
= ARRAY_SIZE(cs35l45_dapm_routes
),
906 .controls
= cs35l45_controls
,
907 .num_controls
= ARRAY_SIZE(cs35l45_controls
),
914 static void cs35l45_setup_hibernate(struct cs35l45_private
*cs35l45
)
918 if (cs35l45
->bus_type
== CONTROL_BUS_I2C
)
919 wksrc
= CS35L45_WKSRC_I2C
;
921 wksrc
= CS35L45_WKSRC_SPI
;
923 regmap_update_bits(cs35l45
->regmap
, CS35L45_WAKESRC_CTL
,
924 CS35L45_WKSRC_EN_MASK
,
925 wksrc
<< CS35L45_WKSRC_EN_SHIFT
);
927 regmap_set_bits(cs35l45
->regmap
, CS35L45_WAKESRC_CTL
,
928 CS35L45_UPDT_WKCTL_MASK
);
930 regmap_update_bits(cs35l45
->regmap
, CS35L45_WKI2C_CTL
,
931 CS35L45_WKI2C_ADDR_MASK
, cs35l45
->i2c_addr
);
933 regmap_set_bits(cs35l45
->regmap
, CS35L45_WKI2C_CTL
,
934 CS35L45_UPDT_WKI2C_MASK
);
937 static int cs35l45_enter_hibernate(struct cs35l45_private
*cs35l45
)
939 dev_dbg(cs35l45
->dev
, "Enter hibernate\n");
941 cs35l45_setup_hibernate(cs35l45
);
943 regmap_set_bits(cs35l45
->regmap
, CS35L45_IRQ1_MASK_2
, CS35L45_DSP_VIRT2_MBOX_MASK
);
945 // Don't wait for ACK since bus activity would wake the device
946 regmap_write(cs35l45
->regmap
, CS35L45_DSP_VIRT1_MBOX_1
, CSPL_MBOX_CMD_HIBERNATE
);
951 static int cs35l45_exit_hibernate(struct cs35l45_private
*cs35l45
)
953 const int wake_retries
= 20;
954 const int sleep_retries
= 5;
957 for (i
= 0; i
< sleep_retries
; i
++) {
958 dev_dbg(cs35l45
->dev
, "Exit hibernate\n");
960 for (j
= 0; j
< wake_retries
; j
++) {
961 ret
= cs35l45_set_cspl_mbox_cmd(cs35l45
, cs35l45
->regmap
,
962 CSPL_MBOX_CMD_OUT_OF_HIBERNATE
);
964 dev_dbg(cs35l45
->dev
, "Wake success at cycle: %d\n", j
);
965 regmap_clear_bits(cs35l45
->regmap
, CS35L45_IRQ1_MASK_2
,
966 CS35L45_DSP_VIRT2_MBOX_MASK
);
969 usleep_range(100, 200);
972 dev_err(cs35l45
->dev
, "Wake failed, re-enter hibernate: %d\n", ret
);
974 cs35l45_setup_hibernate(cs35l45
);
977 dev_err(cs35l45
->dev
, "Timed out waking device\n");
982 static int cs35l45_runtime_suspend(struct device
*dev
)
984 struct cs35l45_private
*cs35l45
= dev_get_drvdata(dev
);
986 if (!cs35l45
->dsp
.preloaded
|| !cs35l45
->dsp
.cs_dsp
.running
)
989 cs35l45_enter_hibernate(cs35l45
);
991 regcache_cache_only(cs35l45
->regmap
, true);
992 regcache_mark_dirty(cs35l45
->regmap
);
994 dev_dbg(cs35l45
->dev
, "Runtime suspended\n");
999 static int cs35l45_runtime_resume(struct device
*dev
)
1001 struct cs35l45_private
*cs35l45
= dev_get_drvdata(dev
);
1004 if (!cs35l45
->dsp
.preloaded
|| !cs35l45
->dsp
.cs_dsp
.running
)
1007 dev_dbg(cs35l45
->dev
, "Runtime resume\n");
1009 regcache_cache_only(cs35l45
->regmap
, false);
1011 ret
= cs35l45_exit_hibernate(cs35l45
);
1015 ret
= regcache_sync(cs35l45
->regmap
);
1017 dev_warn(cs35l45
->dev
, "regcache_sync failed: %d\n", ret
);
1019 /* Clear global error status */
1020 regmap_clear_bits(cs35l45
->regmap
, CS35L45_ERROR_RELEASE
, CS35L45_GLOBAL_ERR_RLS_MASK
);
1021 regmap_set_bits(cs35l45
->regmap
, CS35L45_ERROR_RELEASE
, CS35L45_GLOBAL_ERR_RLS_MASK
);
1022 regmap_clear_bits(cs35l45
->regmap
, CS35L45_ERROR_RELEASE
, CS35L45_GLOBAL_ERR_RLS_MASK
);
1026 static int cs35l45_sys_suspend(struct device
*dev
)
1028 struct cs35l45_private
*cs35l45
= dev_get_drvdata(dev
);
1030 dev_dbg(cs35l45
->dev
, "System suspend, disabling IRQ\n");
1031 disable_irq(cs35l45
->irq
);
1036 static int cs35l45_sys_suspend_noirq(struct device
*dev
)
1038 struct cs35l45_private
*cs35l45
= dev_get_drvdata(dev
);
1040 dev_dbg(cs35l45
->dev
, "Late system suspend, reenabling IRQ\n");
1041 enable_irq(cs35l45
->irq
);
1046 static int cs35l45_sys_resume_noirq(struct device
*dev
)
1048 struct cs35l45_private
*cs35l45
= dev_get_drvdata(dev
);
1050 dev_dbg(cs35l45
->dev
, "Early system resume, disabling IRQ\n");
1051 disable_irq(cs35l45
->irq
);
1056 static int cs35l45_sys_resume(struct device
*dev
)
1058 struct cs35l45_private
*cs35l45
= dev_get_drvdata(dev
);
1060 dev_dbg(cs35l45
->dev
, "System resume, reenabling IRQ\n");
1061 enable_irq(cs35l45
->irq
);
1066 static int cs35l45_apply_property_config(struct cs35l45_private
*cs35l45
)
1068 struct device_node
*node
= cs35l45
->dev
->of_node
;
1069 unsigned int gpio_regs
[] = {CS35L45_GPIO1_CTRL1
, CS35L45_GPIO2_CTRL1
,
1070 CS35L45_GPIO3_CTRL1
};
1071 unsigned int pad_regs
[] = {CS35L45_SYNC_GPIO1
,
1072 CS35L45_INTB_GPIO2_MCLK_REF
, CS35L45_GPIO3
};
1073 struct device_node
*child
;
1081 for (i
= 0; i
< CS35L45_NUM_GPIOS
; i
++) {
1082 sprintf(of_name
, "cirrus,gpio-ctrl%d", i
+ 1);
1083 child
= of_get_child_by_name(node
, of_name
);
1087 ret
= of_property_read_u32(child
, "gpio-dir", &val
);
1089 regmap_update_bits(cs35l45
->regmap
, gpio_regs
[i
],
1090 CS35L45_GPIO_DIR_MASK
,
1091 val
<< CS35L45_GPIO_DIR_SHIFT
);
1093 ret
= of_property_read_u32(child
, "gpio-lvl", &val
);
1095 regmap_update_bits(cs35l45
->regmap
, gpio_regs
[i
],
1096 CS35L45_GPIO_LVL_MASK
,
1097 val
<< CS35L45_GPIO_LVL_SHIFT
);
1099 ret
= of_property_read_u32(child
, "gpio-op-cfg", &val
);
1101 regmap_update_bits(cs35l45
->regmap
, gpio_regs
[i
],
1102 CS35L45_GPIO_OP_CFG_MASK
,
1103 val
<< CS35L45_GPIO_OP_CFG_SHIFT
);
1105 ret
= of_property_read_u32(child
, "gpio-pol", &val
);
1107 regmap_update_bits(cs35l45
->regmap
, gpio_regs
[i
],
1108 CS35L45_GPIO_POL_MASK
,
1109 val
<< CS35L45_GPIO_POL_SHIFT
);
1111 ret
= of_property_read_u32(child
, "gpio-ctrl", &val
);
1113 regmap_update_bits(cs35l45
->regmap
, pad_regs
[i
],
1114 CS35L45_GPIO_CTRL_MASK
,
1115 val
<< CS35L45_GPIO_CTRL_SHIFT
);
1117 ret
= of_property_read_u32(child
, "gpio-invert", &val
);
1119 regmap_update_bits(cs35l45
->regmap
, pad_regs
[i
],
1120 CS35L45_GPIO_INVERT_MASK
,
1121 val
<< CS35L45_GPIO_INVERT_SHIFT
);
1123 cs35l45
->irq_invert
= val
;
1129 if (device_property_read_u32(cs35l45
->dev
,
1130 "cirrus,asp-sdout-hiz-ctrl", &val
) == 0) {
1131 regmap_update_bits(cs35l45
->regmap
, CS35L45_ASP_CONTROL3
,
1132 CS35L45_ASP_DOUT_HIZ_CTRL_MASK
,
1133 val
<< CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT
);
1139 static int cs35l45_dsp_virt2_mbox3_irq_handle(struct cs35l45_private
*cs35l45
,
1140 const unsigned int cmd
,
1143 static char *speak_status
= "Unknown";
1146 case EVENT_SPEAKER_STATUS
:
1149 speak_status
= "All Clear";
1152 speak_status
= "Open Circuit";
1155 speak_status
= "Short Circuit";
1159 dev_info(cs35l45
->dev
, "MBOX event (SPEAKER_STATUS): %s\n",
1162 case EVENT_BOOT_DONE
:
1163 dev_dbg(cs35l45
->dev
, "MBOX event (BOOT_DONE)\n");
1166 dev_err(cs35l45
->dev
, "MBOX event not supported %u\n", cmd
);
1173 static irqreturn_t
cs35l45_dsp_virt2_mbox_cb(int irq
, void *data
)
1175 struct cs35l45_private
*cs35l45
= data
;
1176 unsigned int mbox_val
;
1179 ret
= regmap_read(cs35l45
->regmap
, CS35L45_DSP_VIRT2_MBOX_3
, &mbox_val
);
1180 if (!ret
&& mbox_val
)
1181 cs35l45_dsp_virt2_mbox3_irq_handle(cs35l45
, mbox_val
& CS35L45_MBOX3_CMD_MASK
,
1182 (mbox_val
& CS35L45_MBOX3_DATA_MASK
) >> CS35L45_MBOX3_DATA_SHIFT
);
1184 /* Handle DSP trace log IRQ */
1185 ret
= regmap_read(cs35l45
->regmap
, CS35L45_DSP_VIRT2_MBOX_4
, &mbox_val
);
1186 if (!ret
&& mbox_val
!= 0) {
1187 dev_err(cs35l45
->dev
, "Spurious DSP MBOX4 IRQ\n");
1190 return IRQ_RETVAL(ret
);
1193 static irqreturn_t
cs35l45_pll_unlock(int irq
, void *data
)
1195 struct cs35l45_private
*cs35l45
= data
;
1197 dev_dbg(cs35l45
->dev
, "PLL unlock detected!");
1202 static irqreturn_t
cs35l45_pll_lock(int irq
, void *data
)
1204 struct cs35l45_private
*cs35l45
= data
;
1206 dev_dbg(cs35l45
->dev
, "PLL lock detected!");
1211 static irqreturn_t
cs35l45_spk_safe_err(int irq
, void *data
);
1213 static const struct cs35l45_irq cs35l45_irqs
[] = {
1214 CS35L45_IRQ(AMP_SHORT_ERR
, "Amplifier short error", cs35l45_spk_safe_err
),
1215 CS35L45_IRQ(UVLO_VDDBATT_ERR
, "VDDBATT undervoltage error", cs35l45_spk_safe_err
),
1216 CS35L45_IRQ(BST_SHORT_ERR
, "Boost inductor error", cs35l45_spk_safe_err
),
1217 CS35L45_IRQ(BST_UVP_ERR
, "Boost undervoltage error", cs35l45_spk_safe_err
),
1218 CS35L45_IRQ(TEMP_ERR
, "Overtemperature error", cs35l45_spk_safe_err
),
1219 CS35L45_IRQ(AMP_CAL_ERR
, "Amplifier calibration error", cs35l45_spk_safe_err
),
1220 CS35L45_IRQ(UVLO_VDDLV_ERR
, "LV threshold detector error", cs35l45_spk_safe_err
),
1221 CS35L45_IRQ(GLOBAL_ERROR
, "Global error", cs35l45_spk_safe_err
),
1222 CS35L45_IRQ(DSP_WDT_EXPIRE
, "DSP Watchdog Timer", cs35l45_spk_safe_err
),
1223 CS35L45_IRQ(PLL_UNLOCK_FLAG_RISE
, "PLL unlock", cs35l45_pll_unlock
),
1224 CS35L45_IRQ(PLL_LOCK_FLAG
, "PLL lock", cs35l45_pll_lock
),
1225 CS35L45_IRQ(DSP_VIRT2_MBOX
, "DSP virtual MBOX 2 write flag", cs35l45_dsp_virt2_mbox_cb
),
1228 static irqreturn_t
cs35l45_spk_safe_err(int irq
, void *data
)
1230 struct cs35l45_private
*cs35l45
= data
;
1233 i
= irq
- regmap_irq_get_virq(cs35l45
->irq_data
, 0);
1235 if (i
< 0 || i
>= ARRAY_SIZE(cs35l45_irqs
))
1236 dev_err(cs35l45
->dev
, "Unspecified global error condition (%d) detected!\n", irq
);
1238 dev_err(cs35l45
->dev
, "%s condition detected!\n", cs35l45_irqs
[i
].name
);
1243 static const struct regmap_irq cs35l45_reg_irqs
[] = {
1244 CS35L45_REG_IRQ(IRQ1_EINT_1
, AMP_SHORT_ERR
),
1245 CS35L45_REG_IRQ(IRQ1_EINT_1
, UVLO_VDDBATT_ERR
),
1246 CS35L45_REG_IRQ(IRQ1_EINT_1
, BST_SHORT_ERR
),
1247 CS35L45_REG_IRQ(IRQ1_EINT_1
, BST_UVP_ERR
),
1248 CS35L45_REG_IRQ(IRQ1_EINT_1
, TEMP_ERR
),
1249 CS35L45_REG_IRQ(IRQ1_EINT_3
, AMP_CAL_ERR
),
1250 CS35L45_REG_IRQ(IRQ1_EINT_18
, UVLO_VDDLV_ERR
),
1251 CS35L45_REG_IRQ(IRQ1_EINT_18
, GLOBAL_ERROR
),
1252 CS35L45_REG_IRQ(IRQ1_EINT_2
, DSP_WDT_EXPIRE
),
1253 CS35L45_REG_IRQ(IRQ1_EINT_3
, PLL_UNLOCK_FLAG_RISE
),
1254 CS35L45_REG_IRQ(IRQ1_EINT_3
, PLL_LOCK_FLAG
),
1255 CS35L45_REG_IRQ(IRQ1_EINT_2
, DSP_VIRT2_MBOX
),
1258 static const struct regmap_irq_chip cs35l45_regmap_irq_chip
= {
1259 .name
= "cs35l45 IRQ1 Controller",
1260 .main_status
= CS35L45_IRQ1_STATUS
,
1261 .status_base
= CS35L45_IRQ1_EINT_1
,
1262 .mask_base
= CS35L45_IRQ1_MASK_1
,
1263 .ack_base
= CS35L45_IRQ1_EINT_1
,
1265 .irqs
= cs35l45_reg_irqs
,
1266 .num_irqs
= ARRAY_SIZE(cs35l45_reg_irqs
),
1270 static int cs35l45_initialize(struct cs35l45_private
*cs35l45
)
1272 struct device
*dev
= cs35l45
->dev
;
1273 unsigned int dev_id
[5];
1277 ret
= regmap_read_poll_timeout(cs35l45
->regmap
, CS35L45_IRQ1_EINT_4
, sts
,
1278 (sts
& CS35L45_OTP_BOOT_DONE_STS_MASK
),
1281 dev_err(cs35l45
->dev
, "Timeout waiting for OTP boot\n");
1285 ret
= regmap_bulk_read(cs35l45
->regmap
, CS35L45_DEVID
, dev_id
, ARRAY_SIZE(dev_id
));
1287 dev_err(cs35l45
->dev
, "Get Device ID failed: %d\n", ret
);
1291 switch (dev_id
[0]) {
1296 dev_err(cs35l45
->dev
, "Bad DEVID 0x%x\n", dev_id
[0]);
1300 dev_info(cs35l45
->dev
, "Cirrus Logic CS35L45: REVID %02X OTPID %02X\n",
1301 dev_id
[1], dev_id
[4]);
1303 regmap_write(cs35l45
->regmap
, CS35L45_IRQ1_EINT_4
,
1304 CS35L45_OTP_BOOT_DONE_STS_MASK
| CS35L45_OTP_BUSY_MASK
);
1306 ret
= cs35l45_apply_patch(cs35l45
);
1308 dev_err(dev
, "Failed to apply init patch %d\n", ret
);
1312 ret
= cs35l45_apply_property_config(cs35l45
);
1316 cs35l45
->amplifier_mode
= AMP_MODE_SPK
;
1321 static const struct reg_sequence cs35l45_fs_errata_patch
[] = {
1322 {0x02B80080, 0x00000001},
1323 {0x02B80088, 0x00000001},
1324 {0x02B80090, 0x00000001},
1325 {0x02B80098, 0x00000001},
1326 {0x02B800A0, 0x00000001},
1327 {0x02B800A8, 0x00000001},
1328 {0x02B800B0, 0x00000001},
1329 {0x02B800B8, 0x00000001},
1330 {0x02B80280, 0x00000001},
1331 {0x02B80288, 0x00000001},
1332 {0x02B80290, 0x00000001},
1333 {0x02B80298, 0x00000001},
1334 {0x02B802A0, 0x00000001},
1335 {0x02B802A8, 0x00000001},
1336 {0x02B802B0, 0x00000001},
1337 {0x02B802B8, 0x00000001},
1340 static const struct cs_dsp_region cs35l45_dsp1_regions
[] = {
1341 { .type
= WMFW_HALO_PM_PACKED
, .base
= CS35L45_DSP1_PMEM_0
},
1342 { .type
= WMFW_HALO_XM_PACKED
, .base
= CS35L45_DSP1_XMEM_PACK_0
},
1343 { .type
= WMFW_HALO_YM_PACKED
, .base
= CS35L45_DSP1_YMEM_PACK_0
},
1344 {. type
= WMFW_ADSP2_XM
, .base
= CS35L45_DSP1_XMEM_UNPACK24_0
},
1345 {. type
= WMFW_ADSP2_YM
, .base
= CS35L45_DSP1_YMEM_UNPACK24_0
},
1348 static int cs35l45_dsp_init(struct cs35l45_private
*cs35l45
)
1350 struct wm_adsp
*dsp
= &cs35l45
->dsp
;
1353 dsp
->part
= "cs35l45";
1354 dsp
->fw
= 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */
1355 dsp
->toggle_preload
= true;
1356 dsp
->cs_dsp
.num
= 1;
1357 dsp
->cs_dsp
.type
= WMFW_HALO
;
1358 dsp
->cs_dsp
.rev
= 0;
1359 dsp
->cs_dsp
.dev
= cs35l45
->dev
;
1360 dsp
->cs_dsp
.regmap
= cs35l45
->regmap
;
1361 dsp
->cs_dsp
.base
= CS35L45_DSP1_CLOCK_FREQ
;
1362 dsp
->cs_dsp
.base_sysinfo
= CS35L45_DSP1_SYS_ID
;
1363 dsp
->cs_dsp
.mem
= cs35l45_dsp1_regions
;
1364 dsp
->cs_dsp
.num_mems
= ARRAY_SIZE(cs35l45_dsp1_regions
);
1365 dsp
->cs_dsp
.lock_regions
= 0xFFFFFFFF;
1367 ret
= wm_halo_init(dsp
);
1369 regmap_multi_reg_write(cs35l45
->regmap
, cs35l45_fs_errata_patch
,
1370 ARRAY_SIZE(cs35l45_fs_errata_patch
));
1375 int cs35l45_probe(struct cs35l45_private
*cs35l45
)
1377 struct device
*dev
= cs35l45
->dev
;
1378 unsigned long irq_pol
= IRQF_ONESHOT
| IRQF_SHARED
;
1381 cs35l45
->vdd_batt
= devm_regulator_get(dev
, "vdd-batt");
1382 if (IS_ERR(cs35l45
->vdd_batt
))
1383 return dev_err_probe(dev
, PTR_ERR(cs35l45
->vdd_batt
),
1384 "Failed to request vdd-batt\n");
1386 cs35l45
->vdd_a
= devm_regulator_get(dev
, "vdd-a");
1387 if (IS_ERR(cs35l45
->vdd_a
))
1388 return dev_err_probe(dev
, PTR_ERR(cs35l45
->vdd_a
),
1389 "Failed to request vdd-a\n");
1391 /* VDD_BATT must always be enabled before other supplies */
1392 ret
= regulator_enable(cs35l45
->vdd_batt
);
1394 return dev_err_probe(dev
, ret
, "Failed to enable vdd-batt\n");
1396 ret
= regulator_enable(cs35l45
->vdd_a
);
1398 return dev_err_probe(dev
, ret
, "Failed to enable vdd-a\n");
1400 /* If reset is shared only one instance can claim it */
1401 cs35l45
->reset_gpio
= devm_gpiod_get_optional(dev
, "reset", GPIOD_OUT_LOW
);
1402 if (IS_ERR(cs35l45
->reset_gpio
)) {
1403 ret
= PTR_ERR(cs35l45
->reset_gpio
);
1404 cs35l45
->reset_gpio
= NULL
;
1405 if (ret
== -EBUSY
) {
1406 dev_dbg(dev
, "Reset line busy, assuming shared reset\n");
1408 dev_err_probe(dev
, ret
, "Failed to get reset GPIO\n");
1413 if (cs35l45
->reset_gpio
) {
1414 usleep_range(CS35L45_RESET_HOLD_US
, CS35L45_RESET_HOLD_US
+ 100);
1415 gpiod_set_value_cansleep(cs35l45
->reset_gpio
, 1);
1418 usleep_range(CS35L45_RESET_US
, CS35L45_RESET_US
+ 100);
1420 ret
= cs35l45_initialize(cs35l45
);
1424 ret
= cs35l45_dsp_init(cs35l45
);
1428 pm_runtime_set_autosuspend_delay(cs35l45
->dev
, 3000);
1429 pm_runtime_use_autosuspend(cs35l45
->dev
);
1430 pm_runtime_mark_last_busy(cs35l45
->dev
);
1431 pm_runtime_set_active(cs35l45
->dev
);
1432 pm_runtime_get_noresume(cs35l45
->dev
);
1433 pm_runtime_enable(cs35l45
->dev
);
1436 if (cs35l45
->irq_invert
)
1437 irq_pol
|= IRQF_TRIGGER_HIGH
;
1439 irq_pol
|= IRQF_TRIGGER_LOW
;
1441 ret
= devm_regmap_add_irq_chip(dev
, cs35l45
->regmap
, cs35l45
->irq
, irq_pol
, 0,
1442 &cs35l45_regmap_irq_chip
, &cs35l45
->irq_data
);
1444 dev_err(dev
, "Failed to register IRQ chip: %d\n", ret
);
1448 for (i
= 0; i
< ARRAY_SIZE(cs35l45_irqs
); i
++) {
1449 irq
= regmap_irq_get_virq(cs35l45
->irq_data
, cs35l45_irqs
[i
].irq
);
1451 dev_err(dev
, "Failed to get %s\n", cs35l45_irqs
[i
].name
);
1456 ret
= devm_request_threaded_irq(dev
, irq
, NULL
, cs35l45_irqs
[i
].handler
,
1457 irq_pol
, cs35l45_irqs
[i
].name
, cs35l45
);
1459 dev_err(dev
, "Failed to request IRQ %s: %d\n",
1460 cs35l45_irqs
[i
].name
, ret
);
1466 ret
= devm_snd_soc_register_component(dev
, &cs35l45_component
,
1468 ARRAY_SIZE(cs35l45_dai
));
1472 pm_runtime_put_autosuspend(cs35l45
->dev
);
1477 pm_runtime_disable(cs35l45
->dev
);
1478 pm_runtime_put_noidle(cs35l45
->dev
);
1479 wm_adsp2_remove(&cs35l45
->dsp
);
1482 gpiod_set_value_cansleep(cs35l45
->reset_gpio
, 0);
1484 regulator_disable(cs35l45
->vdd_a
);
1485 regulator_disable(cs35l45
->vdd_batt
);
1489 EXPORT_SYMBOL_NS_GPL(cs35l45_probe
, "SND_SOC_CS35L45");
1491 void cs35l45_remove(struct cs35l45_private
*cs35l45
)
1493 pm_runtime_get_sync(cs35l45
->dev
);
1494 pm_runtime_disable(cs35l45
->dev
);
1495 wm_adsp2_remove(&cs35l45
->dsp
);
1497 gpiod_set_value_cansleep(cs35l45
->reset_gpio
, 0);
1499 pm_runtime_put_noidle(cs35l45
->dev
);
1500 regulator_disable(cs35l45
->vdd_a
);
1501 /* VDD_BATT must be the last to power-off */
1502 regulator_disable(cs35l45
->vdd_batt
);
1504 EXPORT_SYMBOL_NS_GPL(cs35l45_remove
, "SND_SOC_CS35L45");
1506 EXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops
) = {
1507 RUNTIME_PM_OPS(cs35l45_runtime_suspend
, cs35l45_runtime_resume
, NULL
)
1509 SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend
, cs35l45_sys_resume
)
1510 NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend_noirq
, cs35l45_sys_resume_noirq
)
1513 MODULE_DESCRIPTION("ASoC CS35L45 driver");
1514 MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
1515 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
1516 MODULE_LICENSE("GPL");