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