blob: bf4ec4646906133814ac8d8b1546ebe469effc68 [file] [log] [blame]
Rohit kumar6b1687b2018-08-01 14:31:09 +05301// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/module.h>
7#include <linux/platform_device.h>
8#include <linux/atomic.h>
9#include <linux/of_device.h>
10#include <sound/pcm.h>
11#include <sound/pcm_params.h>
12#include <linux/soc/qcom/apr.h>
13#include "common.h"
14#include "qdsp6/q6afe.h"
15
16#define DEFAULT_SAMPLE_RATE_48K 48000
17#define DEFAULT_MCLK_RATE 24576000
18#define DEFAULT_BCLK_RATE 12288000
19
20struct sdm845_snd_data {
21 struct snd_soc_card *card;
22 uint32_t pri_mi2s_clk_count;
23 uint32_t quat_tdm_clk_count;
24};
25
26static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
27
28static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
29 struct snd_pcm_hw_params *params)
30{
31 struct snd_soc_pcm_runtime *rtd = substream->private_data;
32 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
33 int ret = 0;
34 int channels, slot_width;
35
36 switch (params_format(params)) {
37 case SNDRV_PCM_FORMAT_S16_LE:
38 slot_width = 32;
39 break;
40 default:
41 dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
42 __func__, params_format(params));
43 return -EINVAL;
44 }
45
46 channels = params_channels(params);
47 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
48 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3,
49 8, slot_width);
50 if (ret < 0) {
51 dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
52 __func__, ret);
53 goto end;
54 }
55
56 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
57 channels, tdm_slot_offset);
58 if (ret < 0) {
59 dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
60 __func__, ret);
61 goto end;
62 }
63 } else {
64 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0,
65 8, slot_width);
66 if (ret < 0) {
67 dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
68 __func__, ret);
69 goto end;
70 }
71
72 ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
73 tdm_slot_offset, 0, NULL);
74 if (ret < 0) {
75 dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
76 __func__, ret);
77 goto end;
78 }
79 }
80end:
81 return ret;
82}
83
84static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
85 struct snd_pcm_hw_params *params)
86{
87 struct snd_soc_pcm_runtime *rtd = substream->private_data;
88 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
89 int ret = 0;
90
91 switch (cpu_dai->id) {
92 case QUATERNARY_TDM_RX_0:
93 case QUATERNARY_TDM_TX_0:
94 ret = sdm845_tdm_snd_hw_params(substream, params);
95 break;
96 default:
97 pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
98 break;
99 }
100 return ret;
101}
102
103static int sdm845_snd_startup(struct snd_pcm_substream *substream)
104{
105 unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
106 struct snd_soc_pcm_runtime *rtd = substream->private_data;
107 struct snd_soc_card *card = rtd->card;
108 struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
109 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
110
111 switch (cpu_dai->id) {
112 case PRIMARY_MI2S_RX:
113 case PRIMARY_MI2S_TX:
114 if (++(data->pri_mi2s_clk_count) == 1) {
115 snd_soc_dai_set_sysclk(cpu_dai,
116 Q6AFE_LPASS_CLK_ID_MCLK_1,
117 DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
118 snd_soc_dai_set_sysclk(cpu_dai,
119 Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
120 DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
121 }
122 snd_soc_dai_set_fmt(cpu_dai, fmt);
123 break;
124
125 case QUATERNARY_TDM_RX_0:
126 case QUATERNARY_TDM_TX_0:
127 if (++(data->quat_tdm_clk_count) == 1) {
128 snd_soc_dai_set_sysclk(cpu_dai,
129 Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
130 DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
131 }
132 break;
133
134 default:
135 pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
136 break;
137 }
138 return 0;
139}
140
141static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
142{
143 struct snd_soc_pcm_runtime *rtd = substream->private_data;
144 struct snd_soc_card *card = rtd->card;
145 struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
146 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
147
148 switch (cpu_dai->id) {
149 case PRIMARY_MI2S_RX:
150 case PRIMARY_MI2S_TX:
151 if (--(data->pri_mi2s_clk_count) == 0) {
152 snd_soc_dai_set_sysclk(cpu_dai,
153 Q6AFE_LPASS_CLK_ID_MCLK_1,
154 0, SNDRV_PCM_STREAM_PLAYBACK);
155 snd_soc_dai_set_sysclk(cpu_dai,
156 Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
157 0, SNDRV_PCM_STREAM_PLAYBACK);
158 };
159 break;
160
161 case QUATERNARY_TDM_RX_0:
162 case QUATERNARY_TDM_TX_0:
163 if (--(data->quat_tdm_clk_count) == 0) {
164 snd_soc_dai_set_sysclk(cpu_dai,
165 Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
166 0, SNDRV_PCM_STREAM_PLAYBACK);
167 }
168 break;
169
170 default:
171 pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
172 break;
173 }
174}
175
176static struct snd_soc_ops sdm845_be_ops = {
177 .hw_params = sdm845_snd_hw_params,
178 .startup = sdm845_snd_startup,
179 .shutdown = sdm845_snd_shutdown,
180};
181
182static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
183 struct snd_pcm_hw_params *params)
184{
185 struct snd_interval *rate = hw_param_interval(params,
186 SNDRV_PCM_HW_PARAM_RATE);
187 struct snd_interval *channels = hw_param_interval(params,
188 SNDRV_PCM_HW_PARAM_CHANNELS);
189 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
190
191 rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
192 channels->min = channels->max = 2;
193 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
194
195 return 0;
196}
197
198static void sdm845_add_be_ops(struct snd_soc_card *card)
199{
200 struct snd_soc_dai_link *link = card->dai_link;
201 int i, num_links = card->num_links;
202
203 for (i = 0; i < num_links; i++) {
204 if (link->no_pcm == 1) {
205 link->ops = &sdm845_be_ops;
206 link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
207 }
208 link++;
209 }
210}
211
212static int sdm845_snd_platform_probe(struct platform_device *pdev)
213{
214 struct snd_soc_card *card;
215 struct sdm845_snd_data *data;
216 struct device *dev = &pdev->dev;
217 int ret;
218
219 card = kzalloc(sizeof(*card), GFP_KERNEL);
220 if (!card)
221 return -ENOMEM;
222
223 /* Allocate the private data */
224 data = kzalloc(sizeof(*data), GFP_KERNEL);
225 if (!data)
226 return -ENOMEM;
227
228 card->dev = dev;
229 card->auto_bind = true;
230 dev_set_drvdata(dev, card);
231 ret = qcom_snd_parse_of(card);
232 if (ret) {
233 dev_err(dev, "Error parsing OF data\n");
234 goto parse_dt_fail;
235 }
236
237 data->card = card;
238 snd_soc_card_set_drvdata(card, data);
239
240 sdm845_add_be_ops(card);
241 ret = snd_soc_register_card(card);
242 if (ret) {
243 dev_err(dev, "Sound card registration failed\n");
244 goto register_card_fail;
245 }
246 return ret;
247
248register_card_fail:
249 kfree(card->dai_link);
250parse_dt_fail:
251 kfree(data);
252 kfree(card);
253 return ret;
254}
255
256static int sdm845_snd_platform_remove(struct platform_device *pdev)
257{
258 struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
259 struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
260
261 card->auto_bind = false;
262 snd_soc_unregister_card(card);
263 kfree(card->dai_link);
264 kfree(data);
265 kfree(card);
266 return 0;
267}
268
269static const struct of_device_id sdm845_snd_device_id[] = {
270 { .compatible = "qcom,sdm845-sndcard" },
271 {},
272};
273MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
274
275static struct platform_driver sdm845_snd_driver = {
276 .probe = sdm845_snd_platform_probe,
277 .remove = sdm845_snd_platform_remove,
278 .driver = {
279 .name = "msm-snd-sdm845",
280 .of_match_table = sdm845_snd_device_id,
281 },
282};
283module_platform_driver(sdm845_snd_driver);
284
285MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
286MODULE_LICENSE("GPL v2");