xref: /linux/sound/soc/qcom/sm8250.c (revision 813b46808822db6838c43e92ba21ce013d23fcdc)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020, Linaro Limited
3 
4 #include <dt-bindings/sound/qcom,q6afe.h>
5 #include <linux/module.h>
6 #include <linux/platform_device.h>
7 #include <sound/soc.h>
8 #include <sound/soc-dapm.h>
9 #include <sound/pcm.h>
10 #include <sound/pcm_params.h>
11 #include <linux/soundwire/sdw.h>
12 #include <sound/jack.h>
13 #include <linux/input-event-codes.h>
14 #include "qdsp6/q6afe.h"
15 #include "common.h"
16 #include "usb_offload_utils.h"
17 #include "sdw.h"
18 
19 #define DRIVER_NAME		"sm8250"
20 #define MI2S_BCLK_RATE		1536000
21 
22 struct sm8250_snd_data {
23 	bool stream_prepared[AFE_PORT_MAX];
24 	struct snd_soc_card *card;
25 	struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
26 	struct snd_soc_jack jack;
27 	struct snd_soc_jack usb_offload_jack;
28 	bool usb_offload_jack_setup;
29 	bool jack_setup;
30 };
31 
32 static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd)
33 {
34 	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
35 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
36 	int ret;
37 
38 	if (cpu_dai->id == USB_RX)
39 		ret = qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack,
40 						      &data->usb_offload_jack_setup);
41 	else
42 		ret = qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
43 	return ret;
44 }
45 
46 static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd)
47 {
48 	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
49 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
50 
51 	if (cpu_dai->id == USB_RX)
52 		qcom_snd_usb_offload_jack_remove(rtd,
53 						 &data->usb_offload_jack_setup);
54 
55 }
56 
57 static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
58 				     struct snd_pcm_hw_params *params)
59 {
60 	struct snd_interval *rate = hw_param_interval(params,
61 					SNDRV_PCM_HW_PARAM_RATE);
62 	struct snd_interval *channels = hw_param_interval(params,
63 					SNDRV_PCM_HW_PARAM_CHANNELS);
64 	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
65 
66 	rate->min = rate->max = 48000;
67 	channels->min = channels->max = 2;
68 	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
69 
70 	return 0;
71 }
72 
73 static int sm8250_snd_startup(struct snd_pcm_substream *substream)
74 {
75 	unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
76 	unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
77 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
78 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
79 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
80 
81 	switch (cpu_dai->id) {
82 	case PRIMARY_MI2S_RX:
83 		codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
84 		snd_soc_dai_set_sysclk(cpu_dai,
85 			Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
86 			MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
87 		snd_soc_dai_set_fmt(cpu_dai, fmt);
88 		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
89 		break;
90 	case SECONDARY_MI2S_RX:
91 		codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
92 		snd_soc_dai_set_sysclk(cpu_dai,
93 			Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
94 			MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
95 		snd_soc_dai_set_fmt(cpu_dai, fmt);
96 		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
97 		break;
98 	case TERTIARY_MI2S_RX:
99 		codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
100 		snd_soc_dai_set_sysclk(cpu_dai,
101 			Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
102 			MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
103 		snd_soc_dai_set_fmt(cpu_dai, fmt);
104 		snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
105 		break;
106 	default:
107 		break;
108 	}
109 
110 	return qcom_snd_sdw_startup(substream);
111 }
112 
113 static void sm8250_snd_shutdown(struct snd_pcm_substream *substream)
114 {
115 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
116 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
117 	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
118 	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
119 
120 	data->sruntime[cpu_dai->id] = NULL;
121 	sdw_release_stream(sruntime);
122 }
123 
124 static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
125 				struct snd_pcm_hw_params *params)
126 {
127 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
128 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
129 	struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
130 
131 	return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
132 }
133 
134 static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
135 {
136 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
137 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
138 	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
139 	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
140 
141 	return qcom_snd_sdw_prepare(substream, sruntime,
142 				    &data->stream_prepared[cpu_dai->id]);
143 }
144 
145 static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
146 {
147 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
148 	struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
149 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
150 	struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
151 
152 	return qcom_snd_sdw_hw_free(substream, sruntime,
153 				    &data->stream_prepared[cpu_dai->id]);
154 }
155 
156 static const struct snd_soc_ops sm8250_be_ops = {
157 	.startup = sm8250_snd_startup,
158 	.shutdown = sm8250_snd_shutdown,
159 	.hw_params = sm8250_snd_hw_params,
160 	.hw_free = sm8250_snd_hw_free,
161 	.prepare = sm8250_snd_prepare,
162 };
163 
164 static void sm8250_add_be_ops(struct snd_soc_card *card)
165 {
166 	struct snd_soc_dai_link *link;
167 	int i;
168 
169 	for_each_card_prelinks(card, i, link) {
170 		if (link->no_pcm == 1) {
171 			link->init = sm8250_snd_init;
172 			link->exit = sm8250_snd_exit;
173 			link->be_hw_params_fixup = sm8250_be_hw_params_fixup;
174 			link->ops = &sm8250_be_ops;
175 		}
176 	}
177 }
178 
179 static int sm8250_platform_probe(struct platform_device *pdev)
180 {
181 	struct snd_soc_card *card;
182 	struct sm8250_snd_data *data;
183 	struct device *dev = &pdev->dev;
184 	int ret;
185 
186 	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
187 	if (!card)
188 		return -ENOMEM;
189 
190 	card->owner = THIS_MODULE;
191 	/* Allocate the private data */
192 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
193 	if (!data)
194 		return -ENOMEM;
195 
196 	card->dev = dev;
197 	dev_set_drvdata(dev, card);
198 	snd_soc_card_set_drvdata(card, data);
199 	ret = qcom_snd_parse_of(card);
200 	if (ret)
201 		return ret;
202 
203 	card->driver_name = DRIVER_NAME;
204 	sm8250_add_be_ops(card);
205 	return devm_snd_soc_register_card(dev, card);
206 }
207 
208 static const struct of_device_id snd_sm8250_dt_match[] = {
209 	{.compatible = "qcom,sm8250-sndcard"},
210 	{.compatible = "qcom,qrb4210-rb2-sndcard"},
211 	{.compatible = "qcom,qrb5165-rb5-sndcard"},
212 	{}
213 };
214 
215 MODULE_DEVICE_TABLE(of, snd_sm8250_dt_match);
216 
217 static struct platform_driver snd_sm8250_driver = {
218 	.probe  = sm8250_platform_probe,
219 	.driver = {
220 		.name = "snd-sm8250",
221 		.of_match_table = snd_sm8250_dt_match,
222 	},
223 };
224 module_platform_driver(snd_sm8250_driver);
225 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
226 MODULE_DESCRIPTION("SM8250 ASoC Machine Driver");
227 MODULE_LICENSE("GPL");
228