blob: 07e1cef370d568c9811b6501a999f6453640f3fd [file] [log] [blame]
Karthikeyan Manifc1e9722018-05-03 18:38:56 -07001/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
Asish Bhattacharya366f7502017-07-25 15:15:56 +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#include <linux/platform_device.h>
13#include <linux/slab.h>
14#include <linux/module.h>
15#include <linux/of_device.h>
16#include <linux/err.h>
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/soc.h>
20#include <linux/msm_ext_display.h>
21
22#define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000
23#define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT)
24#define AUD_EXT_DISP_ACK_CONNECT (AUDIO_ACK_CONNECT)
25#define AUD_EXT_DISP_ACK_ENABLE (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE)
26
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070027#define SOC_EXT_DISP_AUDIO_TYPE(index) \
28 static SOC_ENUM_SINGLE_DECL(ext_disp_audio_type##index, SND_SOC_NOPM, \
29 index, ext_disp_audio_type_text)
30#define SOC_EXT_DISP_AUDIO_ACK_STATE(index) \
31 static SOC_ENUM_SINGLE_DECL(ext_disp_audio_ack_state##index, \
32 SND_SOC_NOPM, index, ext_disp_audio_ack_text)
33
34#define SWITCH_DP_CODEC(codec_info, codec_data, dai_id) \
35 codec_info.type = EXT_DISPLAY_TYPE_DP; \
36 codec_info.ctrl_id = codec_data->ctl[dai_id]; \
37 codec_info.stream_id = codec_data->stream[dai_id]; \
38 msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, \
39 &codec_info)
40
41enum {
42 DP_STREAM0 = 0,
43 DP_STREAM1,
44 DP_STREAM_MAX,
45};
46
47enum {
48 DP_DAI1 = 0,
49 DP_DAI2,
50 HDMI_DAI,
51 DP_DAI_MAX,
52};
53
Asish Bhattacharya366f7502017-07-25 15:15:56 +053054static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"};
55static const char *const ext_disp_audio_ack_text[] = {"Disconnect", "Connect",
56 "Ack_Enable"};
57
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070058SOC_EXT_DISP_AUDIO_TYPE(0);
59SOC_EXT_DISP_AUDIO_ACK_STATE(0);
60SOC_EXT_DISP_AUDIO_TYPE(1);
61SOC_EXT_DISP_AUDIO_ACK_STATE(1);
Asish Bhattacharya366f7502017-07-25 15:15:56 +053062
63struct msm_ext_disp_audio_codec_rx_data {
64 struct platform_device *ext_disp_core_pdev;
65 struct msm_ext_disp_audio_codec_ops ext_disp_ops;
66 int cable_status;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070067 struct mutex dp_ops_lock;
68 int stream[DP_DAI_MAX];
69 int ctl[DP_DAI_MAX];
Asish Bhattacharya366f7502017-07-25 15:15:56 +053070};
71
72static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol,
73 struct snd_ctl_elem_info *uinfo)
74{
75 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
76 struct msm_ext_disp_audio_codec_rx_data *codec_data;
77 struct msm_ext_disp_audio_edid_blk edid_blk;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070078 int rc = 0;
79 struct msm_ext_disp_codec_id codec_info;
80 int dai_id = kcontrol->private_value;
Asish Bhattacharya366f7502017-07-25 15:15:56 +053081
82 codec_data = snd_soc_codec_get_drvdata(codec);
83
84 if (!codec_data) {
85 dev_err(codec->dev, "%s: codec_data is NULL\n", __func__);
86 return -EINVAL;
87 }
88
89 if (!codec_data->ext_disp_ops.get_audio_edid_blk) {
90 dev_dbg(codec->dev, "%s: get_audio_edid_blk() is NULL\n",
91 __func__);
92 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
93 uinfo->count = 0;
94 return 0;
95 }
96
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070097 dev_dbg(codec->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
98 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
99
100 mutex_lock(&codec_data->dp_ops_lock);
101 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530102 rc = codec_data->ext_disp_ops.get_audio_edid_blk(
103 codec_data->ext_disp_core_pdev, &edid_blk);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700104 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530105 if (rc >= 0) {
106 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
107 uinfo->count = edid_blk.audio_data_blk_size +
108 edid_blk.spk_alloc_data_blk_size;
109 }
110
111 dev_dbg(codec->dev, "%s: count: %d\n", __func__, uinfo->count);
112
113 return rc;
114}
115
116static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
117 struct snd_ctl_elem_value *ucontrol) {
118 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
119 struct msm_ext_disp_audio_codec_rx_data *codec_data;
120 struct msm_ext_disp_audio_edid_blk edid_blk;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700121 struct msm_ext_disp_codec_id codec_info;
122 int rc = 0;
123 int dai_id = kcontrol->private_value;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530124
125 codec_data = snd_soc_codec_get_drvdata(codec);
126 if (!codec_data || !codec_data->ext_disp_ops.get_audio_edid_blk) {
127 dev_err(codec->dev, "%s: codec_data or get_audio_edid_blk() is NULL\n",
128 __func__);
129 return -EINVAL;
130 }
131
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700132 dev_dbg(codec->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
133 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
134
135 mutex_lock(&codec_data->dp_ops_lock);
136 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530137 rc = codec_data->ext_disp_ops.get_audio_edid_blk(
138 codec_data->ext_disp_core_pdev, &edid_blk);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700139 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530140 if (rc >= 0) {
141 if (sizeof(ucontrol->value.bytes.data) <
142 (edid_blk.audio_data_blk_size +
143 edid_blk.spk_alloc_data_blk_size)) {
144 dev_err(codec->dev,
145 "%s: Not enough memory to copy EDID data\n",
146 __func__);
147 return -ENOMEM;
148 }
149
150 memcpy(ucontrol->value.bytes.data,
151 edid_blk.audio_data_blk,
152 edid_blk.audio_data_blk_size);
153 memcpy((ucontrol->value.bytes.data +
154 edid_blk.audio_data_blk_size),
155 edid_blk.spk_alloc_data_blk,
156 edid_blk.spk_alloc_data_blk_size);
157
158 dev_dbg(codec->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n",
159 __func__, edid_blk.audio_data_blk_size,
160 edid_blk.spk_alloc_data_blk_size);
161 }
162
163 return rc;
164}
165
166static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
167 struct snd_ctl_elem_value *ucontrol)
168{
169 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
170 struct msm_ext_disp_audio_codec_rx_data *codec_data;
171 enum msm_ext_disp_cable_state cable_state;
172 enum msm_ext_disp_type disp_type;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700173 struct msm_ext_disp_codec_id codec_info;
174 int rc = 0;
175 int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530176
177 codec_data = snd_soc_codec_get_drvdata(codec);
178 if (!codec_data ||
179 !codec_data->ext_disp_ops.get_audio_edid_blk ||
180 !codec_data->ext_disp_ops.get_intf_id) {
181 dev_err(codec->dev, "%s: codec_data, get_audio_edid_blk() or get_intf_id is NULL\n",
182 __func__);
183 return -EINVAL;
184 }
185
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700186 dev_dbg(codec->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
187 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
188
189 mutex_lock(&codec_data->dp_ops_lock);
190 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530191 cable_state = codec_data->ext_disp_ops.cable_status(
192 codec_data->ext_disp_core_pdev, 1);
193 if (cable_state < 0) {
194 dev_err(codec->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n",
195 __func__, cable_state);
196 rc = cable_state;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700197 goto cable_err;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530198 }
199
200 codec_data->cable_status = cable_state;
201 if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) {
202 dev_err(codec->dev, "%s: Display cable disconnected\n",
203 __func__);
204 ucontrol->value.integer.value[0] = 0;
205 rc = 0;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700206 goto cable_err;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530207 }
208
209 disp_type = codec_data->ext_disp_ops.get_intf_id(
210 codec_data->ext_disp_core_pdev);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700211 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530212 if (disp_type >= 0) {
213 switch (disp_type) {
214 case EXT_DISPLAY_TYPE_DP:
215 ucontrol->value.integer.value[0] = 2;
216 rc = 0;
217 break;
218 case EXT_DISPLAY_TYPE_HDMI:
219 ucontrol->value.integer.value[0] = 1;
220 rc = 0;
221 break;
222 default:
223 rc = -EINVAL;
224 dev_err(codec->dev, "%s: Invalid disp_type:%d\n",
225 __func__, disp_type);
226 goto done;
227 }
228 dev_dbg(codec->dev, "%s: Display type: %d\n",
229 __func__, disp_type);
230 } else {
231 dev_err(codec->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n",
232 __func__, disp_type);
233 rc = disp_type;
234 }
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700235 return rc;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530236
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700237cable_err:
238 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530239done:
240 return rc;
241}
242
243static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
244 struct snd_ctl_elem_value *ucontrol)
245{
246 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
247 struct msm_ext_disp_audio_codec_rx_data *codec_data;
248 u32 ack_state = 0;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700249 struct msm_ext_disp_codec_id codec_info;
250 int rc = 0;
251 int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530252
253 codec_data = snd_soc_codec_get_drvdata(codec);
254 if (!codec_data ||
255 !codec_data->ext_disp_ops.acknowledge) {
256 dev_err(codec->dev,
257 "%s: codec_data or ops acknowledge() is NULL\n",
258 __func__);
259 rc = -EINVAL;
260 goto done;
261 }
262
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700263 dev_dbg(codec->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
264 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
265
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530266 switch (ucontrol->value.enumerated.item[0]) {
267 case 0:
268 ack_state = AUD_EXT_DISP_ACK_DISCONNECT;
269 break;
270 case 1:
271 ack_state = AUD_EXT_DISP_ACK_CONNECT;
272 break;
273 case 2:
274 ack_state = AUD_EXT_DISP_ACK_ENABLE;
275 break;
276 default:
277 rc = -EINVAL;
278 dev_err(codec->dev,
279 "%s: invalid value %d for mixer ctl\n",
280 __func__, ucontrol->value.enumerated.item[0]);
281 goto done;
282 }
283 dev_dbg(codec->dev, "%s: control %d, ack set value 0x%x\n",
284 __func__, ucontrol->value.enumerated.item[0], ack_state);
285
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700286 mutex_lock(&codec_data->dp_ops_lock);
287 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530288 rc = codec_data->ext_disp_ops.acknowledge(
289 codec_data->ext_disp_core_pdev, ack_state);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700290 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530291 if (rc < 0) {
292 dev_err(codec->dev, "%s: error from acknowledge(), err:%d\n",
293 __func__, rc);
294 }
295
296done:
297 return rc;
298}
299
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700300static int msm_ext_disp_audio_device_set(struct snd_kcontrol *kcontrol,
301 struct snd_ctl_elem_value *ucontrol)
302{
303 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
304 struct msm_ext_disp_audio_codec_rx_data *codec_data;
305 int rc = 0;
306 int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
307
308 codec_data = snd_soc_codec_get_drvdata(codec);
309 if (!codec_data) {
310 dev_err(codec->dev,
311 "%s: codec_data or ops acknowledge() is NULL\n",
312 __func__);
313 rc = -EINVAL;
314 goto done;
315 }
316
317 mutex_lock(&codec_data->dp_ops_lock);
318 codec_data->ctl[dai_id] = ucontrol->value.enumerated.item[0];
319 codec_data->stream[dai_id] = ucontrol->value.enumerated.item[1];
320 mutex_unlock(&codec_data->dp_ops_lock);
321
322done:
323 return rc;
324}
325
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530326static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
327 {
328 .access = SNDRV_CTL_ELEM_ACCESS_READ |
329 SNDRV_CTL_ELEM_ACCESS_VOLATILE,
330 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
331 .name = "HDMI EDID",
332 .info = msm_ext_disp_edid_ctl_info,
333 .get = msm_ext_disp_edid_get,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700334 .private_value = HDMI_DAI,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530335 },
336 {
337 .access = SNDRV_CTL_ELEM_ACCESS_READ |
338 SNDRV_CTL_ELEM_ACCESS_VOLATILE,
339 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
340 .name = "Display Port EDID",
341 .info = msm_ext_disp_edid_ctl_info,
342 .get = msm_ext_disp_edid_get,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700343 .private_value = DP_DAI1,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530344 },
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700345 {
346 .access = SNDRV_CTL_ELEM_ACCESS_READ |
347 SNDRV_CTL_ELEM_ACCESS_VOLATILE,
348 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
349 .name = "Display Port1 EDID",
350 .info = msm_ext_disp_edid_ctl_info,
351 .get = msm_ext_disp_edid_get,
352 .private_value = DP_DAI2,
353 },
354 SOC_ENUM_EXT("External Display Type",
355 ext_disp_audio_type0,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530356 msm_ext_disp_audio_type_get, NULL),
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700357 SOC_ENUM_EXT("External Display1 Type",
358 ext_disp_audio_type1,
359 msm_ext_disp_audio_type_get, NULL),
360 SOC_ENUM_EXT("External Display Audio Ack",
361 ext_disp_audio_ack_state0,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530362 NULL, msm_ext_disp_audio_ack_set),
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700363 SOC_ENUM_EXT("External Display1 Audio Ack",
364 ext_disp_audio_ack_state1,
365 NULL, msm_ext_disp_audio_ack_set),
366
367 SOC_SINGLE_EXT("External Display Audio Device",
368 SND_SOC_NOPM, DP_DAI1, DP_STREAM_MAX, 0,
369 NULL, msm_ext_disp_audio_device_set),
370 SOC_SINGLE_EXT("External Display1 Audio Device",
371 SND_SOC_NOPM, DP_DAI2, DP_STREAM_MAX, 0,
372 NULL, msm_ext_disp_audio_device_set),
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530373};
374
375static int msm_ext_disp_audio_codec_rx_dai_startup(
376 struct snd_pcm_substream *substream,
377 struct snd_soc_dai *dai)
378{
379 int ret = 0;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700380 struct msm_ext_disp_codec_id codec_info;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530381 struct msm_ext_disp_audio_codec_rx_data *codec_data =
382 dev_get_drvdata(dai->codec->dev);
383
384 if (!codec_data || !codec_data->ext_disp_ops.cable_status) {
385 dev_err(dai->dev, "%s() codec_data or cable_status is null\n",
386 __func__);
387 return -EINVAL;
388 }
389
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700390 dev_dbg(dai->codec->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
391 codec_data->ctl[dai->id], codec_data->stream[dai->id]);
392
393 mutex_lock(&codec_data->dp_ops_lock);
394 SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530395 codec_data->cable_status =
396 codec_data->ext_disp_ops.cable_status(
397 codec_data->ext_disp_core_pdev, 1);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700398 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530399 if (codec_data->cable_status < 0) {
400 dev_err(dai->dev,
401 "%s() ext disp core is not ready (ret val = %d)\n",
402 __func__, codec_data->cable_status);
403 ret = codec_data->cable_status;
404 } else if (!codec_data->cable_status) {
405 dev_err(dai->dev,
406 "%s() ext disp cable is not connected (ret val = %d)\n",
407 __func__, codec_data->cable_status);
408 ret = -ENODEV;
409 }
410
411 return ret;
412}
413
414static int msm_ext_disp_audio_codec_rx_dai_hw_params(
415 struct snd_pcm_substream *substream,
416 struct snd_pcm_hw_params *params,
417 struct snd_soc_dai *dai)
418{
419 u32 channel_allocation = 0;
420 u32 level_shift = 0; /* 0dB */
421 bool down_mix = 0;
422 u32 num_channels = params_channels(params);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700423 struct msm_ext_disp_codec_id codec_info;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530424 int rc = 0;
425 struct msm_ext_disp_audio_setup_params audio_setup_params = {0};
426
427 struct msm_ext_disp_audio_codec_rx_data *codec_data =
428 dev_get_drvdata(dai->codec->dev);
429
430 if (!codec_data || !codec_data->ext_disp_ops.audio_info_setup) {
431 dev_err(dai->dev, "%s: codec_data or audio_info_setup is null\n",
432 __func__);
433 return -EINVAL;
434 }
435
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700436 dev_dbg(dai->codec->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
437 codec_data->ctl[dai->id], codec_data->stream[dai->id]);
438
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530439 if (codec_data->cable_status < 0) {
440 dev_err_ratelimited(dai->dev,
441 "%s() ext disp core is not ready (ret val = %d)\n",
442 __func__, codec_data->cable_status);
443 return codec_data->cable_status;
444 } else if (!codec_data->cable_status) {
445 dev_err_ratelimited(dai->dev,
446 "%s() ext disp cable is not connected (ret val = %d)\n",
447 __func__, codec_data->cable_status);
448 return -ENODEV;
449 }
450
451 /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
452 switch (num_channels) {
453 case 2:
454 channel_allocation = 0;
455 break;
456 case 3:
457 channel_allocation = 0x02;/*default to FL/FR/FC*/
458 audio_setup_params.sample_present = 0x3;
459 break;
460 case 4:
461 channel_allocation = 0x06;/*default to FL/FR/FC/RC*/
462 audio_setup_params.sample_present = 0x7;
463 break;
464 case 5:
465 channel_allocation = 0x0A;/*default to FL/FR/FC/RR/RL*/
466 audio_setup_params.sample_present = 0x7;
467 break;
468 case 6:
469 channel_allocation = 0x0B;
470 audio_setup_params.sample_present = 0x7;
471 break;
472 case 7:
473 channel_allocation = 0x12;/*default to FL/FR/FC/RL/RR/RRC/RLC*/
474 audio_setup_params.sample_present = 0xf;
475 break;
476 case 8:
477 channel_allocation = 0x13;
478 audio_setup_params.sample_present = 0xf;
479 break;
480 default:
481 dev_err(dai->dev, "invalid Channels = %u\n", num_channels);
482 return -EINVAL;
483 }
484
485 dev_dbg(dai->dev,
486 "%s() num_ch %u samplerate %u channel_allocation = %u\n",
487 __func__, num_channels, params_rate(params),
488 channel_allocation);
489
490 audio_setup_params.sample_rate_hz = params_rate(params);
491 audio_setup_params.num_of_channels = num_channels;
492 audio_setup_params.channel_allocation = channel_allocation;
493 audio_setup_params.level_shift = level_shift;
494 audio_setup_params.down_mix = down_mix;
495
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700496 mutex_lock(&codec_data->dp_ops_lock);
497 SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530498 rc = codec_data->ext_disp_ops.audio_info_setup(
499 codec_data->ext_disp_core_pdev, &audio_setup_params);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700500 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530501 if (rc < 0) {
502 dev_err_ratelimited(dai->dev,
503 "%s() ext disp core is not ready, rc: %d\n",
504 __func__, rc);
505 }
506
507 return rc;
508}
509
510static void msm_ext_disp_audio_codec_rx_dai_shutdown(
511 struct snd_pcm_substream *substream,
512 struct snd_soc_dai *dai)
513{
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700514 int rc = 0;
515 struct msm_ext_disp_codec_id codec_info;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530516
517 struct msm_ext_disp_audio_codec_rx_data *codec_data =
518 dev_get_drvdata(dai->codec->dev);
519
520 if (!codec_data || !codec_data->ext_disp_ops.teardown_done ||
521 !codec_data->ext_disp_ops.cable_status) {
522 dev_err(dai->dev, "%s: codec data or teardown_done or cable_status is null\n",
523 __func__);
524 return;
525 }
526
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700527 dev_dbg(dai->codec->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
528 codec_data->ctl[dai->id], codec_data->stream[dai->id]);
529
530 mutex_lock(&codec_data->dp_ops_lock);
531 SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530532 rc = codec_data->ext_disp_ops.cable_status(
533 codec_data->ext_disp_core_pdev, 0);
534 if (rc < 0) {
535 dev_err(dai->dev,
536 "%s: ext disp core had problems releasing audio flag\n",
537 __func__);
538 }
539
540 codec_data->ext_disp_ops.teardown_done(
541 codec_data->ext_disp_core_pdev);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700542 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530543}
544
545static int msm_ext_disp_audio_codec_rx_probe(struct snd_soc_codec *codec)
546{
547 struct msm_ext_disp_audio_codec_rx_data *codec_data;
548 struct device_node *of_node_parent = NULL;
549
550 codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data),
551 GFP_KERNEL);
552
553 if (!codec_data) {
554 dev_err(codec->dev, "%s(): fail to allocate dai data\n",
555 __func__);
556 return -ENOMEM;
557 }
558
559 of_node_parent = of_get_parent(codec->dev->of_node);
560 if (!of_node_parent) {
561 dev_err(codec->dev, "%s(): Parent device tree node not found\n",
562 __func__);
563 kfree(codec_data);
564 return -ENODEV;
565 }
566
567 codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent);
568 if (!codec_data->ext_disp_core_pdev) {
569 dev_err(codec->dev, "%s(): can't get parent pdev\n", __func__);
570 kfree(codec_data);
571 return -ENODEV;
572 }
573
574 if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev,
575 &codec_data->ext_disp_ops)) {
576 dev_err(codec->dev, "%s(): can't register with ext disp core",
577 __func__);
578 kfree(codec_data);
579 return -ENODEV;
580 }
581
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700582 mutex_init(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530583 dev_set_drvdata(codec->dev, codec_data);
584
585 dev_dbg(codec->dev, "%s(): registered %s with ext disp core\n",
586 __func__, codec->component.name);
587
588 return 0;
589}
590
591static int msm_ext_disp_audio_codec_rx_remove(struct snd_soc_codec *codec)
592{
593 struct msm_ext_disp_audio_codec_rx_data *codec_data;
594
595 codec_data = dev_get_drvdata(codec->dev);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700596 mutex_destroy(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530597 kfree(codec_data);
598
599 return 0;
600}
601
602static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = {
603 .startup = msm_ext_disp_audio_codec_rx_dai_startup,
604 .hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params,
605 .shutdown = msm_ext_disp_audio_codec_rx_dai_shutdown
606};
607
608static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = {
609 {
610 .name = "msm_hdmi_audio_codec_rx_dai",
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700611 .id = HDMI_DAI,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530612 .playback = {
613 .stream_name = "HDMI Playback",
614 .channels_min = 1,
615 .channels_max = 8,
616 .rate_min = 48000,
617 .rate_max = 48000,
618 .rates = MSM_EXT_DISP_PCM_RATES,
619 .formats = SNDRV_PCM_FMTBIT_S16_LE,
620 },
621 .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
622 },
623 {
624 .name = "msm_dp_audio_codec_rx_dai",
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700625 .id = DP_DAI1,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530626 .playback = {
627 .stream_name = "Display Port Playback",
628 .channels_min = 1,
629 .channels_max = 8,
630 .rate_min = 48000,
631 .rate_max = 192000,
632 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700633 SNDRV_PCM_RATE_192000,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530634 .formats = SNDRV_PCM_FMTBIT_S16_LE |
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700635 SNDRV_PCM_FMTBIT_S24_LE |
636 SNDRV_PCM_FMTBIT_S24_3LE,
637 },
638 .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
639 },
640 {
641 .name = "msm_dp_audio_codec_rx1_dai",
642 .id = DP_DAI2,
643 .playback = {
644 .stream_name = "Display Port1 Playback",
645 .channels_min = 1,
646 .channels_max = 8,
647 .rate_min = 48000,
648 .rate_max = 192000,
649 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
650 SNDRV_PCM_RATE_192000,
651 .formats = SNDRV_PCM_FMTBIT_S16_LE |
652 SNDRV_PCM_FMTBIT_S24_LE |
653 SNDRV_PCM_FMTBIT_S24_3LE,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530654 },
655 .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
656 },
657};
658
659static struct snd_soc_codec_driver msm_ext_disp_audio_codec_rx_soc_driver = {
660 .probe = msm_ext_disp_audio_codec_rx_probe,
661 .remove = msm_ext_disp_audio_codec_rx_remove,
662 .component_driver = {
663 .controls = msm_ext_disp_codec_rx_controls,
664 .num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls),
665 },
666};
667
668static int msm_ext_disp_audio_codec_rx_plat_probe(
669 struct platform_device *pdev)
670{
671 dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__,
672 dev_name(&pdev->dev));
673
674 return snd_soc_register_codec(&pdev->dev,
675 &msm_ext_disp_audio_codec_rx_soc_driver,
676 msm_ext_disp_audio_codec_rx_dais,
677 ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais));
678}
679
680static int msm_ext_disp_audio_codec_rx_plat_remove(
681 struct platform_device *pdev)
682{
683 snd_soc_unregister_codec(&pdev->dev);
684 return 0;
685}
686static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = {
687 { .compatible = "qcom,msm-ext-disp-audio-codec-rx", },
688 {}
689};
690MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match);
691
692static struct platform_driver msm_ext_disp_audio_codec_rx_driver = {
693 .driver = {
694 .name = "msm-ext-disp-audio-codec-rx",
695 .owner = THIS_MODULE,
696 .of_match_table = msm_ext_disp_audio_codec_rx_dt_match,
697 },
698 .probe = msm_ext_disp_audio_codec_rx_plat_probe,
699 .remove = msm_ext_disp_audio_codec_rx_plat_remove,
700};
701
702static int __init msm_ext_disp_audio_codec_rx_init(void)
703{
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700704 int rc = 0;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530705
706 rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver);
707 if (rc) {
708 pr_err("%s: failed to register ext disp codec driver err:%d\n",
709 __func__, rc);
710 }
711
712 return rc;
713}
714module_init(msm_ext_disp_audio_codec_rx_init);
715
716static void __exit msm_ext_disp_audio_codec_rx_exit(void)
717{
718 platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver);
719}
720module_exit(msm_ext_disp_audio_codec_rx_exit);
721
722MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver");
723MODULE_LICENSE("GPL v2");