blob: bcf21b5d9b7b4bd496aec251dd6c1ab52dc0bb99 [file] [log] [blame]
Karthikeyan Mani44d58882018-05-03 18:30:02 -07001/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/bitops.h>
18#include <linux/slab.h>
19#include <linux/of_device.h>
20#include <sound/core.h>
21#include <sound/pcm.h>
22#include <sound/soc.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053023#include <sound/pcm_params.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053024#include <dsp/apr_audio-v2.h>
25#include <dsp/q6afe-v2.h>
26#include "msm-dai-q6-v2.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053027
28#define HDMI_RX_CA_MAX 0x32
29
30enum {
31 STATUS_PORT_STARTED, /* track if AFE port has started */
32 STATUS_MAX
33};
34
35struct msm_ext_disp_ca {
36 bool set_ca;
37 u32 ca;
38};
39
40struct msm_dai_q6_hdmi_dai_data {
41 DECLARE_BITMAP(status_mask, STATUS_MAX);
42 u32 rate;
43 u32 channels;
Karthikeyan Mani44d58882018-05-03 18:30:02 -070044 u32 stream_idx;
45 u32 ctl_idx;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053046 struct msm_ext_disp_ca ca;
47 union afe_port_config port_config;
48};
49
50static int msm_dai_q6_ext_disp_format_put(struct snd_kcontrol *kcontrol,
51 struct snd_ctl_elem_value *ucontrol)
52{
53 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
54 int value = ucontrol->value.integer.value[0];
55
56 if (!dai_data) {
57 pr_err("%s: dai_data is NULL\n", __func__);
58 return -EINVAL;
59 }
60
61 dai_data->port_config.hdmi_multi_ch.datatype = value;
62 pr_debug("%s: value = %d\n", __func__, value);
63
64 return 0;
65}
66
67static int msm_dai_q6_ext_disp_format_get(struct snd_kcontrol *kcontrol,
68 struct snd_ctl_elem_value *ucontrol)
69{
70 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
71
72 if (!dai_data) {
73 pr_err("%s: dai_data is NULL\n", __func__);
74 return -EINVAL;
75 }
76
77 ucontrol->value.integer.value[0] =
78 dai_data->port_config.hdmi_multi_ch.datatype;
79 pr_debug("%s: value = %ld\n",
80 __func__, ucontrol->value.integer.value[0]);
81
82 return 0;
83}
84
Karthikeyan Mani44d58882018-05-03 18:30:02 -070085static int msm_dai_q6_ext_disp_device_idx_put(struct snd_kcontrol *kcontrol,
86 struct snd_ctl_elem_value *ucontrol)
87{
88 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
89
90 if (!dai_data) {
91 pr_err("%s: dai_data is NULL\n", __func__);
92 return -EINVAL;
93 }
94
95 dai_data->ctl_idx = ucontrol->value.integer.value[0];
96 dai_data->stream_idx = ucontrol->value.integer.value[1];
97 pr_debug("%s: DP ctl id %d stream id %d\n", __func__,
98 dai_data->ctl_idx, dai_data->stream_idx);
99
100 return 0;
101}
102
103static int msm_dai_q6_ext_disp_device_idx_get(struct snd_kcontrol *kcontrol,
104 struct snd_ctl_elem_value *ucontrol)
105{
106 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
107
108 if (!dai_data) {
109 pr_err("%s: dai_data is NULL\n", __func__);
110 return -EINVAL;
111 }
112
113 ucontrol->value.integer.value[0] = dai_data->ctl_idx;
114 ucontrol->value.integer.value[1] = dai_data->stream_idx;
115 pr_debug("%s: DP ctl id %d stream id %d\n", __func__,
116 dai_data->ctl_idx, dai_data->stream_idx);
117
118 return 0;
119}
120
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530121static int msm_dai_q6_ext_disp_ca_put(struct snd_kcontrol *kcontrol,
122 struct snd_ctl_elem_value *ucontrol)
123{
124 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
125
126 if (!dai_data) {
127 pr_err("%s: dai_data is NULL\n", __func__);
128 return -EINVAL;
129 }
130
131 dai_data->ca.ca = ucontrol->value.integer.value[0];
132 dai_data->ca.set_ca = true;
133 pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca);
134 return 0;
135}
136
137static int msm_dai_q6_ext_disp_ca_get(struct snd_kcontrol *kcontrol,
138 struct snd_ctl_elem_value *ucontrol)
139{
140 struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
141
142 if (!dai_data) {
143 pr_err("%s: dai_data is NULL\n", __func__);
144 return -EINVAL;
145 }
146
147 ucontrol->value.integer.value[0] = dai_data->ca.ca;
148 pr_debug("%s: ca = %d\n", __func__, dai_data->ca.ca);
149 return 0;
150}
151
152/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
153 * 0: linear PCM
154 * 1: non-linear PCM
155 */
156static const char * const hdmi_format[] = {
157 "LPCM",
158 "Compr"
159};
160
161static const struct soc_enum hdmi_config_enum[] = {
162 SOC_ENUM_SINGLE_EXT(2, hdmi_format),
163};
164
165static int msm_dai_q6_ext_disp_drift_info(struct snd_kcontrol *kcontrol,
166 struct snd_ctl_elem_info *uinfo)
167{
168 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
169 uinfo->count = sizeof(struct afe_param_id_dev_timing_stats);
170
171 return 0;
172}
173
174static int msm_dai_q6_ext_disp_drift_get(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_value *ucontrol)
176{
177 int ret = -EINVAL;
178 struct afe_param_id_dev_timing_stats timing_stats;
179 struct snd_soc_dai *dai = kcontrol->private_data;
180 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
181
182 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
183 pr_err("%s: afe port not started. status_mask = %ld\n",
184 __func__, *dai_data->status_mask);
185 goto done;
186 }
187
188 memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats));
189 ret = afe_get_av_dev_drift(&timing_stats, dai->id);
190 if (ret) {
191 pr_err("%s: Error getting AFE Drift for port %d, err=%d\n",
192 __func__, dai->id, ret);
193
194 ret = -EINVAL;
195 goto done;
196 }
197
198 memcpy(ucontrol->value.bytes.data, (void *)&timing_stats,
199 sizeof(struct afe_param_id_dev_timing_stats));
200done:
201 return ret;
202}
203
204static const struct snd_kcontrol_new hdmi_config_controls[] = {
205 SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
206 msm_dai_q6_ext_disp_format_get,
207 msm_dai_q6_ext_disp_format_put),
208 SOC_SINGLE_MULTI_EXT("HDMI RX CA", SND_SOC_NOPM, 0,
209 HDMI_RX_CA_MAX, 0, 1,
210 msm_dai_q6_ext_disp_ca_get,
211 msm_dai_q6_ext_disp_ca_put),
212 {
213 .access = SNDRV_CTL_ELEM_ACCESS_READ,
214 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
215 .name = "HDMI DRIFT",
216 .info = msm_dai_q6_ext_disp_drift_info,
217 .get = msm_dai_q6_ext_disp_drift_get,
218 },
219};
220
221static const struct snd_kcontrol_new display_port_config_controls[] = {
222 SOC_ENUM_EXT("Display Port RX Format", hdmi_config_enum[0],
223 msm_dai_q6_ext_disp_format_get,
224 msm_dai_q6_ext_disp_format_put),
225 SOC_SINGLE_MULTI_EXT("Display Port RX CA", SND_SOC_NOPM, 0,
226 HDMI_RX_CA_MAX, 0, 1,
227 msm_dai_q6_ext_disp_ca_get,
228 msm_dai_q6_ext_disp_ca_put),
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700229 SOC_SINGLE_MULTI_EXT("Display Port RX DEVICE IDX", SND_SOC_NOPM, 0,
230 1, 0, 1,
231 msm_dai_q6_ext_disp_device_idx_get,
232 msm_dai_q6_ext_disp_device_idx_put),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530233 {
234 .access = SNDRV_CTL_ELEM_ACCESS_READ,
235 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
236 .name = "DISPLAY_PORT DRIFT",
237 .info = msm_dai_q6_ext_disp_drift_info,
238 .get = msm_dai_q6_ext_disp_drift_get,
239 },
240};
241
242/* Current implementation assumes hw_param is called once
243 * This may not be the case but what to do when ADM and AFE
244 * port are already opened and parameter changes
245 */
246static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_substream *substream,
247 struct snd_pcm_hw_params *params,
248 struct snd_soc_dai *dai)
249{
250 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
251
252 dai_data->channels = params_channels(params);
253 dai_data->rate = params_rate(params);
254 dai_data->port_config.hdmi_multi_ch.reserved = 0;
255 dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version = 1;
256 dai_data->port_config.hdmi_multi_ch.sample_rate = dai_data->rate;
257 switch (params_format(params)) {
258 case SNDRV_PCM_FORMAT_S16_LE:
259 dai_data->port_config.hdmi_multi_ch.bit_width = 16;
260 break;
261 case SNDRV_PCM_FORMAT_S24_LE:
Ben Romberger8e4368d2017-08-18 15:54:18 -0700262 case SNDRV_PCM_FORMAT_S24_3LE:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530263 dai_data->port_config.hdmi_multi_ch.bit_width = 24;
264 break;
265 }
266
267 /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
268 switch (dai_data->channels) {
269 case 2:
270 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0;
271 break;
272 case 3:
273 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x02;
274 break;
275 case 4:
276 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x06;
277 break;
278 case 5:
279 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0A;
280 break;
281 case 6:
282 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x0B;
283 break;
284 case 7:
285 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x12;
286 break;
287 case 8:
288 dai_data->port_config.hdmi_multi_ch.channel_allocation = 0x13;
289 break;
290 default:
291 dev_err(dai->dev, "invalid Channels = %u\n",
292 dai_data->channels);
293 return -EINVAL;
294 }
295 dev_dbg(dai->dev, "%s() minor version: %u samplerate: %u bitwidth: %u\n"
296 "num_ch = %u channel_allocation = %u datatype = %d\n", __func__,
297 dai_data->port_config.hdmi_multi_ch.hdmi_cfg_minor_version,
298 dai_data->port_config.hdmi_multi_ch.sample_rate,
299 dai_data->port_config.hdmi_multi_ch.bit_width,
300 dai_data->channels,
301 dai_data->port_config.hdmi_multi_ch.channel_allocation,
302 dai_data->port_config.hdmi_multi_ch.datatype);
303
304 return 0;
305}
306
307
308static void msm_dai_q6_hdmi_shutdown(struct snd_pcm_substream *substream,
309 struct snd_soc_dai *dai)
310{
311 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
312 int rc = 0;
313
314 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
315 pr_info("%s: afe port not started. dai_data->status_mask = %ld\n",
316 __func__, *dai_data->status_mask);
317 return;
318 }
319
320 rc = afe_close(dai->id); /* can block */
321 if (rc < 0)
322 dev_err(dai->dev, "fail to close AFE port\n");
323
324 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
325 *dai_data->status_mask);
326
327 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
328}
329
330
331static int msm_dai_q6_hdmi_prepare(struct snd_pcm_substream *substream,
332 struct snd_soc_dai *dai)
333{
334 struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
335 int rc = 0;
336
337 if (dai_data->ca.set_ca)
338 dai_data->port_config.hdmi_multi_ch.channel_allocation =
339 dai_data->ca.ca;
340
341 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700342
343 rc = afe_set_display_stream(dai->id, dai_data->stream_idx,
344 dai_data->ctl_idx);
345 if (rc < 0) {
346 dev_err(dai->dev, "fail to set AFE ctl, stream ID params %x\n",
347 dai->id);
348 if (rc != -EOPNOTSUPP) {
349 dev_err(dai->dev, "not starting AFE port\n");
350 goto err;
351 }
352 }
353
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530354 rc = afe_port_start(dai->id, &dai_data->port_config,
355 dai_data->rate);
356 if (rc < 0)
357 dev_err(dai->dev, "fail to open AFE port %x\n",
358 dai->id);
359 else
360 set_bit(STATUS_PORT_STARTED,
361 dai_data->status_mask);
362 }
363
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700364err:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530365 return rc;
366}
367
368static inline void msm_dai_q6_hdmi_set_dai_id(struct snd_soc_dai *dai)
369{
370 if (!dai->driver->id) {
371 dev_warn(dai->dev, "DAI driver id is not set\n");
372 return;
373 }
374 dai->id = dai->driver->id;
375}
376
377static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
378{
379 struct msm_dai_q6_hdmi_dai_data *dai_data;
380 const struct snd_kcontrol_new *kcontrol;
381 int rc = 0;
382 struct snd_soc_dapm_route intercon;
383 struct snd_soc_dapm_context *dapm;
384
385 if (!dai || !dai->driver) {
386 pr_err("%s: dai or dai->driver is NULL\n", __func__);
387 return -EINVAL;
388 }
389 dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data),
390 GFP_KERNEL);
391
392 if (!dai_data) {
393 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
394 dai->id);
395 rc = -ENOMEM;
396 } else
397 dev_set_drvdata(dai->dev, dai_data);
398
399 msm_dai_q6_hdmi_set_dai_id(dai);
400
401 if (dai->driver->id == HDMI_RX) {
402 kcontrol = &hdmi_config_controls[0];
403 rc = snd_ctl_add(dai->component->card->snd_card,
404 snd_ctl_new1(kcontrol, dai_data));
405
406 kcontrol = &hdmi_config_controls[1];
407 rc = snd_ctl_add(dai->component->card->snd_card,
408 snd_ctl_new1(kcontrol, dai_data));
409
410 kcontrol = &hdmi_config_controls[2];
411 rc = snd_ctl_add(dai->component->card->snd_card,
412 snd_ctl_new1(kcontrol, dai));
413 } else if (dai->driver->id == DISPLAY_PORT_RX) {
414 kcontrol = &display_port_config_controls[0];
415 rc = snd_ctl_add(dai->component->card->snd_card,
416 snd_ctl_new1(kcontrol, dai_data));
417
418 kcontrol = &display_port_config_controls[1];
419 rc = snd_ctl_add(dai->component->card->snd_card,
420 snd_ctl_new1(kcontrol, dai_data));
421
422 kcontrol = &display_port_config_controls[2];
423 rc = snd_ctl_add(dai->component->card->snd_card,
Karthikeyan Mani44d58882018-05-03 18:30:02 -0700424 snd_ctl_new1(kcontrol, dai_data));
425
426 kcontrol = &display_port_config_controls[3];
427 rc = snd_ctl_add(dai->component->card->snd_card,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530428 snd_ctl_new1(kcontrol, dai));
429 } else {
430 dev_err(dai->dev, "%s: Invalid id:%d\n",
431 __func__, dai->driver->id);
432 kfree(dai_data);
433 dev_set_drvdata(dai->dev, NULL);
434 return -EINVAL;
435 }
436
437 dapm = snd_soc_component_get_dapm(dai->component);
438 memset(&intercon, 0, sizeof(intercon));
439 if (!rc) {
440 if (dai->driver->playback.stream_name &&
441 dai->driver->playback.aif_name) {
442 dev_dbg(dai->dev, "%s add route for widget %s",
443 __func__, dai->driver->playback.stream_name);
444 intercon.source = dai->driver->playback.aif_name;
445 intercon.sink = dai->driver->playback.stream_name;
446 dev_dbg(dai->dev, "%s src %s sink %s\n",
447 __func__, intercon.source, intercon.sink);
448 snd_soc_dapm_add_routes(dapm, &intercon, 1);
449 }
450 if (dai->driver->capture.stream_name &&
451 dai->driver->capture.aif_name) {
452 dev_dbg(dai->dev, "%s add route for widget %s",
453 __func__, dai->driver->capture.stream_name);
454 intercon.sink = dai->driver->capture.aif_name;
455 intercon.source = dai->driver->capture.stream_name;
456 dev_dbg(dai->dev, "%s src %s sink %s\n",
457 __func__, intercon.source, intercon.sink);
458 snd_soc_dapm_add_routes(dapm, &intercon, 1);
459 }
460 }
461 return rc;
462}
463
464static int msm_dai_q6_hdmi_dai_remove(struct snd_soc_dai *dai)
465{
466 struct msm_dai_q6_hdmi_dai_data *dai_data;
467 int rc;
468
469 dai_data = dev_get_drvdata(dai->dev);
470
471 /* If AFE port is still up, close it */
472 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
473 rc = afe_close(dai->id); /* can block */
474 if (rc < 0)
475 dev_err(dai->dev, "fail to close AFE port\n");
476
477 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
478 }
479 kfree(dai_data);
480
481 return 0;
482}
483
484static struct snd_soc_dai_ops msm_dai_q6_hdmi_ops = {
485 .prepare = msm_dai_q6_hdmi_prepare,
486 .hw_params = msm_dai_q6_hdmi_hw_params,
487 .shutdown = msm_dai_q6_hdmi_shutdown,
488};
489
490static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
491 .playback = {
492 .stream_name = "HDMI Playback",
493 .aif_name = "HDMI",
494 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
495 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
496 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
497 SNDRV_PCM_RATE_192000,
Ben Romberger8e4368d2017-08-18 15:54:18 -0700498 .formats = SNDRV_PCM_FMTBIT_S16_LE |
499 SNDRV_PCM_FMTBIT_S24_LE |
500 SNDRV_PCM_FMTBIT_S24_3LE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530501 .channels_min = 2,
502 .channels_max = 8,
503 .rate_max = 192000,
504 .rate_min = 48000,
505 },
506 .ops = &msm_dai_q6_hdmi_ops,
507 .id = HDMI_RX,
508 .probe = msm_dai_q6_hdmi_dai_probe,
509 .remove = msm_dai_q6_hdmi_dai_remove,
510};
511
512static struct snd_soc_dai_driver msm_dai_q6_display_port_rx_dai[] = {
513 {
514 .playback = {
515 .stream_name = "Display Port Playback",
516 .aif_name = "DISPLAY_PORT",
517 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
518 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
519 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
520 SNDRV_PCM_RATE_192000,
521 .formats = SNDRV_PCM_FMTBIT_S16_LE |
Ben Romberger8e4368d2017-08-18 15:54:18 -0700522 SNDRV_PCM_FMTBIT_S24_LE |
523 SNDRV_PCM_FMTBIT_S24_3LE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530524 .channels_min = 2,
525 .channels_max = 8,
526 .rate_max = 192000,
527 .rate_min = 48000,
528 },
529 .ops = &msm_dai_q6_hdmi_ops,
530 .id = DISPLAY_PORT_RX,
531 .probe = msm_dai_q6_hdmi_dai_probe,
532 .remove = msm_dai_q6_hdmi_dai_remove,
533 },
534};
535
536static const struct snd_soc_component_driver msm_dai_hdmi_q6_component = {
537 .name = "msm-dai-q6-hdmi",
538};
539
540/* To do: change to register DAIs as batch */
541static int msm_dai_q6_hdmi_dev_probe(struct platform_device *pdev)
542{
543 int rc, id;
544 const char *q6_dev_id = "qcom,msm-dai-q6-dev-id";
545
546 rc = of_property_read_u32(pdev->dev.of_node, q6_dev_id, &id);
547 if (rc) {
548 dev_err(&pdev->dev,
549 "%s: missing %s in dt node\n", __func__, q6_dev_id);
550 return rc;
551 }
552
553 pdev->id = id;
554
555 pr_debug("%s: dev name %s, id:%d\n", __func__,
556 dev_name(&pdev->dev), pdev->id);
557
558 switch (pdev->id) {
559 case HDMI_RX:
560 rc = snd_soc_register_component(&pdev->dev,
561 &msm_dai_hdmi_q6_component,
562 &msm_dai_q6_hdmi_hdmi_rx_dai, 1);
563 break;
564 case DISPLAY_PORT_RX:
565 rc = snd_soc_register_component(&pdev->dev,
566 &msm_dai_hdmi_q6_component,
567 &msm_dai_q6_display_port_rx_dai[0],
568 ARRAY_SIZE(msm_dai_q6_display_port_rx_dai));
569 break;
570 default:
571 dev_err(&pdev->dev, "invalid device ID %d\n", pdev->id);
572 rc = -ENODEV;
573 break;
574 }
575 return rc;
576}
577
578static int msm_dai_q6_hdmi_dev_remove(struct platform_device *pdev)
579{
580 snd_soc_unregister_component(&pdev->dev);
581 return 0;
582}
583
584static const struct of_device_id msm_dai_q6_hdmi_dt_match[] = {
585 {.compatible = "qcom,msm-dai-q6-hdmi"},
586 {}
587};
588MODULE_DEVICE_TABLE(of, msm_dai_q6_hdmi_dt_match);
589
590static struct platform_driver msm_dai_q6_hdmi_driver = {
591 .probe = msm_dai_q6_hdmi_dev_probe,
592 .remove = msm_dai_q6_hdmi_dev_remove,
593 .driver = {
594 .name = "msm-dai-q6-hdmi",
595 .owner = THIS_MODULE,
596 .of_match_table = msm_dai_q6_hdmi_dt_match,
597 },
598};
599
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530600int __init msm_dai_q6_hdmi_init(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530601{
602 return platform_driver_register(&msm_dai_q6_hdmi_driver);
603}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530604
Asish Bhattacharya5faacb32017-12-04 17:23:15 +0530605void msm_dai_q6_hdmi_exit(void)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530606{
607 platform_driver_unregister(&msm_dai_q6_hdmi_driver);
608}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530609
610/* Module information */
611MODULE_DESCRIPTION("MSM DSP HDMI DAI driver");
612MODULE_LICENSE("GPL v2");