blob: 42d53e721928629f53f5d62ff7405a7e9631bff4 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Sanjana B63bdc7b2020-01-20 19:31:18 +05302/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303 */
4
5#include <linux/init.h>
6#include <linux/module.h>
7#include <linux/device.h>
8#include <linux/platform_device.h>
9#include <linux/bitops.h>
10#include <linux/slab.h>
11#include <linux/of_device.h>
12#include <sound/core.h>
13#include <sound/pcm.h>
14#include <sound/soc.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053015#include <sound/pcm_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053016#include <dsp/apr_audio-v2.h>
17#include <dsp/q6afe-v2.h>
18#include "msm-dai-q6-v2.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053019
20#define HDMI_RX_CA_MAX 0x32
21
22enum {
Karthikeyan Mani311bd672019-06-06 13:40:55 -070023 DP_CONTROLLER0 = 0,
24 DP_CONTROLLER1,
25 DP_CONTROLLER_MAX,
26};
27
28enum {
29 DP_STREAM0 = 0,
30 DP_STREAM1,
31 DP_STREAM_MAX,
32};
33
34enum {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053035 STATUS_PORT_STARTED, /* track if AFE port has started */
36 STATUS_MAX
37};
38
39struct msm_ext_disp_ca {
40 bool set_ca;
41 u32 ca;
42};
43
44struct msm_dai_q6_hdmi_dai_data {
45 DECLARE_BITMAP(status_mask, STATUS_MAX);
46 u32 rate;
47 u32 channels;
Karthikeyan Mani44d58882018-05-03 18:30:02 -070048 u32 stream_idx;
49 u32 ctl_idx;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053050 struct msm_ext_disp_ca ca;
51 union afe_port_config port_config;
52};
53
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -070054static int get_port_id(int dai_id)
55{
56 /* Currently, display devices share a common AFE port */
Sanjana B63bdc7b2020-01-20 19:31:18 +053057 if (dai_id != HDMI_RX || dai_id != HDMI_RX_MS)
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -070058 return DISPLAY_PORT_RX;
59
60 return dai_id;
61}
62
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053063static int msm_dai_q6_ext_disp_format_put(struct snd_kcontrol *kcontrol,
64 struct snd_ctl_elem_value *ucontrol)
65{
66 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
67 int value = ucontrol->value.integer.value[0];
68
69 if (!dai_data) {
70 pr_err("%s: dai_data is NULL\n", __func__);
71 return -EINVAL;
72 }
73
74 dai_data->port_config.hdmi_multi_ch.datatype = value;
75 pr_debug("%s: value = %d\n", __func__, value);
76
77 return 0;
78}
79
80static int msm_dai_q6_ext_disp_format_get(struct snd_kcontrol *kcontrol,
81 struct snd_ctl_elem_value *ucontrol)
82{
83 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
84
85 if (!dai_data) {
86 pr_err("%s: dai_data is NULL\n", __func__);
87 return -EINVAL;
88 }
89
90 ucontrol->value.integer.value[0] =
91 dai_data->port_config.hdmi_multi_ch.datatype;
92 pr_debug("%s: value = %ld\n",
93 __func__, ucontrol->value.integer.value[0]);
94
95 return 0;
96}
97
Karthikeyan Mani44d58882018-05-03 18:30:02 -070098static int msm_dai_q6_ext_disp_device_idx_put(struct snd_kcontrol *kcontrol,
99 struct snd_ctl_elem_value *ucontrol)
100{
101 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
102
103 if (!dai_data) {
104 pr_err("%s: dai_data is NULL\n", __func__);
105 return -EINVAL;
106 }
107
Karthikeyan Mani311bd672019-06-06 13:40:55 -0700108 if ((ucontrol->value.integer.value[0] > (DP_CONTROLLER_MAX - 1)) ||
109 (ucontrol->value.integer.value[1] > (DP_STREAM_MAX - 1)) ||
110 (ucontrol->value.integer.value[0] < 0) ||
111 (ucontrol->value.integer.value[1] < 0)) {
112 pr_err("%s: DP control index invalid\n", __func__);
113 return -EINVAL;
114 }
115
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700116 dai_data->ctl_idx = ucontrol->value.integer.value[0];
117 dai_data->stream_idx = ucontrol->value.integer.value[1];
118 pr_debug("%s: DP ctl id %d stream id %d\n", __func__,
119 dai_data->ctl_idx, dai_data->stream_idx);
120
121 return 0;
122}
123
124static int msm_dai_q6_ext_disp_device_idx_get(struct snd_kcontrol *kcontrol,
125 struct snd_ctl_elem_value *ucontrol)
126{
127 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
128
129 if (!dai_data) {
130 pr_err("%s: dai_data is NULL\n", __func__);
131 return -EINVAL;
132 }
133
134 ucontrol->value.integer.value[0] = dai_data->ctl_idx;
135 ucontrol->value.integer.value[1] = dai_data->stream_idx;
136 pr_debug("%s: DP ctl id %d stream id %d\n", __func__,
137 dai_data->ctl_idx, dai_data->stream_idx);
138
139 return 0;
140}
141
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530142static int msm_dai_q6_ext_disp_ca_put(struct snd_kcontrol *kcontrol,
143 struct snd_ctl_elem_value *ucontrol)
144{
145 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
146
147 if (!dai_data) {
148 pr_err("%s: dai_data is NULL\n", __func__);
149 return -EINVAL;
150 }
151
152 dai_data->ca.ca = ucontrol->value.integer.value[0];
153 dai_data->ca.set_ca = true;
154 pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca);
155 return 0;
156}
157
158static int msm_dai_q6_ext_disp_ca_get(struct snd_kcontrol *kcontrol,
159 struct snd_ctl_elem_value *ucontrol)
160{
161 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
162
163 if (!dai_data) {
164 pr_err("%s: dai_data is NULL\n", __func__);
165 return -EINVAL;
166 }
167
168 ucontrol->value.integer.value[0] = dai_data->ca.ca;
169 pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca);
170 return 0;
171}
172
173/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
174 * 0: linear PCM
175 * 1: non-linear PCM
176 */
177static const char * const hdmi_format[] = {
178 "LPCM",
179 "Compr"
180};
181
182static const struct soc_enum hdmi_config_enum[] = {
183 SOC_ENUM_SINGLE_EXT(2, hdmi_format),
184};
185
186static int msm_dai_q6_ext_disp_drift_info(struct snd_kcontrol *kcontrol,
187 struct snd_ctl_elem_info *uinfo)
188{
189 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
190 uinfo->count = sizeof(struct afe_param_id_dev_timing_stats);
191
192 return 0;
193}
194
195static int msm_dai_q6_ext_disp_drift_get(struct snd_kcontrol *kcontrol,
196 struct snd_ctl_elem_value *ucontrol)
197{
198 int ret = -EINVAL;
199 struct afe_param_id_dev_timing_stats timing_stats;
200 struct snd_soc_dai *dai = kcontrol->private_data;
201 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
202
203 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Vignesh Kulothungan2ce67842018-09-25 16:40:29 -0700204 pr_debug("%s: afe port not started. status_mask = %ld\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530205 __func__, *dai_data->status_mask);
206 goto done;
207 }
208
209 memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats));
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700210 ret = afe_get_av_dev_drift(&timing_stats, get_port_id(dai->id));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530211 if (ret) {
212 pr_err("%s: Error getting AFE Drift for port %d, err=%d\n",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700213 __func__, get_port_id(dai->id), ret);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530214
215 ret = -EINVAL;
216 goto done;
217 }
218
219 memcpy(ucontrol->value.bytes.data, (void *)&timing_stats,
220 sizeof(struct afe_param_id_dev_timing_stats));
221done:
222 return ret;
223}
224
225static const struct snd_kcontrol_new hdmi_config_controls[] = {
226 SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
227 msm_dai_q6_ext_disp_format_get,
228 msm_dai_q6_ext_disp_format_put),
229 SOC_SINGLE_MULTI_EXT("HDMI RX CA", SND_SOC_NOPM, 0,
230 HDMI_RX_CA_MAX, 0, 1,
231 msm_dai_q6_ext_disp_ca_get,
232 msm_dai_q6_ext_disp_ca_put),
233 {
234 .access = SNDRV_CTL_ELEM_ACCESS_READ,
235 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
236 .name = "HDMI DRIFT",
237 .info = msm_dai_q6_ext_disp_drift_info,
238 .get = msm_dai_q6_ext_disp_drift_get,
239 },
240};
241
242static const struct snd_kcontrol_new display_port_config_controls[] = {
243 SOC_ENUM_EXT("Display Port RX Format", hdmi_config_enum[0],
244 msm_dai_q6_ext_disp_format_get,
245 msm_dai_q6_ext_disp_format_put),
246 SOC_SINGLE_MULTI_EXT("Display Port RX CA", SND_SOC_NOPM, 0,
247 HDMI_RX_CA_MAX, 0, 1,
248 msm_dai_q6_ext_disp_ca_get,
249 msm_dai_q6_ext_disp_ca_put),
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700250 SOC_SINGLE_MULTI_EXT("Display Port RX DEVICE IDX", SND_SOC_NOPM, 0,
Karthikeyan Mani311bd672019-06-06 13:40:55 -0700251 1, 0, 2,
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700252 msm_dai_q6_ext_disp_device_idx_get,
253 msm_dai_q6_ext_disp_device_idx_put),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530254 {
255 .access = SNDRV_CTL_ELEM_ACCESS_READ,
256 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
257 .name = "DISPLAY_PORT DRIFT",
258 .info = msm_dai_q6_ext_disp_drift_info,
259 .get = msm_dai_q6_ext_disp_drift_get,
260 },
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700261 SOC_ENUM_EXT("Display Port1 RX Format", hdmi_config_enum[0],
262 msm_dai_q6_ext_disp_format_get,
263 msm_dai_q6_ext_disp_format_put),
264 SOC_SINGLE_MULTI_EXT("Display Port1 RX CA", SND_SOC_NOPM, 0,
265 HDMI_RX_CA_MAX, 0, 1,
266 msm_dai_q6_ext_disp_ca_get,
267 msm_dai_q6_ext_disp_ca_put),
268 SOC_SINGLE_MULTI_EXT("Display Port1 RX DEVICE IDX", SND_SOC_NOPM, 0,
269 1, 0, 2,
270 msm_dai_q6_ext_disp_device_idx_get,
271 msm_dai_q6_ext_disp_device_idx_put),
272 {
273 .access = SNDRV_CTL_ELEM_ACCESS_READ,
274 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
275 .name = "DISPLAY_PORT1 DRIFT",
276 .info = msm_dai_q6_ext_disp_drift_info,
277 .get = msm_dai_q6_ext_disp_drift_get,
278 },
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530279};
280
281/* Current implementation assumes hw_param is called once
282 * This may not be the case but what to do when ADM and AFE
283 * port are already opened and parameter changes
284 */
285static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_substream *substream,
286 struct snd_pcm_hw_params *params,
287 struct snd_soc_dai *dai)
288{
289 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
290
291 dai_data->channels = params_channels(params);
292 dai_data->rate = params_rate(params);
293 dai_data->port_config.hdmi_multi_ch.reserved = 0;
294 dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version = 1;
295 dai_data->port_config.hdmi_multi_ch.sample_rate = dai_data->rate;
296 switch (params_format(params)) {
297 case SNDRV_PCM_FORMAT_S16_LE:
298 dai_data->port_config.hdmi_multi_ch.bit_width = 16;
299 break;
300 case SNDRV_PCM_FORMAT_S24_LE:
Ben Romberger8e4368d2017-08-18 15:54:18 -0700301 case SNDRV_PCM_FORMAT_S24_3LE:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530302 dai_data->port_config.hdmi_multi_ch.bit_width = 24;
303 break;
304 }
305
306 /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
307 switch (dai_data->channels) {
308 case 2:
309 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0;
310 break;
311 case 3:
312 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x02;
313 break;
314 case 4:
315 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x06;
316 break;
317 case 5:
318 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0A;
319 break;
320 case 6:
321 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0B;
322 break;
323 case 7:
324 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x12;
325 break;
326 case 8:
327 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x13;
328 break;
329 default:
330 dev_err(dai->dev, "invalid Channels = %u\n",
331 dai_data->channels);
332 return -EINVAL;
333 }
334 dev_dbg(dai->dev, "%s() minor version: %u samplerate: %u bitwidth: %u\n"
335 "num_ch = %u channel_allocation = %u datatype = %d\n", __func__,
336 dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version,
337 dai_data->port_config.hdmi_multi_ch.sample_rate,
338 dai_data->port_config.hdmi_multi_ch.bit_width,
339 dai_data->channels,
340 dai_data->port_config.hdmi_multi_ch.channel_allocation,
341 dai_data->port_config.hdmi_multi_ch.datatype);
342
343 return 0;
344}
345
346
347static void msm_dai_q6_hdmi_shutdown(struct snd_pcm_substream *substream,
348 struct snd_soc_dai *dai)
349{
350 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
351 int rc = 0;
352
353 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
354 pr_info("%s: afe port not started. dai_data->status_mask = %ld\n",
355 __func__, *dai_data->status_mask);
356 return;
357 }
358
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700359 rc = afe_close(get_port_id(dai->id)); /* can block */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530360 if (rc < 0)
361 dev_err(dai->dev, "fail to close AFE port\n");
362
363 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
364 *dai_data->status_mask);
365
366 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
367}
368
369
370static int msm_dai_q6_hdmi_prepare(struct snd_pcm_substream *substream,
371 struct snd_soc_dai *dai)
372{
373 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
374 int rc = 0;
375
376 if (dai_data->ca.set_ca)
377 dai_data->port_config.hdmi_multi_ch.channel_allocation =
378 dai_data->ca.ca;
379
380 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700381 rc = afe_set_display_stream(get_port_id(dai->id), dai_data->stream_idx,
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700382 dai_data->ctl_idx);
383 if (rc < 0) {
384 dev_err(dai->dev, "fail to set AFE ctl, stream ID params %x\n",
385 dai->id);
386 if (rc != -EOPNOTSUPP) {
387 dev_err(dai->dev, "not starting AFE port\n");
388 goto err;
389 }
390 }
391
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700392 rc = afe_port_start(get_port_id(dai->id), &dai_data->port_config,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530393 dai_data->rate);
394 if (rc < 0)
395 dev_err(dai->dev, "fail to open AFE port %x\n",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700396 get_port_id(dai->id));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530397 else
398 set_bit(STATUS_PORT_STARTED,
399 dai_data->status_mask);
400 }
401
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700402err:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530403 return rc;
404}
405
406static inline void msm_dai_q6_hdmi_set_dai_id(struct snd_soc_dai *dai)
407{
408 if (!dai->driver->id) {
409 dev_warn(dai->dev, "DAI driver id is not set\n");
410 return;
411 }
412 dai->id = dai->driver->id;
413}
414
415static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
416{
417 struct msm_dai_q6_hdmi_dai_data *dai_data;
418 const struct snd_kcontrol_new *kcontrol;
419 int rc = 0;
420 struct snd_soc_dapm_route intercon;
421 struct snd_soc_dapm_context *dapm;
422
423 if (!dai || !dai->driver) {
424 pr_err("%s: dai or dai->driver is NULL\n", __func__);
425 return -EINVAL;
426 }
427 dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data),
428 GFP_KERNEL);
429
430 if (!dai_data) {
431 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
432 dai->id);
433 rc = -ENOMEM;
434 } else
435 dev_set_drvdata(dai->dev, dai_data);
436
437 msm_dai_q6_hdmi_set_dai_id(dai);
438
Sanjana B63bdc7b2020-01-20 19:31:18 +0530439 if (dai->driver->id == HDMI_RX || dai->driver->id == HDMI_RX_MS) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530440 kcontrol = &hdmi_config_controls[0];
441 rc = snd_ctl_add(dai->component->card->snd_card,
442 snd_ctl_new1(kcontrol, dai_data));
443
444 kcontrol = &hdmi_config_controls[1];
445 rc = snd_ctl_add(dai->component->card->snd_card,
446 snd_ctl_new1(kcontrol, dai_data));
447
448 kcontrol = &hdmi_config_controls[2];
449 rc = snd_ctl_add(dai->component->card->snd_card,
450 snd_ctl_new1(kcontrol, dai));
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700451 } else if (dai->driver->id == MSM_DISPLAY_PORT) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530452 kcontrol = &display_port_config_controls[0];
453 rc = snd_ctl_add(dai->component->card->snd_card,
454 snd_ctl_new1(kcontrol, dai_data));
455
456 kcontrol = &display_port_config_controls[1];
457 rc = snd_ctl_add(dai->component->card->snd_card,
458 snd_ctl_new1(kcontrol, dai_data));
459
460 kcontrol = &display_port_config_controls[2];
461 rc = snd_ctl_add(dai->component->card->snd_card,
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700462 snd_ctl_new1(kcontrol, dai_data));
463
464 kcontrol = &display_port_config_controls[3];
465 rc = snd_ctl_add(dai->component->card->snd_card,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530466 snd_ctl_new1(kcontrol, dai));
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700467 } else if (dai->driver->id == MSM_DISPLAY_PORT1) {
468 kcontrol = &display_port_config_controls[4];
469 rc = snd_ctl_add(dai->component->card->snd_card,
470 snd_ctl_new1(kcontrol, dai_data));
471
472 kcontrol = &display_port_config_controls[5];
473 rc = snd_ctl_add(dai->component->card->snd_card,
474 snd_ctl_new1(kcontrol, dai_data));
475
476 kcontrol = &display_port_config_controls[6];
477 rc = snd_ctl_add(dai->component->card->snd_card,
478 snd_ctl_new1(kcontrol, dai_data));
479
480 kcontrol = &display_port_config_controls[7];
481 rc = snd_ctl_add(dai->component->card->snd_card,
482 snd_ctl_new1(kcontrol, dai));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530483 } else {
484 dev_err(dai->dev, "%s: Invalid id:%d\n",
485 __func__, dai->driver->id);
486 kfree(dai_data);
487 dev_set_drvdata(dai->dev, NULL);
488 return -EINVAL;
489 }
490
491 dapm = snd_soc_component_get_dapm(dai->component);
492 memset(&intercon, 0, sizeof(intercon));
493 if (!rc) {
494 if (dai->driver->playback.stream_name &&
495 dai->driver->playback.aif_name) {
496 dev_dbg(dai->dev, "%s add route for widget %s",
497 __func__, dai->driver->playback.stream_name);
498 intercon.source = dai->driver->playback.aif_name;
499 intercon.sink = dai->driver->playback.stream_name;
500 dev_dbg(dai->dev, "%s src %s sink %s\n",
501 __func__, intercon.source, intercon.sink);
502 snd_soc_dapm_add_routes(dapm, &intercon, 1);
503 }
504 if (dai->driver->capture.stream_name &&
505 dai->driver->capture.aif_name) {
506 dev_dbg(dai->dev, "%s add route for widget %s",
507 __func__, dai->driver->capture.stream_name);
508 intercon.sink = dai->driver->capture.aif_name;
509 intercon.source = dai->driver->capture.stream_name;
510 dev_dbg(dai->dev, "%s src %s sink %s\n",
511 __func__, intercon.source, intercon.sink);
512 snd_soc_dapm_add_routes(dapm, &intercon, 1);
513 }
514 }
515 return rc;
516}
517
518static int msm_dai_q6_hdmi_dai_remove(struct snd_soc_dai *dai)
519{
520 struct msm_dai_q6_hdmi_dai_data *dai_data;
521 int rc;
522
523 dai_data = dev_get_drvdata(dai->dev);
524
525 /* If AFE port is still up, close it */
526 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700527 rc = afe_close(get_port_id(dai->id)); /* can block */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530528 if (rc < 0)
529 dev_err(dai->dev, "fail to close AFE port\n");
530
531 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
532 }
533 kfree(dai_data);
534
535 return 0;
536}
537
538static struct snd_soc_dai_ops msm_dai_q6_hdmi_ops = {
539 .prepare = msm_dai_q6_hdmi_prepare,
540 .hw_params = msm_dai_q6_hdmi_hw_params,
541 .shutdown = msm_dai_q6_hdmi_shutdown,
542};
543
544static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
545 .playback = {
546 .stream_name = "HDMI Playback",
547 .aif_name = "HDMI",
548 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
549 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
550 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
551 SNDRV_PCM_RATE_192000,
Ben Romberger8e4368d2017-08-18 15:54:18 -0700552 .formats = SNDRV_PCM_FMTBIT_S16_LE |
553 SNDRV_PCM_FMTBIT_S24_LE |
554 SNDRV_PCM_FMTBIT_S24_3LE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530555 .channels_min = 2,
556 .channels_max = 8,
557 .rate_max = 192000,
558 .rate_min = 48000,
559 },
560 .ops = &msm_dai_q6_hdmi_ops,
561 .id = HDMI_RX,
562 .probe = msm_dai_q6_hdmi_dai_probe,
563 .remove = msm_dai_q6_hdmi_dai_remove,
564};
565
Sanjana B63bdc7b2020-01-20 19:31:18 +0530566static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_ms_rx_dai = {
567 .playback = {
568 .stream_name = "HDMI MS Playback",
569 .aif_name = "HDMI_MS",
570 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
571 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
572 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
573 SNDRV_PCM_RATE_192000,
574 .formats = SNDRV_PCM_FMTBIT_S16_LE |
575 SNDRV_PCM_FMTBIT_S24_LE |
576 SNDRV_PCM_FMTBIT_S24_3LE,
577 .channels_min = 2,
578 .channels_max = 8,
579 .rate_max = 192000,
580 .rate_min = 48000,
581 },
582 .ops = &msm_dai_q6_hdmi_ops,
583 .id = HDMI_RX_MS,
584 .probe = msm_dai_q6_hdmi_dai_probe,
585 .remove = msm_dai_q6_hdmi_dai_remove,
586};
587
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530588static struct snd_soc_dai_driver msm_dai_q6_display_port_rx_dai[] = {
589 {
590 .playback = {
591 .stream_name = "Display Port Playback",
592 .aif_name = "DISPLAY_PORT",
593 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
594 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
595 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
596 SNDRV_PCM_RATE_192000,
597 .formats = SNDRV_PCM_FMTBIT_S16_LE |
Ben Romberger8e4368d2017-08-18 15:54:18 -0700598 SNDRV_PCM_FMTBIT_S24_LE |
599 SNDRV_PCM_FMTBIT_S24_3LE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530600 .channels_min = 2,
601 .channels_max = 8,
602 .rate_max = 192000,
603 .rate_min = 48000,
604 },
605 .ops = &msm_dai_q6_hdmi_ops,
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700606 .id = MSM_DISPLAY_PORT,
607 .probe = msm_dai_q6_hdmi_dai_probe,
608 .remove = msm_dai_q6_hdmi_dai_remove,
609 },
610 {
611 .playback = {
612 .stream_name = "Display Port1 Playback",
613 .aif_name = "DISPLAY_PORT1",
614 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
615 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
616 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
617 SNDRV_PCM_RATE_192000,
618 .formats = SNDRV_PCM_FMTBIT_S16_LE |
619 SNDRV_PCM_FMTBIT_S24_LE |
620 SNDRV_PCM_FMTBIT_S24_3LE,
621 .channels_min = 2,
622 .channels_max = 8,
623 .rate_max = 192000,
624 .rate_min = 48000,
625 },
626 .ops = &msm_dai_q6_hdmi_ops,
627 .id = MSM_DISPLAY_PORT1,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530628 .probe = msm_dai_q6_hdmi_dai_probe,
629 .remove = msm_dai_q6_hdmi_dai_remove,
630 },
631};
632
633static const struct snd_soc_component_driver msm_dai_hdmi_q6_component = {
634 .name = "msm-dai-q6-hdmi",
635};
636
637/* To do: change to register DAIs as batch */
638static int msm_dai_q6_hdmi_dev_probe(struct platform_device *pdev)
639{
640 int rc, id;
641 const char *q6_dev_id = "qcom,msm-dai-q6-dev-id";
642
643 rc = of_property_read_u32(pdev->dev.of_node, q6_dev_id, &id);
644 if (rc) {
645 dev_err(&pdev->dev,
646 "%s: missing %s in dt node\n", __func__, q6_dev_id);
647 return rc;
648 }
649
650 pdev->id = id;
651
652 pr_debug("%s: dev name %s, id:%d\n", __func__,
653 dev_name(&pdev->dev), pdev->id);
654
655 switch (pdev->id) {
656 case HDMI_RX:
657 rc = snd_soc_register_component(&pdev->dev,
658 &msm_dai_hdmi_q6_component,
659 &msm_dai_q6_hdmi_hdmi_rx_dai, 1);
660 break;
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700661 case MSM_DISPLAY_PORT:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530662 rc = snd_soc_register_component(&pdev->dev,
663 &msm_dai_hdmi_q6_component,
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700664 &msm_dai_q6_display_port_rx_dai[0], 1);
665 break;
666 case MSM_DISPLAY_PORT1:
667 rc = snd_soc_register_component(&pdev->dev,
668 &msm_dai_hdmi_q6_component,
669 &msm_dai_q6_display_port_rx_dai[1], 1);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530670 break;
Sanjana B63bdc7b2020-01-20 19:31:18 +0530671 case HDMI_RX_MS:
672 rc = snd_soc_register_component(&pdev->dev,
673 &msm_dai_hdmi_q6_component,
674 &msm_dai_q6_hdmi_hdmi_ms_rx_dai, 1);
675 break;
676
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530677 default:
678 dev_err(&pdev->dev, "invalid device ID %d\n", pdev->id);
679 rc = -ENODEV;
680 break;
681 }
682 return rc;
683}
684
685static int msm_dai_q6_hdmi_dev_remove(struct platform_device *pdev)
686{
687 snd_soc_unregister_component(&pdev->dev);
688 return 0;
689}
690
691static const struct of_device_id msm_dai_q6_hdmi_dt_match[] = {
692 {.compatible = "qcom,msm-dai-q6-hdmi"},
693 {}
694};
695MODULE_DEVICE_TABLE(of, msm_dai_q6_hdmi_dt_match);
696
697static struct platform_driver msm_dai_q6_hdmi_driver = {
698 .probe = msm_dai_q6_hdmi_dev_probe,
699 .remove = msm_dai_q6_hdmi_dev_remove,
700 .driver = {
701 .name = "msm-dai-q6-hdmi",
702 .owner = THIS_MODULE,
703 .of_match_table = msm_dai_q6_hdmi_dt_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800704 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530705 },
706};
707
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530708int __init msm_dai_q6_hdmi_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530709{
710 return platform_driver_register(&msm_dai_q6_hdmi_driver);
711}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530712
Asish Bhattacharya5faacb32017-12-04 17:23:15 +0530713void msm_dai_q6_hdmi_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530714{
715 platform_driver_unregister(&msm_dai_q6_hdmi_driver);
716}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530717
718/* Module information */
719MODULE_DESCRIPTION("MSM DSP HDMI DAI driver");
720MODULE_LICENSE("GPL v2");