1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. |
4 | // |
5 | // ALSA SoC Machine driver for sc7280 |
6 | |
7 | #include <dt-bindings/sound/qcom,lpass.h> |
8 | #include <dt-bindings/sound/qcom,q6afe.h> |
9 | #include <linux/input.h> |
10 | #include <linux/mod_devicetable.h> |
11 | #include <linux/module.h> |
12 | #include <linux/platform_device.h> |
13 | #include <sound/core.h> |
14 | #include <sound/jack.h> |
15 | #include <sound/pcm.h> |
16 | #include <sound/soc.h> |
17 | #include <sound/rt5682s.h> |
18 | #include <linux/soundwire/sdw.h> |
19 | #include <sound/pcm_params.h> |
20 | |
21 | #include "../codecs/rt5682.h" |
22 | #include "../codecs/rt5682s.h" |
23 | #include "common.h" |
24 | #include "lpass.h" |
25 | #include "qdsp6/q6afe.h" |
26 | |
27 | #define DEFAULT_MCLK_RATE 19200000 |
28 | #define RT5682_PLL_FREQ (48000 * 512) |
29 | #define MI2S_BCLK_RATE 1536000 |
30 | |
31 | struct sc7280_snd_data { |
32 | struct snd_soc_card card; |
33 | struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS]; |
34 | u32 pri_mi2s_clk_count; |
35 | struct snd_soc_jack hs_jack; |
36 | struct snd_soc_jack hdmi_jack; |
37 | bool jack_setup; |
38 | bool stream_prepared[LPASS_MAX_PORTS]; |
39 | }; |
40 | |
41 | static void sc7280_jack_free(struct snd_jack *jack) |
42 | { |
43 | struct snd_soc_component *component = jack->private_data; |
44 | |
45 | snd_soc_component_set_jack(component, NULL, NULL); |
46 | } |
47 | |
48 | static struct snd_soc_jack_pin sc7280_jack_pins[] = { |
49 | { |
50 | .pin = "Headphone Jack" , |
51 | .mask = SND_JACK_HEADPHONE, |
52 | }, |
53 | { |
54 | .pin = "Headset Mic" , |
55 | .mask = SND_JACK_MICROPHONE, |
56 | }, |
57 | }; |
58 | |
59 | static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) |
60 | { |
61 | struct snd_soc_card *card = rtd->card; |
62 | struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card); |
63 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
64 | struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
65 | struct snd_soc_component *component = codec_dai->component; |
66 | struct snd_jack *jack; |
67 | int rval, i; |
68 | |
69 | if (!pdata->jack_setup) { |
70 | rval = snd_soc_card_jack_new_pins(card, id: "Headset Jack" , |
71 | type: SND_JACK_HEADSET | SND_JACK_LINEOUT | |
72 | SND_JACK_MECHANICAL | |
73 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | |
74 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | |
75 | SND_JACK_BTN_4 | SND_JACK_BTN_5, |
76 | jack: &pdata->hs_jack, |
77 | pins: sc7280_jack_pins, |
78 | ARRAY_SIZE(sc7280_jack_pins)); |
79 | |
80 | if (rval < 0) { |
81 | dev_err(card->dev, "Unable to add Headset Jack\n" ); |
82 | return rval; |
83 | } |
84 | |
85 | jack = pdata->hs_jack.jack; |
86 | |
87 | snd_jack_set_key(jack, type: SND_JACK_BTN_0, KEY_PLAYPAUSE); |
88 | snd_jack_set_key(jack, type: SND_JACK_BTN_1, KEY_VOICECOMMAND); |
89 | snd_jack_set_key(jack, type: SND_JACK_BTN_2, KEY_VOLUMEUP); |
90 | snd_jack_set_key(jack, type: SND_JACK_BTN_3, KEY_VOLUMEDOWN); |
91 | |
92 | jack->private_data = component; |
93 | jack->private_free = sc7280_jack_free; |
94 | pdata->jack_setup = true; |
95 | } |
96 | switch (cpu_dai->id) { |
97 | case MI2S_PRIMARY: |
98 | case LPASS_CDC_DMA_RX0: |
99 | case LPASS_CDC_DMA_TX3: |
100 | case TX_CODEC_DMA_TX_3: |
101 | for_each_rtd_codec_dais(rtd, i, codec_dai) { |
102 | rval = snd_soc_component_set_jack(component, jack: &pdata->hs_jack, NULL); |
103 | if (rval != 0 && rval != -ENOTSUPP) { |
104 | dev_err(card->dev, "Failed to set jack: %d\n" , rval); |
105 | return rval; |
106 | } |
107 | } |
108 | break; |
109 | default: |
110 | break; |
111 | } |
112 | |
113 | return 0; |
114 | } |
115 | |
116 | static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd) |
117 | { |
118 | struct snd_soc_card *card = rtd->card; |
119 | struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card); |
120 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
121 | struct snd_soc_component *component = codec_dai->component; |
122 | struct snd_jack *jack; |
123 | int rval; |
124 | |
125 | rval = snd_soc_card_jack_new(card, id: "HDMI Jack" , type: SND_JACK_LINEOUT, |
126 | jack: &pdata->hdmi_jack); |
127 | |
128 | if (rval < 0) { |
129 | dev_err(card->dev, "Unable to add HDMI Jack\n" ); |
130 | return rval; |
131 | } |
132 | |
133 | jack = pdata->hdmi_jack.jack; |
134 | jack->private_data = component; |
135 | jack->private_free = sc7280_jack_free; |
136 | |
137 | return snd_soc_component_set_jack(component, jack: &pdata->hdmi_jack, NULL); |
138 | } |
139 | |
140 | static int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd) |
141 | { |
142 | struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
143 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
144 | struct snd_soc_card *card = rtd->card; |
145 | struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); |
146 | int ret; |
147 | |
148 | if (++data->pri_mi2s_clk_count == 1) { |
149 | snd_soc_dai_set_sysclk(dai: cpu_dai, |
150 | LPASS_MCLK0, |
151 | DEFAULT_MCLK_RATE, |
152 | dir: SNDRV_PCM_STREAM_PLAYBACK); |
153 | } |
154 | snd_soc_dai_set_fmt(dai: codec_dai, |
155 | SND_SOC_DAIFMT_CBC_CFC | |
156 | SND_SOC_DAIFMT_NB_NF | |
157 | SND_SOC_DAIFMT_I2S); |
158 | |
159 | ret = snd_soc_dai_set_pll(dai: codec_dai, pll_id: RT5682S_PLL2, source: RT5682S_PLL_S_MCLK, |
160 | DEFAULT_MCLK_RATE, RT5682_PLL_FREQ); |
161 | if (ret) { |
162 | dev_err(rtd->dev, "can't set codec pll: %d\n" , ret); |
163 | return ret; |
164 | } |
165 | |
166 | ret = snd_soc_dai_set_sysclk(dai: codec_dai, clk_id: RT5682S_SCLK_S_PLL2, |
167 | RT5682_PLL_FREQ, |
168 | SND_SOC_CLOCK_IN); |
169 | |
170 | if (ret) { |
171 | dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n" , |
172 | ret); |
173 | return ret; |
174 | } |
175 | |
176 | return 0; |
177 | } |
178 | |
179 | static int sc7280_init(struct snd_soc_pcm_runtime *rtd) |
180 | { |
181 | struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
182 | |
183 | switch (cpu_dai->id) { |
184 | case MI2S_PRIMARY: |
185 | case LPASS_CDC_DMA_TX3: |
186 | case TX_CODEC_DMA_TX_3: |
187 | return sc7280_headset_init(rtd); |
188 | case LPASS_CDC_DMA_RX0: |
189 | case LPASS_CDC_DMA_VA_TX0: |
190 | case MI2S_SECONDARY: |
191 | case RX_CODEC_DMA_RX_0: |
192 | case SECONDARY_MI2S_RX: |
193 | case VA_CODEC_DMA_TX_0: |
194 | return 0; |
195 | case LPASS_DP_RX: |
196 | return sc7280_hdmi_init(rtd); |
197 | default: |
198 | dev_err(rtd->dev, "%s: invalid dai id 0x%x\n" , __func__, cpu_dai->id); |
199 | } |
200 | |
201 | return -EINVAL; |
202 | } |
203 | |
204 | static int sc7280_snd_hw_params(struct snd_pcm_substream *substream, |
205 | struct snd_pcm_hw_params *params) |
206 | { |
207 | struct snd_pcm_runtime *runtime = substream->runtime; |
208 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
209 | struct snd_soc_dai *codec_dai; |
210 | const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
211 | struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card: rtd->card); |
212 | struct sdw_stream_runtime *sruntime; |
213 | int i; |
214 | |
215 | if (!rtd->dai_link->no_pcm) { |
216 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, min: 2, max: 2); |
217 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, min: 48000, max: 48000); |
218 | } |
219 | |
220 | switch (cpu_dai->id) { |
221 | case LPASS_CDC_DMA_TX3: |
222 | case LPASS_CDC_DMA_RX0: |
223 | case RX_CODEC_DMA_RX_0: |
224 | case SECONDARY_MI2S_RX: |
225 | case TX_CODEC_DMA_TX_3: |
226 | case VA_CODEC_DMA_TX_0: |
227 | for_each_rtd_codec_dais(rtd, i, codec_dai) { |
228 | sruntime = snd_soc_dai_get_stream(dai: codec_dai, direction: substream->stream); |
229 | if (sruntime != ERR_PTR(error: -ENOTSUPP)) |
230 | pdata->sruntime[cpu_dai->id] = sruntime; |
231 | } |
232 | break; |
233 | } |
234 | |
235 | return 0; |
236 | } |
237 | |
238 | static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream) |
239 | { |
240 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
241 | const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
242 | struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card: rtd->card); |
243 | struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; |
244 | int ret; |
245 | |
246 | if (!sruntime) |
247 | return 0; |
248 | |
249 | if (data->stream_prepared[cpu_dai->id]) { |
250 | sdw_disable_stream(stream: sruntime); |
251 | sdw_deprepare_stream(stream: sruntime); |
252 | data->stream_prepared[cpu_dai->id] = false; |
253 | } |
254 | |
255 | ret = sdw_prepare_stream(stream: sruntime); |
256 | if (ret) |
257 | return ret; |
258 | |
259 | ret = sdw_enable_stream(stream: sruntime); |
260 | if (ret) { |
261 | sdw_deprepare_stream(stream: sruntime); |
262 | return ret; |
263 | } |
264 | data->stream_prepared[cpu_dai->id] = true; |
265 | |
266 | return ret; |
267 | } |
268 | |
269 | static int sc7280_snd_prepare(struct snd_pcm_substream *substream) |
270 | { |
271 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
272 | const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
273 | |
274 | switch (cpu_dai->id) { |
275 | case LPASS_CDC_DMA_RX0: |
276 | case LPASS_CDC_DMA_TX3: |
277 | case RX_CODEC_DMA_RX_0: |
278 | case TX_CODEC_DMA_TX_3: |
279 | case VA_CODEC_DMA_TX_0: |
280 | return sc7280_snd_swr_prepare(substream); |
281 | default: |
282 | break; |
283 | } |
284 | |
285 | return 0; |
286 | } |
287 | |
288 | static int sc7280_snd_hw_free(struct snd_pcm_substream *substream) |
289 | { |
290 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
291 | struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card: rtd->card); |
292 | const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
293 | struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; |
294 | |
295 | switch (cpu_dai->id) { |
296 | case LPASS_CDC_DMA_RX0: |
297 | case LPASS_CDC_DMA_TX3: |
298 | case RX_CODEC_DMA_RX_0: |
299 | case TX_CODEC_DMA_TX_3: |
300 | case VA_CODEC_DMA_TX_0: |
301 | if (sruntime && data->stream_prepared[cpu_dai->id]) { |
302 | sdw_disable_stream(stream: sruntime); |
303 | sdw_deprepare_stream(stream: sruntime); |
304 | data->stream_prepared[cpu_dai->id] = false; |
305 | } |
306 | break; |
307 | default: |
308 | break; |
309 | } |
310 | return 0; |
311 | } |
312 | |
313 | static void sc7280_snd_shutdown(struct snd_pcm_substream *substream) |
314 | { |
315 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
316 | struct snd_soc_card *card = rtd->card; |
317 | struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); |
318 | struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
319 | |
320 | switch (cpu_dai->id) { |
321 | case MI2S_PRIMARY: |
322 | if (--data->pri_mi2s_clk_count == 0) { |
323 | snd_soc_dai_set_sysclk(dai: cpu_dai, |
324 | LPASS_MCLK0, |
325 | freq: 0, |
326 | dir: SNDRV_PCM_STREAM_PLAYBACK); |
327 | } |
328 | break; |
329 | case SECONDARY_MI2S_RX: |
330 | snd_soc_dai_set_sysclk(dai: cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, |
331 | freq: 0, dir: SNDRV_PCM_STREAM_PLAYBACK); |
332 | break; |
333 | default: |
334 | break; |
335 | } |
336 | } |
337 | |
338 | static int sc7280_snd_startup(struct snd_pcm_substream *substream) |
339 | { |
340 | unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; |
341 | unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; |
342 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
343 | struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
344 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
345 | int ret = 0; |
346 | |
347 | switch (cpu_dai->id) { |
348 | case MI2S_PRIMARY: |
349 | ret = sc7280_rt5682_init(rtd); |
350 | break; |
351 | case SECONDARY_MI2S_RX: |
352 | codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; |
353 | |
354 | snd_soc_dai_set_sysclk(dai: cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, |
355 | MI2S_BCLK_RATE, dir: SNDRV_PCM_STREAM_PLAYBACK); |
356 | |
357 | snd_soc_dai_set_fmt(dai: cpu_dai, fmt); |
358 | snd_soc_dai_set_fmt(dai: codec_dai, fmt: codec_dai_fmt); |
359 | break; |
360 | default: |
361 | break; |
362 | } |
363 | return ret; |
364 | } |
365 | |
366 | static const struct snd_soc_ops sc7280_ops = { |
367 | .startup = sc7280_snd_startup, |
368 | .hw_params = sc7280_snd_hw_params, |
369 | .hw_free = sc7280_snd_hw_free, |
370 | .prepare = sc7280_snd_prepare, |
371 | .shutdown = sc7280_snd_shutdown, |
372 | }; |
373 | |
374 | static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = { |
375 | SND_SOC_DAPM_HP("Headphone Jack" , NULL), |
376 | SND_SOC_DAPM_MIC("Headset Mic" , NULL), |
377 | }; |
378 | |
379 | static const struct snd_kcontrol_new sc7280_snd_controls[] = { |
380 | SOC_DAPM_PIN_SWITCH("Headphone Jack" ), |
381 | SOC_DAPM_PIN_SWITCH("Headset Mic" ), |
382 | }; |
383 | |
384 | static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, |
385 | struct snd_pcm_hw_params *params) |
386 | { |
387 | struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
388 | struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
389 | struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); |
390 | |
391 | rate->min = rate->max = 48000; |
392 | channels->min = channels->max = 2; |
393 | snd_mask_set_format(mask: fmt, SNDRV_PCM_FORMAT_S16_LE); |
394 | |
395 | return 0; |
396 | } |
397 | |
398 | static int sc7280_snd_platform_probe(struct platform_device *pdev) |
399 | { |
400 | struct snd_soc_card *card; |
401 | struct sc7280_snd_data *data; |
402 | struct device *dev = &pdev->dev; |
403 | struct snd_soc_dai_link *link; |
404 | int ret, i; |
405 | |
406 | data = devm_kzalloc(dev, size: sizeof(*data), GFP_KERNEL); |
407 | if (!data) |
408 | return -ENOMEM; |
409 | |
410 | card = &data->card; |
411 | snd_soc_card_set_drvdata(card, data); |
412 | |
413 | card->owner = THIS_MODULE; |
414 | card->driver_name = "SC7280" ; |
415 | card->dev = dev; |
416 | |
417 | card->dapm_widgets = sc7280_snd_widgets; |
418 | card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets); |
419 | card->controls = sc7280_snd_controls; |
420 | card->num_controls = ARRAY_SIZE(sc7280_snd_controls); |
421 | |
422 | ret = qcom_snd_parse_of(card); |
423 | if (ret) |
424 | return ret; |
425 | |
426 | for_each_card_prelinks(card, i, link) { |
427 | link->init = sc7280_init; |
428 | link->ops = &sc7280_ops; |
429 | if (link->no_pcm == 1) |
430 | link->be_hw_params_fixup = sc7280_snd_be_hw_params_fixup; |
431 | } |
432 | |
433 | return devm_snd_soc_register_card(dev, card); |
434 | } |
435 | |
436 | static const struct of_device_id sc7280_snd_device_id[] = { |
437 | { .compatible = "google,sc7280-herobrine" }, |
438 | {} |
439 | }; |
440 | MODULE_DEVICE_TABLE(of, sc7280_snd_device_id); |
441 | |
442 | static struct platform_driver sc7280_snd_driver = { |
443 | .probe = sc7280_snd_platform_probe, |
444 | .driver = { |
445 | .name = "msm-snd-sc7280" , |
446 | .of_match_table = sc7280_snd_device_id, |
447 | .pm = &snd_soc_pm_ops, |
448 | }, |
449 | }; |
450 | module_platform_driver(sc7280_snd_driver); |
451 | |
452 | MODULE_DESCRIPTION("sc7280 ASoC Machine Driver" ); |
453 | MODULE_LICENSE("GPL" ); |
454 | |