1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020, Linaro Limited
4 #include <dt-bindings/sound/qcom,q6afe.h>
5 #include <linux/module.h>
6 #include <linux/platform_device.h>
8 #include <sound/soc-dapm.h>
10 #include <linux/soundwire/sdw.h>
11 #include <sound/jack.h>
12 #include <linux/input-event-codes.h>
13 #include "qdsp6/q6afe.h"
17 #define DRIVER_NAME "sm8250"
18 #define MI2S_BCLK_RATE 1536000
20 struct sm8250_snd_data
{
21 bool stream_prepared
[AFE_PORT_MAX
];
22 struct snd_soc_card
*card
;
23 struct sdw_stream_runtime
*sruntime
[AFE_PORT_MAX
];
24 struct snd_soc_jack jack
;
28 static int sm8250_snd_init(struct snd_soc_pcm_runtime
*rtd
)
30 struct sm8250_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
32 return qcom_snd_wcd_jack_setup(rtd
, &data
->jack
, &data
->jack_setup
);
35 static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime
*rtd
,
36 struct snd_pcm_hw_params
*params
)
38 struct snd_interval
*rate
= hw_param_interval(params
,
39 SNDRV_PCM_HW_PARAM_RATE
);
40 struct snd_interval
*channels
= hw_param_interval(params
,
41 SNDRV_PCM_HW_PARAM_CHANNELS
);
43 rate
->min
= rate
->max
= 48000;
44 channels
->min
= channels
->max
= 2;
49 static int sm8250_snd_startup(struct snd_pcm_substream
*substream
)
51 unsigned int fmt
= SND_SOC_DAIFMT_BP_FP
;
52 unsigned int codec_dai_fmt
= SND_SOC_DAIFMT_BC_FC
;
53 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
54 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
55 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
57 switch (cpu_dai
->id
) {
59 codec_dai_fmt
|= SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_I2S
;
60 snd_soc_dai_set_sysclk(cpu_dai
,
61 Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT
,
62 MI2S_BCLK_RATE
, SNDRV_PCM_STREAM_PLAYBACK
);
63 snd_soc_dai_set_fmt(cpu_dai
, fmt
);
64 snd_soc_dai_set_fmt(codec_dai
, codec_dai_fmt
);
66 case SECONDARY_MI2S_RX
:
67 codec_dai_fmt
|= SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_I2S
;
68 snd_soc_dai_set_sysclk(cpu_dai
,
69 Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT
,
70 MI2S_BCLK_RATE
, SNDRV_PCM_STREAM_PLAYBACK
);
71 snd_soc_dai_set_fmt(cpu_dai
, fmt
);
72 snd_soc_dai_set_fmt(codec_dai
, codec_dai_fmt
);
74 case TERTIARY_MI2S_RX
:
75 codec_dai_fmt
|= SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_I2S
;
76 snd_soc_dai_set_sysclk(cpu_dai
,
77 Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT
,
78 MI2S_BCLK_RATE
, SNDRV_PCM_STREAM_PLAYBACK
);
79 snd_soc_dai_set_fmt(cpu_dai
, fmt
);
80 snd_soc_dai_set_fmt(codec_dai
, codec_dai_fmt
);
86 return qcom_snd_sdw_startup(substream
);
89 static void sm8250_snd_shutdown(struct snd_pcm_substream
*substream
)
91 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
92 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
93 struct sm8250_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
94 struct sdw_stream_runtime
*sruntime
= data
->sruntime
[cpu_dai
->id
];
96 data
->sruntime
[cpu_dai
->id
] = NULL
;
97 sdw_release_stream(sruntime
);
100 static int sm8250_snd_hw_params(struct snd_pcm_substream
*substream
,
101 struct snd_pcm_hw_params
*params
)
103 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
104 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
105 struct sm8250_snd_data
*pdata
= snd_soc_card_get_drvdata(rtd
->card
);
107 return qcom_snd_sdw_hw_params(substream
, params
, &pdata
->sruntime
[cpu_dai
->id
]);
110 static int sm8250_snd_prepare(struct snd_pcm_substream
*substream
)
112 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
113 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
114 struct sm8250_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
115 struct sdw_stream_runtime
*sruntime
= data
->sruntime
[cpu_dai
->id
];
117 return qcom_snd_sdw_prepare(substream
, sruntime
,
118 &data
->stream_prepared
[cpu_dai
->id
]);
121 static int sm8250_snd_hw_free(struct snd_pcm_substream
*substream
)
123 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
124 struct sm8250_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
125 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
126 struct sdw_stream_runtime
*sruntime
= data
->sruntime
[cpu_dai
->id
];
128 return qcom_snd_sdw_hw_free(substream
, sruntime
,
129 &data
->stream_prepared
[cpu_dai
->id
]);
132 static const struct snd_soc_ops sm8250_be_ops
= {
133 .startup
= sm8250_snd_startup
,
134 .shutdown
= sm8250_snd_shutdown
,
135 .hw_params
= sm8250_snd_hw_params
,
136 .hw_free
= sm8250_snd_hw_free
,
137 .prepare
= sm8250_snd_prepare
,
140 static void sm8250_add_be_ops(struct snd_soc_card
*card
)
142 struct snd_soc_dai_link
*link
;
145 for_each_card_prelinks(card
, i
, link
) {
146 if (link
->no_pcm
== 1) {
147 link
->init
= sm8250_snd_init
;
148 link
->be_hw_params_fixup
= sm8250_be_hw_params_fixup
;
149 link
->ops
= &sm8250_be_ops
;
154 static int sm8250_platform_probe(struct platform_device
*pdev
)
156 struct snd_soc_card
*card
;
157 struct sm8250_snd_data
*data
;
158 struct device
*dev
= &pdev
->dev
;
161 card
= devm_kzalloc(dev
, sizeof(*card
), GFP_KERNEL
);
165 card
->owner
= THIS_MODULE
;
166 /* Allocate the private data */
167 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
172 dev_set_drvdata(dev
, card
);
173 snd_soc_card_set_drvdata(card
, data
);
174 ret
= qcom_snd_parse_of(card
);
178 card
->driver_name
= DRIVER_NAME
;
179 sm8250_add_be_ops(card
);
180 return devm_snd_soc_register_card(dev
, card
);
183 static const struct of_device_id snd_sm8250_dt_match
[] = {
184 {.compatible
= "qcom,sm8250-sndcard"},
185 {.compatible
= "qcom,qrb4210-rb2-sndcard"},
186 {.compatible
= "qcom,qrb5165-rb5-sndcard"},
190 MODULE_DEVICE_TABLE(of
, snd_sm8250_dt_match
);
192 static struct platform_driver snd_sm8250_driver
= {
193 .probe
= sm8250_platform_probe
,
195 .name
= "snd-sm8250",
196 .of_match_table
= snd_sm8250_dt_match
,
199 module_platform_driver(snd_sm8250_driver
);
200 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
201 MODULE_DESCRIPTION("SM8250 ASoC Machine Driver");
202 MODULE_LICENSE("GPL");