1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
6 #include <linux/module.h>
7 #include <linux/platform_device.h>
8 #include <linux/of_device.h>
10 #include <sound/pcm_params.h>
12 #include "qdsp6/q6afe.h"
14 #define DEFAULT_SAMPLE_RATE_48K 48000
15 #define DEFAULT_MCLK_RATE 24576000
16 #define DEFAULT_BCLK_RATE 12288000
18 struct sdm845_snd_data
{
19 struct snd_soc_card
*card
;
20 uint32_t pri_mi2s_clk_count
;
21 uint32_t quat_tdm_clk_count
;
24 static unsigned int tdm_slot_offset
[8] = {0, 4, 8, 12, 16, 20, 24, 28};
26 static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream
*substream
,
27 struct snd_pcm_hw_params
*params
)
29 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
30 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
32 int channels
, slot_width
;
34 switch (params_format(params
)) {
35 case SNDRV_PCM_FORMAT_S16_LE
:
39 dev_err(rtd
->dev
, "%s: invalid param format 0x%x\n",
40 __func__
, params_format(params
));
44 channels
= params_channels(params
);
45 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
46 ret
= snd_soc_dai_set_tdm_slot(cpu_dai
, 0, 0x3,
49 dev_err(rtd
->dev
, "%s: failed to set tdm slot, err:%d\n",
54 ret
= snd_soc_dai_set_channel_map(cpu_dai
, 0, NULL
,
55 channels
, tdm_slot_offset
);
57 dev_err(rtd
->dev
, "%s: failed to set channel map, err:%d\n",
62 ret
= snd_soc_dai_set_tdm_slot(cpu_dai
, 0xf, 0,
65 dev_err(rtd
->dev
, "%s: failed to set tdm slot, err:%d\n",
70 ret
= snd_soc_dai_set_channel_map(cpu_dai
, channels
,
71 tdm_slot_offset
, 0, NULL
);
73 dev_err(rtd
->dev
, "%s: failed to set channel map, err:%d\n",
82 static int sdm845_snd_hw_params(struct snd_pcm_substream
*substream
,
83 struct snd_pcm_hw_params
*params
)
85 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
86 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
89 switch (cpu_dai
->id
) {
90 case QUATERNARY_TDM_RX_0
:
91 case QUATERNARY_TDM_TX_0
:
92 ret
= sdm845_tdm_snd_hw_params(substream
, params
);
95 pr_err("%s: invalid dai id 0x%x\n", __func__
, cpu_dai
->id
);
101 static int sdm845_snd_startup(struct snd_pcm_substream
*substream
)
103 unsigned int fmt
= SND_SOC_DAIFMT_CBS_CFS
;
104 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
105 struct snd_soc_card
*card
= rtd
->card
;
106 struct sdm845_snd_data
*data
= snd_soc_card_get_drvdata(card
);
107 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
109 switch (cpu_dai
->id
) {
110 case PRIMARY_MI2S_RX
:
111 case PRIMARY_MI2S_TX
:
112 if (++(data
->pri_mi2s_clk_count
) == 1) {
113 snd_soc_dai_set_sysclk(cpu_dai
,
114 Q6AFE_LPASS_CLK_ID_MCLK_1
,
115 DEFAULT_MCLK_RATE
, SNDRV_PCM_STREAM_PLAYBACK
);
116 snd_soc_dai_set_sysclk(cpu_dai
,
117 Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT
,
118 DEFAULT_BCLK_RATE
, SNDRV_PCM_STREAM_PLAYBACK
);
120 snd_soc_dai_set_fmt(cpu_dai
, fmt
);
123 case QUATERNARY_TDM_RX_0
:
124 case QUATERNARY_TDM_TX_0
:
125 if (++(data
->quat_tdm_clk_count
) == 1) {
126 snd_soc_dai_set_sysclk(cpu_dai
,
127 Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT
,
128 DEFAULT_BCLK_RATE
, SNDRV_PCM_STREAM_PLAYBACK
);
133 pr_err("%s: invalid dai id 0x%x\n", __func__
, cpu_dai
->id
);
139 static void sdm845_snd_shutdown(struct snd_pcm_substream
*substream
)
141 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
142 struct snd_soc_card
*card
= rtd
->card
;
143 struct sdm845_snd_data
*data
= snd_soc_card_get_drvdata(card
);
144 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
146 switch (cpu_dai
->id
) {
147 case PRIMARY_MI2S_RX
:
148 case PRIMARY_MI2S_TX
:
149 if (--(data
->pri_mi2s_clk_count
) == 0) {
150 snd_soc_dai_set_sysclk(cpu_dai
,
151 Q6AFE_LPASS_CLK_ID_MCLK_1
,
152 0, SNDRV_PCM_STREAM_PLAYBACK
);
153 snd_soc_dai_set_sysclk(cpu_dai
,
154 Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT
,
155 0, SNDRV_PCM_STREAM_PLAYBACK
);
159 case QUATERNARY_TDM_RX_0
:
160 case QUATERNARY_TDM_TX_0
:
161 if (--(data
->quat_tdm_clk_count
) == 0) {
162 snd_soc_dai_set_sysclk(cpu_dai
,
163 Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT
,
164 0, SNDRV_PCM_STREAM_PLAYBACK
);
169 pr_err("%s: invalid dai id 0x%x\n", __func__
, cpu_dai
->id
);
174 static struct snd_soc_ops sdm845_be_ops
= {
175 .hw_params
= sdm845_snd_hw_params
,
176 .startup
= sdm845_snd_startup
,
177 .shutdown
= sdm845_snd_shutdown
,
180 static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime
*rtd
,
181 struct snd_pcm_hw_params
*params
)
183 struct snd_interval
*rate
= hw_param_interval(params
,
184 SNDRV_PCM_HW_PARAM_RATE
);
185 struct snd_interval
*channels
= hw_param_interval(params
,
186 SNDRV_PCM_HW_PARAM_CHANNELS
);
187 struct snd_mask
*fmt
= hw_param_mask(params
, SNDRV_PCM_HW_PARAM_FORMAT
);
189 rate
->min
= rate
->max
= DEFAULT_SAMPLE_RATE_48K
;
190 channels
->min
= channels
->max
= 2;
191 snd_mask_set_format(fmt
, SNDRV_PCM_FORMAT_S16_LE
);
196 static void sdm845_add_be_ops(struct snd_soc_card
*card
)
198 struct snd_soc_dai_link
*link
= card
->dai_link
;
199 int i
, num_links
= card
->num_links
;
201 for (i
= 0; i
< num_links
; i
++) {
202 if (link
->no_pcm
== 1) {
203 link
->ops
= &sdm845_be_ops
;
204 link
->be_hw_params_fixup
= sdm845_be_hw_params_fixup
;
210 static int sdm845_snd_platform_probe(struct platform_device
*pdev
)
212 struct snd_soc_card
*card
;
213 struct sdm845_snd_data
*data
;
214 struct device
*dev
= &pdev
->dev
;
217 card
= kzalloc(sizeof(*card
), GFP_KERNEL
);
221 /* Allocate the private data */
222 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
225 goto data_alloc_fail
;
229 dev_set_drvdata(dev
, card
);
230 ret
= qcom_snd_parse_of(card
);
232 dev_err(dev
, "Error parsing OF data\n");
237 snd_soc_card_set_drvdata(card
, data
);
239 sdm845_add_be_ops(card
);
240 ret
= snd_soc_register_card(card
);
242 dev_err(dev
, "Sound card registration failed\n");
243 goto register_card_fail
;
248 kfree(card
->dai_link
);
256 static int sdm845_snd_platform_remove(struct platform_device
*pdev
)
258 struct snd_soc_card
*card
= dev_get_drvdata(&pdev
->dev
);
259 struct sdm845_snd_data
*data
= snd_soc_card_get_drvdata(card
);
261 snd_soc_unregister_card(card
);
262 kfree(card
->dai_link
);
268 static const struct of_device_id sdm845_snd_device_id
[] = {
269 { .compatible
= "qcom,sdm845-sndcard" },
272 MODULE_DEVICE_TABLE(of
, sdm845_snd_device_id
);
274 static struct platform_driver sdm845_snd_driver
= {
275 .probe
= sdm845_snd_platform_probe
,
276 .remove
= sdm845_snd_platform_remove
,
278 .name
= "msm-snd-sdm845",
279 .of_match_table
= sdm845_snd_device_id
,
282 module_platform_driver(sdm845_snd_driver
);
284 MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
285 MODULE_LICENSE("GPL v2");