cs35l45.c (6085f9e6dc1973cf98ee7f5dcf629939e50f1b84) cs35l45.c (74b14e2850a34740c121cf2758d4181063d4c77c)
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2//
3// cs35l45.c - CS35L45 ALSA SoC audio driver
4//
5// Copyright 2019-2022 Cirrus Logic, Inc.
6//
7// Author: James Schulman <james.schulman@cirrus.com>
8
9#include <linux/gpio/consumer.h>
10#include <linux/module.h>
11#include <linux/pm_runtime.h>
12#include <linux/property.h>
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2//
3// cs35l45.c - CS35L45 ALSA SoC audio driver
4//
5// Copyright 2019-2022 Cirrus Logic, Inc.
6//
7// Author: James Schulman <james.schulman@cirrus.com>
8
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>
13#include <linux/regulator/consumer.h>
14#include <sound/core.h>
15#include <sound/pcm.h>
16#include <sound/pcm_params.h>
17#include <sound/soc.h>
18#include <sound/tlv.h>
19
20#include "cs35l45.h"
21
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>
20
21#include "cs35l45.h"
22
23static bool cs35l45_check_cspl_mbox_sts(const enum cs35l45_cspl_mboxcmd cmd,
24 enum cs35l45_cspl_mboxstate sts)
25{
26 switch (cmd) {
27 case CSPL_MBOX_CMD_NONE:
28 case CSPL_MBOX_CMD_UNKNOWN_CMD:
29 return true;
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 default:
40 return false;
41 }
42}
43
44static int cs35l45_set_cspl_mbox_cmd(struct cs35l45_private *cs35l45,
45 struct regmap *regmap,
46 const enum cs35l45_cspl_mboxcmd cmd)
47{
48 unsigned int sts = 0, i;
49 int ret;
50
51 if (!cs35l45->dsp.cs_dsp.running) {
52 dev_err(cs35l45->dev, "DSP not running\n");
53 return -EPERM;
54 }
55
56 // Set mailbox cmd
57 ret = regmap_write(regmap, CS35L45_DSP_VIRT1_MBOX_1, cmd);
58 if (ret < 0) {
59 if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)
60 dev_err(cs35l45->dev, "Failed to write MBOX: %d\n", ret);
61 return ret;
62 }
63
64 // Read mailbox status and verify it is appropriate for the given cmd
65 for (i = 0; i < 5; i++) {
66 usleep_range(1000, 1100);
67
68 ret = regmap_read(regmap, CS35L45_DSP_MBOX_2, &sts);
69 if (ret < 0) {
70 dev_err(cs35l45->dev, "Failed to read MBOX STS: %d\n", ret);
71 continue;
72 }
73
74 if (!cs35l45_check_cspl_mbox_sts(cmd, sts))
75 dev_dbg(cs35l45->dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts);
76 else
77 return 0;
78 }
79
80 if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)
81 dev_err(cs35l45->dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);
82
83 return -ENOMSG;
84}
85
22static int cs35l45_global_en_ev(struct snd_soc_dapm_widget *w,
23 struct snd_kcontrol *kcontrol, int event)
24{
25 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
26 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
27
28 dev_dbg(cs35l45->dev, "%s event : %x\n", __func__, event);
29

--- 11 unchanged lines hidden (view full) ---

41 break;
42 default:
43 break;
44 }
45
46 return 0;
47}
48
86static int cs35l45_global_en_ev(struct snd_soc_dapm_widget *w,
87 struct snd_kcontrol *kcontrol, int event)
88{
89 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
90 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
91
92 dev_dbg(cs35l45->dev, "%s event : %x\n", __func__, event);
93

--- 11 unchanged lines hidden (view full) ---

105 break;
106 default:
107 break;
108 }
109
110 return 0;
111}
112
113static int cs35l45_dsp_preload_ev(struct snd_soc_dapm_widget *w,
114 struct snd_kcontrol *kcontrol, int event)
115{
116 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
117 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
118 int ret;
119
120 switch (event) {
121 case SND_SOC_DAPM_PRE_PMU:
122 if (cs35l45->dsp.cs_dsp.booted)
123 return 0;
124
125 return wm_adsp_early_event(w, kcontrol, event);
126 case SND_SOC_DAPM_POST_PMU:
127 if (cs35l45->dsp.cs_dsp.running)
128 return 0;
129
130 regmap_set_bits(cs35l45->regmap, CS35L45_PWRMGT_CTL,
131 CS35L45_MEM_RDY_MASK);
132
133 return wm_adsp_event(w, kcontrol, event);
134 case SND_SOC_DAPM_PRE_PMD:
135 if (cs35l45->dsp.preloaded)
136 return 0;
137
138 if (cs35l45->dsp.cs_dsp.running) {
139 ret = wm_adsp_event(w, kcontrol, event);
140 if (ret)
141 return ret;
142 }
143
144 return wm_adsp_early_event(w, kcontrol, event);
145 default:
146 return 0;
147 }
148}
149
150static int cs35l45_dsp_audio_ev(struct snd_soc_dapm_widget *w,
151 struct snd_kcontrol *kcontrol, int event)
152{
153 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
154 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
155
156 switch (event) {
157 case SND_SOC_DAPM_POST_PMU:
158 return cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap,
159 CSPL_MBOX_CMD_RESUME);
160 case SND_SOC_DAPM_PRE_PMD:
161 return cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap,
162 CSPL_MBOX_CMD_PAUSE);
163 default:
164 return 0;
165 }
166
167 return 0;
168}
169
49static const char * const cs35l45_asp_tx_txt[] = {
50 "Zero", "ASP_RX1", "ASP_RX2",
51 "VMON", "IMON", "ERR_VOL",
52 "VDD_BATTMON", "VDD_BSTMON",
170static const char * const cs35l45_asp_tx_txt[] = {
171 "Zero", "ASP_RX1", "ASP_RX2",
172 "VMON", "IMON", "ERR_VOL",
173 "VDD_BATTMON", "VDD_BSTMON",
174 "DSP_TX1", "DSP_TX2",
53 "Interpolator", "IL_TARGET",
54};
55
56static const unsigned int cs35l45_asp_tx_val[] = {
57 CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,
58 CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL,
59 CS35L45_PCM_SRC_VDD_BATTMON, CS35L45_PCM_SRC_VDD_BSTMON,
175 "Interpolator", "IL_TARGET",
176};
177
178static const unsigned int cs35l45_asp_tx_val[] = {
179 CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,
180 CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL,
181 CS35L45_PCM_SRC_VDD_BATTMON, CS35L45_PCM_SRC_VDD_BSTMON,
182 CS35L45_PCM_SRC_DSP_TX1, CS35L45_PCM_SRC_DSP_TX2,
60 CS35L45_PCM_SRC_INTERPOLATOR, CS35L45_PCM_SRC_IL_TARGET,
61};
62
63static const struct soc_enum cs35l45_asp_tx_enums[] = {
64 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT, 0, CS35L45_PCM_SRC_MASK,
65 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
66 cs35l45_asp_tx_val),
67 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT, 0, CS35L45_PCM_SRC_MASK,

--- 5 unchanged lines hidden (view full) ---

73 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT, 0, CS35L45_PCM_SRC_MASK,
74 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
75 cs35l45_asp_tx_val),
76 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT, 0, CS35L45_PCM_SRC_MASK,
77 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
78 cs35l45_asp_tx_val),
79};
80
183 CS35L45_PCM_SRC_INTERPOLATOR, CS35L45_PCM_SRC_IL_TARGET,
184};
185
186static const struct soc_enum cs35l45_asp_tx_enums[] = {
187 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX1_INPUT, 0, CS35L45_PCM_SRC_MASK,
188 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
189 cs35l45_asp_tx_val),
190 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX2_INPUT, 0, CS35L45_PCM_SRC_MASK,

--- 5 unchanged lines hidden (view full) ---

196 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX4_INPUT, 0, CS35L45_PCM_SRC_MASK,
197 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
198 cs35l45_asp_tx_val),
199 SOC_VALUE_ENUM_SINGLE(CS35L45_ASPTX5_INPUT, 0, CS35L45_PCM_SRC_MASK,
200 ARRAY_SIZE(cs35l45_asp_tx_txt), cs35l45_asp_tx_txt,
201 cs35l45_asp_tx_val),
202};
203
204static const char * const cs35l45_dsp_rx_txt[] = {
205 "Zero", "ASP_RX1", "ASP_RX2",
206 "VMON", "IMON", "ERR_VOL",
207 "CLASSH_TGT", "VDD_BATTMON",
208 "VDD_BSTMON", "TEMPMON",
209};
210
211static const unsigned int cs35l45_dsp_rx_val[] = {
212 CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,
213 CS35L45_PCM_SRC_VMON, CS35L45_PCM_SRC_IMON, CS35L45_PCM_SRC_ERR_VOL,
214 CS35L45_PCM_SRC_CLASSH_TGT, CS35L45_PCM_SRC_VDD_BATTMON,
215 CS35L45_PCM_SRC_VDD_BSTMON, CS35L45_PCM_SRC_TEMPMON,
216};
217
218static const struct soc_enum cs35l45_dsp_rx_enums[] = {
219 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX1_INPUT, 0, CS35L45_PCM_SRC_MASK,
220 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
221 cs35l45_dsp_rx_val),
222 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX2_INPUT, 0, CS35L45_PCM_SRC_MASK,
223 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
224 cs35l45_dsp_rx_val),
225 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX3_INPUT, 0, CS35L45_PCM_SRC_MASK,
226 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
227 cs35l45_dsp_rx_val),
228 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX4_INPUT, 0, CS35L45_PCM_SRC_MASK,
229 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
230 cs35l45_dsp_rx_val),
231 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX5_INPUT, 0, CS35L45_PCM_SRC_MASK,
232 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
233 cs35l45_dsp_rx_val),
234 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX6_INPUT, 0, CS35L45_PCM_SRC_MASK,
235 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
236 cs35l45_dsp_rx_val),
237 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX7_INPUT, 0, CS35L45_PCM_SRC_MASK,
238 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
239 cs35l45_dsp_rx_val),
240 SOC_VALUE_ENUM_SINGLE(CS35L45_DSP1RX8_INPUT, 0, CS35L45_PCM_SRC_MASK,
241 ARRAY_SIZE(cs35l45_dsp_rx_txt), cs35l45_dsp_rx_txt,
242 cs35l45_dsp_rx_val),
243};
244
81static const char * const cs35l45_dac_txt[] = {
245static const char * const cs35l45_dac_txt[] = {
82 "Zero", "ASP_RX1", "ASP_RX2"
246 "Zero", "ASP_RX1", "ASP_RX2", "DSP_TX1", "DSP_TX2"
83};
84
85static const unsigned int cs35l45_dac_val[] = {
247};
248
249static const unsigned int cs35l45_dac_val[] = {
86 CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2
250 CS35L45_PCM_SRC_ZERO, CS35L45_PCM_SRC_ASP_RX1, CS35L45_PCM_SRC_ASP_RX2,
251 CS35L45_PCM_SRC_DSP_TX1, CS35L45_PCM_SRC_DSP_TX2
87};
88
89static const struct soc_enum cs35l45_dacpcm_enums[] = {
90 SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT, 0, CS35L45_PCM_SRC_MASK,
91 ARRAY_SIZE(cs35l45_dac_txt), cs35l45_dac_txt,
92 cs35l45_dac_val),
93};
94
95static const struct snd_kcontrol_new cs35l45_asp_muxes[] = {
96 SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums[0]),
97 SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums[1]),
98 SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums[2]),
99 SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums[3]),
100 SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums[4]),
101};
102
252};
253
254static const struct soc_enum cs35l45_dacpcm_enums[] = {
255 SOC_VALUE_ENUM_SINGLE(CS35L45_DACPCM1_INPUT, 0, CS35L45_PCM_SRC_MASK,
256 ARRAY_SIZE(cs35l45_dac_txt), cs35l45_dac_txt,
257 cs35l45_dac_val),
258};
259
260static const struct snd_kcontrol_new cs35l45_asp_muxes[] = {
261 SOC_DAPM_ENUM("ASP_TX1 Source", cs35l45_asp_tx_enums[0]),
262 SOC_DAPM_ENUM("ASP_TX2 Source", cs35l45_asp_tx_enums[1]),
263 SOC_DAPM_ENUM("ASP_TX3 Source", cs35l45_asp_tx_enums[2]),
264 SOC_DAPM_ENUM("ASP_TX4 Source", cs35l45_asp_tx_enums[3]),
265 SOC_DAPM_ENUM("ASP_TX5 Source", cs35l45_asp_tx_enums[4]),
266};
267
268static const struct snd_kcontrol_new cs35l45_dsp_muxes[] = {
269 SOC_DAPM_ENUM("DSP_RX1 Source", cs35l45_dsp_rx_enums[0]),
270 SOC_DAPM_ENUM("DSP_RX2 Source", cs35l45_dsp_rx_enums[1]),
271 SOC_DAPM_ENUM("DSP_RX3 Source", cs35l45_dsp_rx_enums[2]),
272 SOC_DAPM_ENUM("DSP_RX4 Source", cs35l45_dsp_rx_enums[3]),
273 SOC_DAPM_ENUM("DSP_RX5 Source", cs35l45_dsp_rx_enums[4]),
274 SOC_DAPM_ENUM("DSP_RX6 Source", cs35l45_dsp_rx_enums[5]),
275 SOC_DAPM_ENUM("DSP_RX7 Source", cs35l45_dsp_rx_enums[6]),
276 SOC_DAPM_ENUM("DSP_RX8 Source", cs35l45_dsp_rx_enums[7]),
277};
278
103static const struct snd_kcontrol_new cs35l45_dac_muxes[] = {
104 SOC_DAPM_ENUM("DACPCM1 Source", cs35l45_dacpcm_enums[0]),
105};
106
107static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = {
279static const struct snd_kcontrol_new cs35l45_dac_muxes[] = {
280 SOC_DAPM_ENUM("DACPCM1 Source", cs35l45_dacpcm_enums[0]),
281};
282
283static const struct snd_soc_dapm_widget cs35l45_dapm_widgets[] = {
284 SND_SOC_DAPM_SPK("DSP1 Preload", NULL),
285 SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, SND_SOC_NOPM, 0, 0,
286 cs35l45_dsp_preload_ev,
287 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
288 SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0,
289 cs35l45_dsp_audio_ev,
290 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
108 SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM, 0, 0,
109 cs35l45_global_en_ev,
110 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
111 SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2, CS35L45_ASP_EN_SHIFT, 0, NULL, 0),
112
113 SND_SOC_DAPM_SIGGEN("VMON_SRC"),
114 SND_SOC_DAPM_SIGGEN("IMON_SRC"),
115 SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"),

--- 18 unchanged lines hidden (view full) ---

134 SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX5_EN_SHIFT, 0),
135
136 SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[0]),
137 SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[1]),
138 SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[2]),
139 SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[3]),
140 SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[4]),
141
291 SND_SOC_DAPM_SUPPLY("GLOBAL_EN", SND_SOC_NOPM, 0, 0,
292 cs35l45_global_en_ev,
293 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
294 SND_SOC_DAPM_SUPPLY("ASP_EN", CS35L45_BLOCK_ENABLES2, CS35L45_ASP_EN_SHIFT, 0, NULL, 0),
295
296 SND_SOC_DAPM_SIGGEN("VMON_SRC"),
297 SND_SOC_DAPM_SIGGEN("IMON_SRC"),
298 SND_SOC_DAPM_SIGGEN("VDD_BATTMON_SRC"),

--- 18 unchanged lines hidden (view full) ---

317 SND_SOC_DAPM_AIF_OUT("ASP_TX5", NULL, 3, CS35L45_ASP_ENABLES1, CS35L45_ASP_TX5_EN_SHIFT, 0),
318
319 SND_SOC_DAPM_MUX("ASP_TX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[0]),
320 SND_SOC_DAPM_MUX("ASP_TX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[1]),
321 SND_SOC_DAPM_MUX("ASP_TX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[2]),
322 SND_SOC_DAPM_MUX("ASP_TX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[3]),
323 SND_SOC_DAPM_MUX("ASP_TX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_asp_muxes[4]),
324
325 SND_SOC_DAPM_MUX("DSP_RX1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[0]),
326 SND_SOC_DAPM_MUX("DSP_RX2 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[1]),
327 SND_SOC_DAPM_MUX("DSP_RX3 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[2]),
328 SND_SOC_DAPM_MUX("DSP_RX4 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[3]),
329 SND_SOC_DAPM_MUX("DSP_RX5 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[4]),
330 SND_SOC_DAPM_MUX("DSP_RX6 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[5]),
331 SND_SOC_DAPM_MUX("DSP_RX7 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[6]),
332 SND_SOC_DAPM_MUX("DSP_RX8 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dsp_muxes[7]),
333
142 SND_SOC_DAPM_MUX("DACPCM1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]),
143
144 SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0),
145
146 SND_SOC_DAPM_OUTPUT("SPK"),
147};
148
149#define CS35L45_ASP_MUX_ROUTE(name) \
150 { name" Source", "ASP_RX1", "ASP_RX1" }, \
151 { name" Source", "ASP_RX2", "ASP_RX2" }, \
334 SND_SOC_DAPM_MUX("DACPCM1 Source", SND_SOC_NOPM, 0, 0, &cs35l45_dac_muxes[0]),
335
336 SND_SOC_DAPM_OUT_DRV("AMP", SND_SOC_NOPM, 0, 0, NULL, 0),
337
338 SND_SOC_DAPM_OUTPUT("SPK"),
339};
340
341#define CS35L45_ASP_MUX_ROUTE(name) \
342 { name" Source", "ASP_RX1", "ASP_RX1" }, \
343 { name" Source", "ASP_RX2", "ASP_RX2" }, \
344 { name" Source", "DSP_TX1", "DSP1" }, \
345 { name" Source", "DSP_TX2", "DSP1" }, \
152 { name" Source", "VMON", "VMON" }, \
153 { name" Source", "IMON", "IMON" }, \
154 { name" Source", "ERR_VOL", "ERR_VOL" }, \
155 { name" Source", "VDD_BATTMON", "VDD_BATTMON" }, \
156 { name" Source", "VDD_BSTMON", "VDD_BSTMON" }, \
157 { name" Source", "Interpolator", "AMP_INTP" }, \
158 { name" Source", "IL_TARGET", "IL_TARGET" }
159
346 { name" Source", "VMON", "VMON" }, \
347 { name" Source", "IMON", "IMON" }, \
348 { name" Source", "ERR_VOL", "ERR_VOL" }, \
349 { name" Source", "VDD_BATTMON", "VDD_BATTMON" }, \
350 { name" Source", "VDD_BSTMON", "VDD_BSTMON" }, \
351 { name" Source", "Interpolator", "AMP_INTP" }, \
352 { name" Source", "IL_TARGET", "IL_TARGET" }
353
160#define CS35L45_DAC_MUX_ROUTE(name) \
354#define CS35L45_DSP_MUX_ROUTE(name) \
161 { name" Source", "ASP_RX1", "ASP_RX1" }, \
162 { name" Source", "ASP_RX2", "ASP_RX2" }
163
355 { name" Source", "ASP_RX1", "ASP_RX1" }, \
356 { name" Source", "ASP_RX2", "ASP_RX2" }
357
358#define CS35L45_DAC_MUX_ROUTE(name) \
359 { name" Source", "ASP_RX1", "ASP_RX1" }, \
360 { name" Source", "ASP_RX2", "ASP_RX2" }, \
361 { name" Source", "DSP_TX1", "DSP1" }, \
362 { name" Source", "DSP_TX2", "DSP1" }
363
164static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {
165 /* Feedback */
166 { "VMON", NULL, "VMON_SRC" },
167 { "IMON", NULL, "IMON_SRC" },
168 { "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" },
169 { "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" },
170
171 { "Capture", NULL, "ASP_TX1"},

--- 27 unchanged lines hidden (view full) ---

199 { "ASP_RX1", NULL, "Playback" },
200 { "ASP_RX2", NULL, "Playback" },
201 { "ASP_RX1", NULL, "ASP_EN" },
202 { "ASP_RX2", NULL, "ASP_EN" },
203
204 { "AMP", NULL, "DACPCM1 Source"},
205 { "AMP", NULL, "GLOBAL_EN"},
206
364static const struct snd_soc_dapm_route cs35l45_dapm_routes[] = {
365 /* Feedback */
366 { "VMON", NULL, "VMON_SRC" },
367 { "IMON", NULL, "IMON_SRC" },
368 { "VDD_BATTMON", NULL, "VDD_BATTMON_SRC" },
369 { "VDD_BSTMON", NULL, "VDD_BSTMON_SRC" },
370
371 { "Capture", NULL, "ASP_TX1"},

--- 27 unchanged lines hidden (view full) ---

399 { "ASP_RX1", NULL, "Playback" },
400 { "ASP_RX2", NULL, "Playback" },
401 { "ASP_RX1", NULL, "ASP_EN" },
402 { "ASP_RX2", NULL, "ASP_EN" },
403
404 { "AMP", NULL, "DACPCM1 Source"},
405 { "AMP", NULL, "GLOBAL_EN"},
406
407 CS35L45_DSP_MUX_ROUTE("DSP_RX1"),
408 CS35L45_DSP_MUX_ROUTE("DSP_RX2"),
409 CS35L45_DSP_MUX_ROUTE("DSP_RX3"),
410 CS35L45_DSP_MUX_ROUTE("DSP_RX4"),
411 CS35L45_DSP_MUX_ROUTE("DSP_RX5"),
412 CS35L45_DSP_MUX_ROUTE("DSP_RX6"),
413 CS35L45_DSP_MUX_ROUTE("DSP_RX7"),
414 CS35L45_DSP_MUX_ROUTE("DSP_RX8"),
415
416 {"DSP1", NULL, "DSP_RX1 Source"},
417 {"DSP1", NULL, "DSP_RX2 Source"},
418 {"DSP1", NULL, "DSP_RX3 Source"},
419 {"DSP1", NULL, "DSP_RX4 Source"},
420 {"DSP1", NULL, "DSP_RX5 Source"},
421 {"DSP1", NULL, "DSP_RX6 Source"},
422 {"DSP1", NULL, "DSP_RX7 Source"},
423 {"DSP1", NULL, "DSP_RX8 Source"},
424
425 {"DSP1 Preload", NULL, "DSP1 Preloader"},
426 {"DSP1", NULL, "DSP1 Preloader"},
427
207 CS35L45_DAC_MUX_ROUTE("DACPCM1"),
208
209 { "SPK", NULL, "AMP"},
210};
211
212static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true);
213
214static const struct snd_kcontrol_new cs35l45_controls[] = {
215 /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */
216 SOC_SINGLE_S_TLV("Digital PCM Volume",
217 CS35L45_AMP_PCM_CONTROL,
218 CS35L45_AMP_VOL_PCM_SHIFT + 1,
219 -409, 48,
220 (CS35L45_AMP_VOL_PCM_WIDTH - 1) - 1,
221 0, cs35l45_dig_pcm_vol_tlv),
428 CS35L45_DAC_MUX_ROUTE("DACPCM1"),
429
430 { "SPK", NULL, "AMP"},
431};
432
433static const DECLARE_TLV_DB_SCALE(cs35l45_dig_pcm_vol_tlv, -10225, 25, true);
434
435static const struct snd_kcontrol_new cs35l45_controls[] = {
436 /* Ignore bit 0: it is beyond the resolution of TLV_DB_SCALE */
437 SOC_SINGLE_S_TLV("Digital PCM Volume",
438 CS35L45_AMP_PCM_CONTROL,
439 CS35L45_AMP_VOL_PCM_SHIFT + 1,
440 -409, 48,
441 (CS35L45_AMP_VOL_PCM_WIDTH - 1) - 1,
442 0, cs35l45_dig_pcm_vol_tlv),
443 WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
444 WM_ADSP_FW_CONTROL("DSP1", 0),
222};
223
224static int cs35l45_set_pll(struct cs35l45_private *cs35l45, unsigned int freq)
225{
226 unsigned int val;
227 int freq_id;
228
229 freq_id = cs35l45_get_clk_freq_id(freq);

--- 254 unchanged lines hidden (view full) ---

484 .formats = CS35L45_FORMATS,
485 },
486 .symmetric_rate = true,
487 .symmetric_sample_bits = true,
488 .ops = &cs35l45_asp_dai_ops,
489 },
490};
491
445};
446
447static int cs35l45_set_pll(struct cs35l45_private *cs35l45, unsigned int freq)
448{
449 unsigned int val;
450 int freq_id;
451
452 freq_id = cs35l45_get_clk_freq_id(freq);

--- 254 unchanged lines hidden (view full) ---

707 .formats = CS35L45_FORMATS,
708 },
709 .symmetric_rate = true,
710 .symmetric_sample_bits = true,
711 .ops = &cs35l45_asp_dai_ops,
712 },
713};
714
715static int cs35l45_component_probe(struct snd_soc_component *component)
716{
717 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
718
719 return wm_adsp2_component_probe(&cs35l45->dsp, component);
720}
721
722static void cs35l45_component_remove(struct snd_soc_component *component)
723{
724 struct cs35l45_private *cs35l45 = snd_soc_component_get_drvdata(component);
725
726 wm_adsp2_component_remove(&cs35l45->dsp, component);
727}
728
492static const struct snd_soc_component_driver cs35l45_component = {
729static const struct snd_soc_component_driver cs35l45_component = {
730 .probe = cs35l45_component_probe,
731 .remove = cs35l45_component_remove,
732
493 .dapm_widgets = cs35l45_dapm_widgets,
494 .num_dapm_widgets = ARRAY_SIZE(cs35l45_dapm_widgets),
495
496 .dapm_routes = cs35l45_dapm_routes,
497 .num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes),
498
499 .controls = cs35l45_controls,
500 .num_controls = ARRAY_SIZE(cs35l45_controls),

--- 101 unchanged lines hidden (view full) ---

602 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL3,
603 CS35L45_ASP_DOUT_HIZ_CTRL_MASK,
604 val << CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT);
605 }
606
607 return 0;
608}
609
733 .dapm_widgets = cs35l45_dapm_widgets,
734 .num_dapm_widgets = ARRAY_SIZE(cs35l45_dapm_widgets),
735
736 .dapm_routes = cs35l45_dapm_routes,
737 .num_dapm_routes = ARRAY_SIZE(cs35l45_dapm_routes),
738
739 .controls = cs35l45_controls,
740 .num_controls = ARRAY_SIZE(cs35l45_controls),

--- 101 unchanged lines hidden (view full) ---

842 regmap_update_bits(cs35l45->regmap, CS35L45_ASP_CONTROL3,
843 CS35L45_ASP_DOUT_HIZ_CTRL_MASK,
844 val << CS35L45_ASP_DOUT_HIZ_CTRL_SHIFT);
845 }
846
847 return 0;
848}
849
850static int cs35l45_dsp_virt2_mbox3_irq_handle(struct cs35l45_private *cs35l45,
851 const unsigned int cmd,
852 unsigned int data)
853{
854 static char *speak_status = "Unknown";
855
856 switch (cmd) {
857 case EVENT_SPEAKER_STATUS:
858 switch (data) {
859 case 1:
860 speak_status = "All Clear";
861 break;
862 case 2:
863 speak_status = "Open Circuit";
864 break;
865 case 4:
866 speak_status = "Short Circuit";
867 break;
868 }
869
870 dev_info(cs35l45->dev, "MBOX event (SPEAKER_STATUS): %s\n",
871 speak_status);
872 break;
873 case EVENT_BOOT_DONE:
874 dev_dbg(cs35l45->dev, "MBOX event (BOOT_DONE)\n");
875 break;
876 default:
877 dev_err(cs35l45->dev, "MBOX event not supported %u\n", cmd);
878 return -EINVAL;
879 }
880
881 return 0;
882}
883
884static irqreturn_t cs35l45_dsp_virt2_mbox_cb(int irq, void *data)
885{
886 struct cs35l45_private *cs35l45 = data;
887 unsigned int mbox_val;
888 int ret = 0;
889
890 ret = regmap_read(cs35l45->regmap, CS35L45_DSP_VIRT2_MBOX_3, &mbox_val);
891 if (!ret && mbox_val)
892 ret = cs35l45_dsp_virt2_mbox3_irq_handle(cs35l45, mbox_val & CS35L45_MBOX3_CMD_MASK,
893 (mbox_val & CS35L45_MBOX3_DATA_MASK) >> CS35L45_MBOX3_DATA_SHIFT);
894
895 /* Handle DSP trace log IRQ */
896 ret = regmap_read(cs35l45->regmap, CS35L45_DSP_VIRT2_MBOX_4, &mbox_val);
897 if (!ret && mbox_val != 0) {
898 dev_err(cs35l45->dev, "Spurious DSP MBOX4 IRQ\n");
899 }
900
901 return IRQ_RETVAL(ret);
902}
903
610static irqreturn_t cs35l45_pll_unlock(int irq, void *data)
611{
612 struct cs35l45_private *cs35l45 = data;
613
614 dev_dbg(cs35l45->dev, "PLL unlock detected!");
615
616 return IRQ_HANDLED;
617}

--- 16 unchanged lines hidden (view full) ---

634 CS35L45_IRQ(BST_UVP_ERR, "Boost undervoltage error", cs35l45_spk_safe_err),
635 CS35L45_IRQ(TEMP_ERR, "Overtemperature error", cs35l45_spk_safe_err),
636 CS35L45_IRQ(AMP_CAL_ERR, "Amplifier calibration error", cs35l45_spk_safe_err),
637 CS35L45_IRQ(UVLO_VDDLV_ERR, "LV threshold detector error", cs35l45_spk_safe_err),
638 CS35L45_IRQ(GLOBAL_ERROR, "Global error", cs35l45_spk_safe_err),
639 CS35L45_IRQ(DSP_WDT_EXPIRE, "DSP Watchdog Timer", cs35l45_spk_safe_err),
640 CS35L45_IRQ(PLL_UNLOCK_FLAG_RISE, "PLL unlock", cs35l45_pll_unlock),
641 CS35L45_IRQ(PLL_LOCK_FLAG, "PLL lock", cs35l45_pll_lock),
904static irqreturn_t cs35l45_pll_unlock(int irq, void *data)
905{
906 struct cs35l45_private *cs35l45 = data;
907
908 dev_dbg(cs35l45->dev, "PLL unlock detected!");
909
910 return IRQ_HANDLED;
911}

--- 16 unchanged lines hidden (view full) ---

928 CS35L45_IRQ(BST_UVP_ERR, "Boost undervoltage error", cs35l45_spk_safe_err),
929 CS35L45_IRQ(TEMP_ERR, "Overtemperature error", cs35l45_spk_safe_err),
930 CS35L45_IRQ(AMP_CAL_ERR, "Amplifier calibration error", cs35l45_spk_safe_err),
931 CS35L45_IRQ(UVLO_VDDLV_ERR, "LV threshold detector error", cs35l45_spk_safe_err),
932 CS35L45_IRQ(GLOBAL_ERROR, "Global error", cs35l45_spk_safe_err),
933 CS35L45_IRQ(DSP_WDT_EXPIRE, "DSP Watchdog Timer", cs35l45_spk_safe_err),
934 CS35L45_IRQ(PLL_UNLOCK_FLAG_RISE, "PLL unlock", cs35l45_pll_unlock),
935 CS35L45_IRQ(PLL_LOCK_FLAG, "PLL lock", cs35l45_pll_lock),
936 CS35L45_IRQ(DSP_VIRT2_MBOX, "DSP virtual MBOX 2 write flag", cs35l45_dsp_virt2_mbox_cb),
642};
643
644static irqreturn_t cs35l45_spk_safe_err(int irq, void *data)
645{
646 struct cs35l45_private *cs35l45 = data;
647 int i;
648
649 i = irq - regmap_irq_get_virq(cs35l45->irq_data, 0);

--- 10 unchanged lines hidden (view full) ---

660 CS35L45_REG_IRQ(IRQ1_EINT_1, BST_UVP_ERR),
661 CS35L45_REG_IRQ(IRQ1_EINT_1, TEMP_ERR),
662 CS35L45_REG_IRQ(IRQ1_EINT_3, AMP_CAL_ERR),
663 CS35L45_REG_IRQ(IRQ1_EINT_18, UVLO_VDDLV_ERR),
664 CS35L45_REG_IRQ(IRQ1_EINT_18, GLOBAL_ERROR),
665 CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_WDT_EXPIRE),
666 CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_UNLOCK_FLAG_RISE),
667 CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_LOCK_FLAG),
937};
938
939static irqreturn_t cs35l45_spk_safe_err(int irq, void *data)
940{
941 struct cs35l45_private *cs35l45 = data;
942 int i;
943
944 i = irq - regmap_irq_get_virq(cs35l45->irq_data, 0);

--- 10 unchanged lines hidden (view full) ---

955 CS35L45_REG_IRQ(IRQ1_EINT_1, BST_UVP_ERR),
956 CS35L45_REG_IRQ(IRQ1_EINT_1, TEMP_ERR),
957 CS35L45_REG_IRQ(IRQ1_EINT_3, AMP_CAL_ERR),
958 CS35L45_REG_IRQ(IRQ1_EINT_18, UVLO_VDDLV_ERR),
959 CS35L45_REG_IRQ(IRQ1_EINT_18, GLOBAL_ERROR),
960 CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_WDT_EXPIRE),
961 CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_UNLOCK_FLAG_RISE),
962 CS35L45_REG_IRQ(IRQ1_EINT_3, PLL_LOCK_FLAG),
963 CS35L45_REG_IRQ(IRQ1_EINT_2, DSP_VIRT2_MBOX),
668};
669
670static const struct regmap_irq_chip cs35l45_regmap_irq_chip = {
671 .name = "cs35l45 IRQ1 Controller",
672 .main_status = CS35L45_IRQ1_STATUS,
673 .status_base = CS35L45_IRQ1_EINT_1,
674 .mask_base = CS35L45_IRQ1_MASK_1,
675 .ack_base = CS35L45_IRQ1_EINT_1,

--- 43 unchanged lines hidden (view full) ---

719 dev_err(dev, "Failed to apply init patch %d\n", ret);
720 return ret;
721 }
722
723 ret = cs35l45_apply_property_config(cs35l45);
724 if (ret < 0)
725 return ret;
726
964};
965
966static const struct regmap_irq_chip cs35l45_regmap_irq_chip = {
967 .name = "cs35l45 IRQ1 Controller",
968 .main_status = CS35L45_IRQ1_STATUS,
969 .status_base = CS35L45_IRQ1_EINT_1,
970 .mask_base = CS35L45_IRQ1_MASK_1,
971 .ack_base = CS35L45_IRQ1_EINT_1,

--- 43 unchanged lines hidden (view full) ---

1015 dev_err(dev, "Failed to apply init patch %d\n", ret);
1016 return ret;
1017 }
1018
1019 ret = cs35l45_apply_property_config(cs35l45);
1020 if (ret < 0)
1021 return ret;
1022
727 pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000);
728 pm_runtime_use_autosuspend(cs35l45->dev);
729 pm_runtime_set_active(cs35l45->dev);
730 pm_runtime_enable(cs35l45->dev);
731
732 return 0;
733}
734
1023 return 0;
1024}
1025
1026static const struct reg_sequence cs35l45_fs_errata_patch[] = {
1027 {0x02B80080, 0x00000001},
1028 {0x02B80088, 0x00000001},
1029 {0x02B80090, 0x00000001},
1030 {0x02B80098, 0x00000001},
1031 {0x02B800A0, 0x00000001},
1032 {0x02B800A8, 0x00000001},
1033 {0x02B800B0, 0x00000001},
1034 {0x02B800B8, 0x00000001},
1035 {0x02B80280, 0x00000001},
1036 {0x02B80288, 0x00000001},
1037 {0x02B80290, 0x00000001},
1038 {0x02B80298, 0x00000001},
1039 {0x02B802A0, 0x00000001},
1040 {0x02B802A8, 0x00000001},
1041 {0x02B802B0, 0x00000001},
1042 {0x02B802B8, 0x00000001},
1043};
1044
1045static const struct cs_dsp_region cs35l45_dsp1_regions[] = {
1046 { .type = WMFW_HALO_PM_PACKED, .base = CS35L45_DSP1_PMEM_0 },
1047 { .type = WMFW_HALO_XM_PACKED, .base = CS35L45_DSP1_XMEM_PACK_0 },
1048 { .type = WMFW_HALO_YM_PACKED, .base = CS35L45_DSP1_YMEM_PACK_0 },
1049 {. type = WMFW_ADSP2_XM, .base = CS35L45_DSP1_XMEM_UNPACK24_0},
1050 {. type = WMFW_ADSP2_YM, .base = CS35L45_DSP1_YMEM_UNPACK24_0},
1051};
1052
1053static int cs35l45_dsp_init(struct cs35l45_private *cs35l45)
1054{
1055 struct wm_adsp *dsp = &cs35l45->dsp;
1056 int ret;
1057
1058 dsp->part = "cs35l45";
1059 dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */
1060 dsp->toggle_preload = true;
1061 dsp->cs_dsp.num = 1;
1062 dsp->cs_dsp.type = WMFW_HALO;
1063 dsp->cs_dsp.rev = 0;
1064 dsp->cs_dsp.dev = cs35l45->dev;
1065 dsp->cs_dsp.regmap = cs35l45->regmap;
1066 dsp->cs_dsp.base = CS35L45_DSP1_CLOCK_FREQ;
1067 dsp->cs_dsp.base_sysinfo = CS35L45_DSP1_SYS_ID;
1068 dsp->cs_dsp.mem = cs35l45_dsp1_regions;
1069 dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l45_dsp1_regions);
1070 dsp->cs_dsp.lock_regions = 0xFFFFFFFF;
1071
1072 ret = wm_halo_init(dsp);
1073
1074 regmap_multi_reg_write(cs35l45->regmap, cs35l45_fs_errata_patch,
1075 ARRAY_SIZE(cs35l45_fs_errata_patch));
1076
1077 return ret;
1078}
1079
735int cs35l45_probe(struct cs35l45_private *cs35l45)
736{
737 struct device *dev = cs35l45->dev;
738 unsigned long irq_pol = IRQF_ONESHOT | IRQF_SHARED;
739 int ret, i, irq;
740
741 cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt");
742 if (IS_ERR(cs35l45->vdd_batt))

--- 33 unchanged lines hidden (view full) ---

776 }
777
778 usleep_range(CS35L45_RESET_US, CS35L45_RESET_US + 100);
779
780 ret = cs35l45_initialize(cs35l45);
781 if (ret < 0)
782 goto err_reset;
783
1080int cs35l45_probe(struct cs35l45_private *cs35l45)
1081{
1082 struct device *dev = cs35l45->dev;
1083 unsigned long irq_pol = IRQF_ONESHOT | IRQF_SHARED;
1084 int ret, i, irq;
1085
1086 cs35l45->vdd_batt = devm_regulator_get(dev, "vdd-batt");
1087 if (IS_ERR(cs35l45->vdd_batt))

--- 33 unchanged lines hidden (view full) ---

1121 }
1122
1123 usleep_range(CS35L45_RESET_US, CS35L45_RESET_US + 100);
1124
1125 ret = cs35l45_initialize(cs35l45);
1126 if (ret < 0)
1127 goto err_reset;
1128
1129 ret = cs35l45_dsp_init(cs35l45);
1130 if (ret < 0)
1131 goto err_reset;
1132
1133 pm_runtime_set_autosuspend_delay(cs35l45->dev, 3000);
1134 pm_runtime_use_autosuspend(cs35l45->dev);
1135 pm_runtime_mark_last_busy(cs35l45->dev);
1136 pm_runtime_set_active(cs35l45->dev);
1137 pm_runtime_get_noresume(cs35l45->dev);
1138 pm_runtime_enable(cs35l45->dev);
1139
784 if (cs35l45->irq) {
785 if (cs35l45->irq_invert)
786 irq_pol |= IRQF_TRIGGER_HIGH;
787 else
788 irq_pol |= IRQF_TRIGGER_LOW;
789
790 ret = devm_regmap_add_irq_chip(dev, cs35l45->regmap, cs35l45->irq, irq_pol, 0,
791 &cs35l45_regmap_irq_chip, &cs35l45->irq_data);
792 if (ret) {
793 dev_err(dev, "Failed to register IRQ chip: %d\n", ret);
1140 if (cs35l45->irq) {
1141 if (cs35l45->irq_invert)
1142 irq_pol |= IRQF_TRIGGER_HIGH;
1143 else
1144 irq_pol |= IRQF_TRIGGER_LOW;
1145
1146 ret = devm_regmap_add_irq_chip(dev, cs35l45->regmap, cs35l45->irq, irq_pol, 0,
1147 &cs35l45_regmap_irq_chip, &cs35l45->irq_data);
1148 if (ret) {
1149 dev_err(dev, "Failed to register IRQ chip: %d\n", ret);
794 goto err_reset;
1150 goto err_dsp;
795 }
796
797 for (i = 0; i < ARRAY_SIZE(cs35l45_irqs); i++) {
798 irq = regmap_irq_get_virq(cs35l45->irq_data, cs35l45_irqs[i].irq);
799 if (irq < 0) {
800 dev_err(dev, "Failed to get %s\n", cs35l45_irqs[i].name);
801 ret = irq;
1151 }
1152
1153 for (i = 0; i < ARRAY_SIZE(cs35l45_irqs); i++) {
1154 irq = regmap_irq_get_virq(cs35l45->irq_data, cs35l45_irqs[i].irq);
1155 if (irq < 0) {
1156 dev_err(dev, "Failed to get %s\n", cs35l45_irqs[i].name);
1157 ret = irq;
802 goto err_reset;
1158 goto err_dsp;
803 }
804
805 ret = devm_request_threaded_irq(dev, irq, NULL, cs35l45_irqs[i].handler,
806 irq_pol, cs35l45_irqs[i].name, cs35l45);
807 if (ret) {
808 dev_err(dev, "Failed to request IRQ %s: %d\n",
809 cs35l45_irqs[i].name, ret);
1159 }
1160
1161 ret = devm_request_threaded_irq(dev, irq, NULL, cs35l45_irqs[i].handler,
1162 irq_pol, cs35l45_irqs[i].name, cs35l45);
1163 if (ret) {
1164 dev_err(dev, "Failed to request IRQ %s: %d\n",
1165 cs35l45_irqs[i].name, ret);
810 goto err_reset;
1166 goto err_dsp;
811 }
812 }
813 }
814
815 ret = devm_snd_soc_register_component(dev, &cs35l45_component,
816 cs35l45_dai,
817 ARRAY_SIZE(cs35l45_dai));
818 if (ret < 0)
1167 }
1168 }
1169 }
1170
1171 ret = devm_snd_soc_register_component(dev, &cs35l45_component,
1172 cs35l45_dai,
1173 ARRAY_SIZE(cs35l45_dai));
1174 if (ret < 0)
819 goto err_reset;
1175 goto err_dsp;
820
1176
1177 pm_runtime_put_autosuspend(cs35l45->dev);
1178
821 return 0;
822
1179 return 0;
1180
1181err_dsp:
1182 pm_runtime_disable(cs35l45->dev);
1183 pm_runtime_put_noidle(cs35l45->dev);
1184 wm_adsp2_remove(&cs35l45->dsp);
1185
823err_reset:
824 gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);
825err:
826 regulator_disable(cs35l45->vdd_a);
827 regulator_disable(cs35l45->vdd_batt);
828
829 return ret;
830}
831EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);
832
833void cs35l45_remove(struct cs35l45_private *cs35l45)
834{
1186err_reset:
1187 gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);
1188err:
1189 regulator_disable(cs35l45->vdd_a);
1190 regulator_disable(cs35l45->vdd_batt);
1191
1192 return ret;
1193}
1194EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);
1195
1196void cs35l45_remove(struct cs35l45_private *cs35l45)
1197{
1198 pm_runtime_get_sync(cs35l45->dev);
835 pm_runtime_disable(cs35l45->dev);
1199 pm_runtime_disable(cs35l45->dev);
1200 wm_adsp2_remove(&cs35l45->dsp);
836
837 gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);
1201
1202 gpiod_set_value_cansleep(cs35l45->reset_gpio, 0);
1203
1204 pm_runtime_put_noidle(cs35l45->dev);
838 regulator_disable(cs35l45->vdd_a);
839 /* VDD_BATT must be the last to power-off */
840 regulator_disable(cs35l45->vdd_batt);
841}
842EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
843
844const struct dev_pm_ops cs35l45_pm_ops = {
845 SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
846};
847EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45);
848
849MODULE_DESCRIPTION("ASoC CS35L45 driver");
850MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
851MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
852MODULE_LICENSE("Dual BSD/GPL");
1205 regulator_disable(cs35l45->vdd_a);
1206 /* VDD_BATT must be the last to power-off */
1207 regulator_disable(cs35l45->vdd_batt);
1208}
1209EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
1210
1211const struct dev_pm_ops cs35l45_pm_ops = {
1212 SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
1213};
1214EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45);
1215
1216MODULE_DESCRIPTION("ASoC CS35L45 driver");
1217MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
1218MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
1219MODULE_LICENSE("Dual BSD/GPL");