55// sc7180.c -- ALSA SoC Machine driver for SC7180
66
77#include <dt-bindings/sound/sc7180-lpass.h>
8+ #include <dt-bindings/sound/qcom,q6afe.h>
89#include <linux/gpio.h>
910#include <linux/gpio/consumer.h>
1011#include <linux/module.h>
1920#include "../codecs/rt5682.h"
2021#include "../codecs/rt5682s.h"
2122#include "common.h"
23+ #include "qdsp6/q6afe.h"
2224
2325#define DEFAULT_MCLK_RATE 19200000
26+ #define MI2S_BCLK_RATE 1536000
2427#define RT5682_PLL1_FREQ (48000 * 512)
2528
2629#define DRIVER_NAME "SC7180"
@@ -133,12 +136,28 @@ static int sc7180_init(struct snd_soc_pcm_runtime *rtd)
133136 return 0 ;
134137}
135138
136- static int sc7180_snd_startup (struct snd_pcm_substream * substream )
139+ static int sc7180_qdsp_init (struct snd_soc_pcm_runtime * rtd )
137140{
138- struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
139- struct snd_soc_card * card = rtd -> card ;
140- struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
141141 struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
142+
143+ switch (cpu_dai -> id ) {
144+ case PRIMARY_MI2S_RX :
145+ return sc7180_headset_init (rtd );
146+ case PRIMARY_MI2S_TX :
147+ case TERTIARY_MI2S_RX :
148+ return 0 ;
149+ case DISPLAY_PORT_RX :
150+ return sc7180_hdmi_init (rtd );
151+ default :
152+ dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
153+ cpu_dai -> id );
154+ return - EINVAL ;
155+ }
156+ return 0 ;
157+ }
158+
159+ static int sc7180_startup_realtek_codec (struct snd_soc_pcm_runtime * rtd )
160+ {
142161 struct snd_soc_dai * codec_dai = snd_soc_rtd_to_codec (rtd , 0 );
143162 int pll_id , pll_source , pll_in , pll_out , clk_id , ret ;
144163
@@ -154,8 +173,40 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
154173 clk_id = RT5682S_SCLK_S_PLL2 ;
155174 pll_out = RT5682_PLL1_FREQ ;
156175 pll_in = DEFAULT_MCLK_RATE ;
176+ } else {
177+ return 0 ;
178+ }
179+ snd_soc_dai_set_fmt (codec_dai ,
180+ SND_SOC_DAIFMT_BC_FC |
181+ SND_SOC_DAIFMT_NB_NF |
182+ SND_SOC_DAIFMT_I2S );
183+
184+ /* Configure PLL1 for codec */
185+ ret = snd_soc_dai_set_pll (codec_dai , pll_id , pll_source ,
186+ pll_in , pll_out );
187+ if (ret ) {
188+ dev_err (rtd -> dev , "can't set codec pll: %d\n" , ret );
189+ return ret ;
157190 }
158191
192+ /* Configure sysclk for codec */
193+ ret = snd_soc_dai_set_sysclk (codec_dai , clk_id , pll_out ,
194+ SND_SOC_CLOCK_IN );
195+ if (ret )
196+ dev_err (rtd -> dev , "snd_soc_dai_set_sysclk err = %d\n" ,
197+ ret );
198+
199+ return ret ;
200+ }
201+
202+ static int sc7180_snd_startup (struct snd_pcm_substream * substream )
203+ {
204+ struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
205+ struct snd_soc_card * card = rtd -> card ;
206+ struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
207+ struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
208+ int ret ;
209+
159210 switch (cpu_dai -> id ) {
160211 case MI2S_PRIMARY :
161212 if (++ data -> pri_mi2s_clk_count == 1 ) {
@@ -165,30 +216,66 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
165216 SNDRV_PCM_STREAM_PLAYBACK );
166217 }
167218
168- snd_soc_dai_set_fmt (codec_dai ,
169- SND_SOC_DAIFMT_BC_FC |
170- SND_SOC_DAIFMT_NB_NF |
171- SND_SOC_DAIFMT_I2S );
172-
173- /* Configure PLL1 for codec */
174- ret = snd_soc_dai_set_pll (codec_dai , pll_id , pll_source ,
175- pll_in , pll_out );
176- if (ret ) {
177- dev_err (rtd -> dev , "can't set codec pll: %d\n" , ret );
219+ ret = sc7180_startup_realtek_codec (rtd );
220+ if (ret )
178221 return ret ;
222+
223+ break ;
224+ case MI2S_SECONDARY :
225+ break ;
226+ case LPASS_DP_RX :
227+ break ;
228+ default :
229+ dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
230+ cpu_dai -> id );
231+ return - EINVAL ;
232+ }
233+ return 0 ;
234+ }
235+
236+ static int sc7180_qdsp_snd_startup (struct snd_pcm_substream * substream )
237+ {
238+ struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
239+ struct snd_soc_card * card = rtd -> card ;
240+ struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
241+ struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
242+ struct snd_soc_dai * codec_dai = snd_soc_rtd_to_codec (rtd , 0 );
243+ int ret ;
244+
245+ switch (cpu_dai -> id ) {
246+ case PRIMARY_MI2S_RX :
247+ case PRIMARY_MI2S_TX :
248+ if (++ data -> pri_mi2s_clk_count == 1 ) {
249+ snd_soc_dai_set_sysclk (cpu_dai ,
250+ Q6AFE_LPASS_CLK_ID_MCLK_1 ,
251+ DEFAULT_MCLK_RATE ,
252+ SNDRV_PCM_STREAM_PLAYBACK );
253+ snd_soc_dai_set_sysclk (cpu_dai ,
254+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ,
255+ MI2S_BCLK_RATE ,
256+ SNDRV_PCM_STREAM_PLAYBACK );
179257 }
180258
181- /* Configure sysclk for codec */
182- ret = snd_soc_dai_set_sysclk ( codec_dai , clk_id , pll_out ,
183- SND_SOC_CLOCK_IN );
259+ snd_soc_dai_set_fmt ( cpu_dai , SND_SOC_DAIFMT_BP_FP );
260+
261+ ret = sc7180_startup_realtek_codec ( rtd );
184262 if (ret )
185- dev_err (rtd -> dev , "snd_soc_dai_set_sysclk err = %d\n" ,
186- ret );
263+ return ret ;
187264
188265 break ;
189- case MI2S_SECONDARY :
266+ case TERTIARY_MI2S_RX :
267+ snd_soc_dai_set_sysclk (cpu_dai ,
268+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT ,
269+ MI2S_BCLK_RATE ,
270+ SNDRV_PCM_STREAM_PLAYBACK );
271+
272+ snd_soc_dai_set_fmt (codec_dai ,
273+ SND_SOC_DAIFMT_BC_FC |
274+ SND_SOC_DAIFMT_NB_NF |
275+ SND_SOC_DAIFMT_I2S );
276+ snd_soc_dai_set_fmt (cpu_dai , SND_SOC_DAIFMT_BP_FP );
190277 break ;
191- case LPASS_DP_RX :
278+ case DISPLAY_PORT_RX :
192279 break ;
193280 default :
194281 dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
@@ -246,6 +333,42 @@ static void sc7180_snd_shutdown(struct snd_pcm_substream *substream)
246333 }
247334}
248335
336+ static void sc7180_qdsp_snd_shutdown (struct snd_pcm_substream * substream )
337+ {
338+ struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
339+ struct snd_soc_card * card = rtd -> card ;
340+ struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
341+ struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
342+
343+ switch (cpu_dai -> id ) {
344+ case PRIMARY_MI2S_RX :
345+ case PRIMARY_MI2S_TX :
346+ if (-- data -> pri_mi2s_clk_count == 0 ) {
347+ snd_soc_dai_set_sysclk (cpu_dai ,
348+ Q6AFE_LPASS_CLK_ID_MCLK_1 ,
349+ 0 ,
350+ SNDRV_PCM_STREAM_PLAYBACK );
351+ snd_soc_dai_set_sysclk (cpu_dai ,
352+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ,
353+ 0 ,
354+ SNDRV_PCM_STREAM_PLAYBACK );
355+ }
356+ break ;
357+ case TERTIARY_MI2S_RX :
358+ snd_soc_dai_set_sysclk (cpu_dai ,
359+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT ,
360+ 0 ,
361+ SNDRV_PCM_STREAM_PLAYBACK );
362+ break ;
363+ case DISPLAY_PORT_RX :
364+ break ;
365+ default :
366+ dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
367+ cpu_dai -> id );
368+ break ;
369+ }
370+ }
371+
249372static int sc7180_adau7002_init (struct snd_soc_pcm_runtime * rtd )
250373{
251374 struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
@@ -294,11 +417,30 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
294417 return 0 ;
295418}
296419
420+ static int sc7180_qdsp_be_hw_params_fixup (struct snd_soc_pcm_runtime * rtd ,
421+ struct snd_pcm_hw_params * params )
422+ {
423+ struct snd_interval * rate = hw_param_interval (params ,
424+ SNDRV_PCM_HW_PARAM_RATE );
425+ struct snd_interval * channels = hw_param_interval (params ,
426+ SNDRV_PCM_HW_PARAM_CHANNELS );
427+
428+ rate -> min = rate -> max = 48000 ;
429+ channels -> min = channels -> max = 2 ;
430+
431+ return 0 ;
432+ }
433+
297434static const struct snd_soc_ops sc7180_ops = {
298435 .startup = sc7180_snd_startup ,
299436 .shutdown = sc7180_snd_shutdown ,
300437};
301438
439+ static const struct snd_soc_ops sc7180_qdsp_ops = {
440+ .startup = sc7180_qdsp_snd_startup ,
441+ .shutdown = sc7180_qdsp_snd_shutdown ,
442+ };
443+
302444static const struct snd_soc_ops sc7180_adau7002_ops = {
303445 .startup = sc7180_adau7002_snd_startup ,
304446};
@@ -354,7 +496,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
354496 struct snd_soc_dai_link * link ;
355497 int ret ;
356498 int i ;
357- bool no_headphone = false;
499+ bool qdsp = false, no_headphone = false;
358500
359501 /* Allocate the private data */
360502 data = devm_kzalloc (dev , sizeof (* data ), GFP_KERNEL );
@@ -390,6 +532,8 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
390532 no_headphone = true;
391533 card -> dapm_widgets = sc7180_adau7002_snd_widgets ;
392534 card -> num_dapm_widgets = ARRAY_SIZE (sc7180_adau7002_snd_widgets );
535+ } else if (of_device_is_compatible (dev -> of_node , "qcom,sc7180-qdsp6-sndcard" )) {
536+ qdsp = true;
393537 }
394538
395539 ret = qcom_snd_parse_of (card );
@@ -400,6 +544,12 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
400544 if (no_headphone ) {
401545 link -> ops = & sc7180_adau7002_ops ;
402546 link -> init = sc7180_adau7002_init ;
547+ } else if (qdsp ) {
548+ if (link -> no_pcm == 1 ) {
549+ link -> ops = & sc7180_qdsp_ops ;
550+ link -> be_hw_params_fixup = sc7180_qdsp_be_hw_params_fixup ;
551+ link -> init = sc7180_qdsp_init ;
552+ }
403553 } else {
404554 link -> ops = & sc7180_ops ;
405555 link -> init = sc7180_init ;
@@ -412,6 +562,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
412562static const struct of_device_id sc7180_snd_device_id [] = {
413563 {.compatible = "google,sc7180-trogdor" },
414564 {.compatible = "google,sc7180-coachz" },
565+ {.compatible = "qcom,sc7180-qdsp6-sndcard" },
415566 {},
416567};
417568MODULE_DEVICE_TABLE (of , sc7180_snd_device_id );
0 commit comments