blob: 5144b923b03ee9acf4fa95548764ee23367a6be2 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Xiaojun Sang53cd13a2018-06-29 15:14:37 +08002/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya366f7502017-07-25 15:15:56 +05303 */
4#include <linux/platform_device.h>
5#include <linux/slab.h>
6#include <linux/module.h>
7#include <linux/of_device.h>
8#include <linux/err.h>
9#include <sound/core.h>
10#include <sound/pcm.h>
11#include <sound/soc.h>
12#include <linux/msm_ext_display.h>
13
Meng Wang15c825d2018-09-06 10:49:18 +080014#define DRV_NAME "HDMI_codec"
15
Asish Bhattacharya366f7502017-07-25 15:15:56 +053016#define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000
17#define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT)
18#define AUD_EXT_DISP_ACK_CONNECT (AUDIO_ACK_CONNECT)
19#define AUD_EXT_DISP_ACK_ENABLE (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE)
20
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070021#define SOC_EXT_DISP_AUDIO_TYPE(index) \
22 static SOC_ENUM_SINGLE_DECL(ext_disp_audio_type##index, SND_SOC_NOPM, \
23 index, ext_disp_audio_type_text)
24#define SOC_EXT_DISP_AUDIO_ACK_STATE(index) \
25 static SOC_ENUM_SINGLE_DECL(ext_disp_audio_ack_state##index, \
26 SND_SOC_NOPM, index, ext_disp_audio_ack_text)
27
28#define SWITCH_DP_CODEC(codec_info, codec_data, dai_id) \
29 codec_info.type = EXT_DISPLAY_TYPE_DP; \
30 codec_info.ctrl_id = codec_data->ctl[dai_id]; \
31 codec_info.stream_id = codec_data->stream[dai_id]; \
32 msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, \
33 &codec_info)
34
35enum {
Karthikeyan Mani311bd672019-06-06 13:40:55 -070036 DP_CONTROLLER0 = 0,
37 DP_CONTROLLER_MAX,
38};
39
40enum {
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070041 DP_STREAM0 = 0,
42 DP_STREAM1,
43 DP_STREAM_MAX,
44};
45
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -070046/*
47 * Dai id cannot be zero, if component has more than one dai and dai id
48 * is used to differentiate between them
49 */
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070050enum {
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -070051 DP_DAI1 = 1,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070052 DP_DAI2,
53 HDMI_DAI,
54 DP_DAI_MAX,
55};
56
Asish Bhattacharya366f7502017-07-25 15:15:56 +053057static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"};
58static const char *const ext_disp_audio_ack_text[] = {"Disconnect", "Connect",
59 "Ack_Enable"};
60
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070061SOC_EXT_DISP_AUDIO_TYPE(1);
62SOC_EXT_DISP_AUDIO_ACK_STATE(1);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -070063SOC_EXT_DISP_AUDIO_TYPE(2);
64SOC_EXT_DISP_AUDIO_ACK_STATE(2);
Asish Bhattacharya366f7502017-07-25 15:15:56 +053065
66struct msm_ext_disp_audio_codec_rx_data {
67 struct platform_device *ext_disp_core_pdev;
68 struct msm_ext_disp_audio_codec_ops ext_disp_ops;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070069 struct mutex dp_ops_lock;
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -070070 int cable_status[DP_DAI_MAX];
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070071 int stream[DP_DAI_MAX];
72 int ctl[DP_DAI_MAX];
Asish Bhattacharya366f7502017-07-25 15:15:56 +053073};
74
75static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol,
76 struct snd_ctl_elem_info *uinfo)
77{
Meng Wang15c825d2018-09-06 10:49:18 +080078 struct snd_soc_component *component =
79 snd_soc_kcontrol_component(kcontrol);
Asish Bhattacharya366f7502017-07-25 15:15:56 +053080 struct msm_ext_disp_audio_codec_rx_data *codec_data;
81 struct msm_ext_disp_audio_edid_blk edid_blk;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070082 int rc = 0;
83 struct msm_ext_disp_codec_id codec_info;
84 int dai_id = kcontrol->private_value;
Asish Bhattacharya366f7502017-07-25 15:15:56 +053085
Meng Wang15c825d2018-09-06 10:49:18 +080086 codec_data = snd_soc_component_get_drvdata(component);
Asish Bhattacharya366f7502017-07-25 15:15:56 +053087 if (!codec_data) {
Meng Wang15c825d2018-09-06 10:49:18 +080088 dev_err(component->dev, "%s: codec_data is NULL\n", __func__);
Asish Bhattacharya366f7502017-07-25 15:15:56 +053089 return -EINVAL;
90 }
91
Meng Wang15c825d2018-09-06 10:49:18 +080092 dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -070093 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
94
95 mutex_lock(&codec_data->dp_ops_lock);
96 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -070097 if (!codec_data->ext_disp_ops.get_audio_edid_blk) {
98 dev_dbg(component->dev, "%s: get_audio_edid_blk() is NULL\n",
99 __func__);
100 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
101 uinfo->count = 0;
102 mutex_unlock(&codec_data->dp_ops_lock);
Meng Wangb5cf4582019-09-04 09:22:07 +0800103 return 0;
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700104 }
105
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530106 rc = codec_data->ext_disp_ops.get_audio_edid_blk(
107 codec_data->ext_disp_core_pdev, &edid_blk);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700108 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530109 if (rc >= 0) {
110 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
111 uinfo->count = edid_blk.audio_data_blk_size +
112 edid_blk.spk_alloc_data_blk_size;
113 }
114
Meng Wang15c825d2018-09-06 10:49:18 +0800115 dev_dbg(component->dev, "%s: count: %d\n", __func__, uinfo->count);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530116
117 return rc;
118}
119
120static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
121 struct snd_ctl_elem_value *ucontrol) {
Meng Wang15c825d2018-09-06 10:49:18 +0800122 struct snd_soc_component *component =
123 snd_soc_kcontrol_component(kcontrol);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530124 struct msm_ext_disp_audio_codec_rx_data *codec_data;
125 struct msm_ext_disp_audio_edid_blk edid_blk;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700126 struct msm_ext_disp_codec_id codec_info;
127 int rc = 0;
128 int dai_id = kcontrol->private_value;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530129
Meng Wang15c825d2018-09-06 10:49:18 +0800130 codec_data = snd_soc_component_get_drvdata(component);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700131 if (!codec_data) {
132 dev_err(component->dev, "%s: codec_data is NULL\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530133 __func__);
134 return -EINVAL;
135 }
136
Meng Wang15c825d2018-09-06 10:49:18 +0800137 dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700138 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
139
140 mutex_lock(&codec_data->dp_ops_lock);
141 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700142 if (!codec_data->ext_disp_ops.get_audio_edid_blk) {
143 dev_err(component->dev, "%s: codec_data or get_audio_edid_blk() is NULL\n",
144 __func__);
145 mutex_unlock(&codec_data->dp_ops_lock);
146 return -EINVAL;
147 }
148
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530149 rc = codec_data->ext_disp_ops.get_audio_edid_blk(
150 codec_data->ext_disp_core_pdev, &edid_blk);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700151 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530152 if (rc >= 0) {
153 if (sizeof(ucontrol->value.bytes.data) <
154 (edid_blk.audio_data_blk_size +
155 edid_blk.spk_alloc_data_blk_size)) {
Meng Wang15c825d2018-09-06 10:49:18 +0800156 dev_err(component->dev,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530157 "%s: Not enough memory to copy EDID data\n",
158 __func__);
159 return -ENOMEM;
160 }
161
162 memcpy(ucontrol->value.bytes.data,
163 edid_blk.audio_data_blk,
164 edid_blk.audio_data_blk_size);
165 memcpy((ucontrol->value.bytes.data +
166 edid_blk.audio_data_blk_size),
167 edid_blk.spk_alloc_data_blk,
168 edid_blk.spk_alloc_data_blk_size);
169
Meng Wang15c825d2018-09-06 10:49:18 +0800170 dev_dbg(component->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530171 __func__, edid_blk.audio_data_blk_size,
172 edid_blk.spk_alloc_data_blk_size);
173 }
174
175 return rc;
176}
177
178static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
179 struct snd_ctl_elem_value *ucontrol)
180{
Meng Wang15c825d2018-09-06 10:49:18 +0800181 struct snd_soc_component *component =
182 snd_soc_kcontrol_component(kcontrol);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530183 struct msm_ext_disp_audio_codec_rx_data *codec_data;
184 enum msm_ext_disp_cable_state cable_state;
185 enum msm_ext_disp_type disp_type;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700186 struct msm_ext_disp_codec_id codec_info;
187 int rc = 0;
188 int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530189
Meng Wang15c825d2018-09-06 10:49:18 +0800190 codec_data = snd_soc_component_get_drvdata(component);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700191 if (!codec_data) {
192 dev_err(component->dev, "%s: codec_data is NULL\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530193 __func__);
194 return -EINVAL;
195 }
196
Meng Wang15c825d2018-09-06 10:49:18 +0800197 dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700198 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
199
200 mutex_lock(&codec_data->dp_ops_lock);
201 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700202
203 if (!codec_data->ext_disp_ops.get_audio_edid_blk ||
204 !codec_data->ext_disp_ops.get_intf_id) {
205 dev_err(component->dev, "%s: get_audio_edid_blk() or get_intf_id is NULL\n",
206 __func__);
207 rc = -EINVAL;
208 goto cable_err;
209 }
210
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530211 cable_state = codec_data->ext_disp_ops.cable_status(
212 codec_data->ext_disp_core_pdev, 1);
213 if (cable_state < 0) {
Meng Wang15c825d2018-09-06 10:49:18 +0800214 dev_err(component->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530215 __func__, cable_state);
216 rc = cable_state;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700217 goto cable_err;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530218 }
219
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700220 codec_data->cable_status[dai_id] = cable_state;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530221 if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) {
Meng Wang15c825d2018-09-06 10:49:18 +0800222 dev_err(component->dev, "%s: Display cable disconnected\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530223 __func__);
224 ucontrol->value.integer.value[0] = 0;
225 rc = 0;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700226 goto cable_err;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530227 }
228
229 disp_type = codec_data->ext_disp_ops.get_intf_id(
230 codec_data->ext_disp_core_pdev);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700231 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530232 if (disp_type >= 0) {
233 switch (disp_type) {
234 case EXT_DISPLAY_TYPE_DP:
235 ucontrol->value.integer.value[0] = 2;
236 rc = 0;
237 break;
238 case EXT_DISPLAY_TYPE_HDMI:
239 ucontrol->value.integer.value[0] = 1;
240 rc = 0;
241 break;
242 default:
243 rc = -EINVAL;
Meng Wang15c825d2018-09-06 10:49:18 +0800244 dev_err(component->dev, "%s: Invalid disp_type:%d\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530245 __func__, disp_type);
246 goto done;
247 }
Meng Wang15c825d2018-09-06 10:49:18 +0800248 dev_dbg(component->dev, "%s: Display type: %d\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530249 __func__, disp_type);
250 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800251 dev_err(component->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530252 __func__, disp_type);
253 rc = disp_type;
254 }
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700255 return rc;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530256
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700257cable_err:
258 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530259done:
260 return rc;
261}
262
263static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
264 struct snd_ctl_elem_value *ucontrol)
265{
Meng Wang15c825d2018-09-06 10:49:18 +0800266 struct snd_soc_component *component =
267 snd_soc_kcontrol_component(kcontrol);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530268 struct msm_ext_disp_audio_codec_rx_data *codec_data;
269 u32 ack_state = 0;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700270 struct msm_ext_disp_codec_id codec_info;
271 int rc = 0;
272 int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530273
Meng Wang15c825d2018-09-06 10:49:18 +0800274 codec_data = snd_soc_component_get_drvdata(component);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700275 if (!codec_data) {
Meng Wang15c825d2018-09-06 10:49:18 +0800276 dev_err(component->dev,
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700277 "%s: codec_data is NULL\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530278 __func__);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700279 return -EINVAL;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530280 }
281
Meng Wang15c825d2018-09-06 10:49:18 +0800282 dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700283 codec_data->ctl[dai_id], codec_data->stream[dai_id]);
284
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700285 mutex_lock(&codec_data->dp_ops_lock);
286 SWITCH_DP_CODEC(codec_info, codec_data, dai_id);
287
288 if (!codec_data->ext_disp_ops.acknowledge) {
289 dev_err(component->dev,
290 "%s: codec_data ops acknowledge() is NULL\n",
291 __func__);
292 rc = -EINVAL;
293 goto err;
294 }
295
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530296 switch (ucontrol->value.enumerated.item[0]) {
297 case 0:
298 ack_state = AUD_EXT_DISP_ACK_DISCONNECT;
299 break;
300 case 1:
301 ack_state = AUD_EXT_DISP_ACK_CONNECT;
302 break;
303 case 2:
304 ack_state = AUD_EXT_DISP_ACK_ENABLE;
305 break;
306 default:
307 rc = -EINVAL;
Meng Wang15c825d2018-09-06 10:49:18 +0800308 dev_err(component->dev,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530309 "%s: invalid value %d for mixer ctl\n",
310 __func__, ucontrol->value.enumerated.item[0]);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700311 goto err;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530312 }
Meng Wang15c825d2018-09-06 10:49:18 +0800313 dev_dbg(component->dev, "%s: control %d, ack set value 0x%x\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530314 __func__, ucontrol->value.enumerated.item[0], ack_state);
315
316 rc = codec_data->ext_disp_ops.acknowledge(
317 codec_data->ext_disp_core_pdev, ack_state);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700318 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530319 if (rc < 0) {
Meng Wang15c825d2018-09-06 10:49:18 +0800320 dev_err(component->dev, "%s: error from acknowledge(), err:%d\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530321 __func__, rc);
322 }
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700323 return rc;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530324
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700325err:
326 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530327 return rc;
328}
329
Karthikeyan Mani311bd672019-06-06 13:40:55 -0700330static int msm_ext_disp_audio_device_get(struct snd_kcontrol *kcontrol,
331 struct snd_ctl_elem_value *ucontrol)
332{
333 struct snd_soc_component *component =
334 snd_soc_kcontrol_component(kcontrol);
335 struct msm_ext_disp_audio_codec_rx_data *codec_data;
336 int rc = 0;
337 int dai_id = ((struct soc_multi_mixer_control *)
338 kcontrol->private_value)->shift;
339
340 if (dai_id < 0 || dai_id > DP_DAI2) {
341 dev_err(component->dev,
342 "%s: invalid dai id: %d\n", __func__, dai_id);
343 rc = -EINVAL;
344 goto done;
345 }
346
347 codec_data = snd_soc_component_get_drvdata(component);
348 if (!codec_data) {
349 dev_err(component->dev,
350 "%s: codec_data or ops acknowledge() is NULL\n",
351 __func__);
352 rc = -EINVAL;
353 goto done;
354 }
355 ucontrol->value.integer.value[0] = codec_data->ctl[dai_id];
356 ucontrol->value.integer.value[1] = codec_data->stream[dai_id];
357
358done:
359 return rc;
360}
361
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700362static int msm_ext_disp_audio_device_set(struct snd_kcontrol *kcontrol,
363 struct snd_ctl_elem_value *ucontrol)
364{
Meng Wang15c825d2018-09-06 10:49:18 +0800365 struct snd_soc_component *component =
366 snd_soc_kcontrol_component(kcontrol);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700367 struct msm_ext_disp_audio_codec_rx_data *codec_data;
368 int rc = 0;
Karthikeyan Mani311bd672019-06-06 13:40:55 -0700369 int dai_id = ((struct soc_multi_mixer_control *)
370 kcontrol->private_value)->shift;
371
372 if (dai_id < 0 || dai_id > DP_DAI2) {
373 dev_err(component->dev,
374 "%s: invalid dai id: %d\n", __func__, dai_id);
375 rc = -EINVAL;
376 goto done;
377 }
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700378
Meng Wang15c825d2018-09-06 10:49:18 +0800379 codec_data = snd_soc_component_get_drvdata(component);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700380 if (!codec_data) {
Meng Wang15c825d2018-09-06 10:49:18 +0800381 dev_err(component->dev,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700382 "%s: codec_data or ops acknowledge() is NULL\n",
383 __func__);
384 rc = -EINVAL;
385 goto done;
386 }
387
Karthikeyan Mani311bd672019-06-06 13:40:55 -0700388 if ((ucontrol->value.integer.value[0] > (DP_CONTROLLER_MAX - 1)) ||
389 (ucontrol->value.integer.value[1] > (DP_STREAM_MAX - 1)) ||
390 (ucontrol->value.integer.value[0] < 0) ||
391 (ucontrol->value.integer.value[1] < 0)) {
392 dev_err(component->dev,
393 "%s: DP audio control index invalid\n",
394 __func__);
395 rc = -EINVAL;
396 goto done;
397 }
398
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700399 mutex_lock(&codec_data->dp_ops_lock);
Karthikeyan Mani311bd672019-06-06 13:40:55 -0700400 codec_data->ctl[dai_id] = ucontrol->value.integer.value[0];
401 codec_data->stream[dai_id] = ucontrol->value.integer.value[1];
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700402 mutex_unlock(&codec_data->dp_ops_lock);
403
404done:
405 return rc;
406}
407
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530408static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
409 {
410 .access = SNDRV_CTL_ELEM_ACCESS_READ |
411 SNDRV_CTL_ELEM_ACCESS_VOLATILE,
412 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
413 .name = "HDMI EDID",
414 .info = msm_ext_disp_edid_ctl_info,
415 .get = msm_ext_disp_edid_get,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700416 .private_value = HDMI_DAI,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530417 },
418 {
419 .access = SNDRV_CTL_ELEM_ACCESS_READ |
420 SNDRV_CTL_ELEM_ACCESS_VOLATILE,
421 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
422 .name = "Display Port EDID",
423 .info = msm_ext_disp_edid_ctl_info,
424 .get = msm_ext_disp_edid_get,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700425 .private_value = DP_DAI1,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530426 },
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700427 {
428 .access = SNDRV_CTL_ELEM_ACCESS_READ |
429 SNDRV_CTL_ELEM_ACCESS_VOLATILE,
430 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
431 .name = "Display Port1 EDID",
432 .info = msm_ext_disp_edid_ctl_info,
433 .get = msm_ext_disp_edid_get,
434 .private_value = DP_DAI2,
435 },
436 SOC_ENUM_EXT("External Display Type",
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700437 ext_disp_audio_type1,
438 msm_ext_disp_audio_type_get, NULL),
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700439 SOC_ENUM_EXT("External Display1 Type",
440 ext_disp_audio_type2,
441 msm_ext_disp_audio_type_get, NULL),
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700442 SOC_ENUM_EXT("External Display Audio Ack",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700443 ext_disp_audio_ack_state1,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530444 NULL, msm_ext_disp_audio_ack_set),
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700445 SOC_ENUM_EXT("External Display1 Audio Ack",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700446 ext_disp_audio_ack_state2,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700447 NULL, msm_ext_disp_audio_ack_set),
448
Karthikeyan Mani311bd672019-06-06 13:40:55 -0700449 SOC_SINGLE_MULTI_EXT("External Display Audio Device",
450 SND_SOC_NOPM, DP_DAI1, DP_STREAM_MAX - 1, 0, 2,
451 msm_ext_disp_audio_device_get,
452 msm_ext_disp_audio_device_set),
453 SOC_SINGLE_MULTI_EXT("External Display1 Audio Device",
454 SND_SOC_NOPM, DP_DAI2, DP_STREAM_MAX - 1, 0, 2,
455 msm_ext_disp_audio_device_get,
456 msm_ext_disp_audio_device_set),
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530457};
458
459static int msm_ext_disp_audio_codec_rx_dai_startup(
460 struct snd_pcm_substream *substream,
461 struct snd_soc_dai *dai)
462{
463 int ret = 0;
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700464 struct msm_ext_disp_codec_id codec_info;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530465 struct msm_ext_disp_audio_codec_rx_data *codec_data =
Meng Wang15c825d2018-09-06 10:49:18 +0800466 dev_get_drvdata(dai->component->dev);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530467
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700468 if (!codec_data) {
469 dev_err(dai->dev, "%s() codec_data is null\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530470 __func__);
471 return -EINVAL;
472 }
473
Meng Wang15c825d2018-09-06 10:49:18 +0800474 dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n",
475 __func__,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700476 codec_data->ctl[dai->id], codec_data->stream[dai->id]);
477
478 mutex_lock(&codec_data->dp_ops_lock);
479 SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700480
481 if (!codec_data->ext_disp_ops.cable_status) {
482 dev_err(dai->dev, "%s() cable_status is null\n",
483 __func__);
484 mutex_unlock(&codec_data->dp_ops_lock);
485 return -EINVAL;
486 }
487
488 codec_data->cable_status[dai->id] =
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530489 codec_data->ext_disp_ops.cable_status(
490 codec_data->ext_disp_core_pdev, 1);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700491 mutex_unlock(&codec_data->dp_ops_lock);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700492 if (codec_data->cable_status[dai->id] < 0) {
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530493 dev_err(dai->dev,
494 "%s() ext disp core is not ready (ret val = %d)\n",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700495 __func__, codec_data->cable_status[dai->id]);
496 ret = codec_data->cable_status[dai->id];
497 } else if (!codec_data->cable_status[dai->id]) {
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530498 dev_err(dai->dev,
499 "%s() ext disp cable is not connected (ret val = %d)\n",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700500 __func__, codec_data->cable_status[dai->id]);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530501 ret = -ENODEV;
502 }
503
504 return ret;
505}
506
507static int msm_ext_disp_audio_codec_rx_dai_hw_params(
508 struct snd_pcm_substream *substream,
509 struct snd_pcm_hw_params *params,
510 struct snd_soc_dai *dai)
511{
512 u32 channel_allocation = 0;
513 u32 level_shift = 0; /* 0dB */
514 bool down_mix = 0;
515 u32 num_channels = params_channels(params);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700516 struct msm_ext_disp_codec_id codec_info;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530517 int rc = 0;
518 struct msm_ext_disp_audio_setup_params audio_setup_params = {0};
519
520 struct msm_ext_disp_audio_codec_rx_data *codec_data =
Meng Wang15c825d2018-09-06 10:49:18 +0800521 dev_get_drvdata(dai->component->dev);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530522
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700523 if (!codec_data) {
524 dev_err(dai->dev, "%s() codec_data is null\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530525 __func__);
526 return -EINVAL;
527 }
528
Meng Wang15c825d2018-09-06 10:49:18 +0800529 dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n",
530 __func__,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700531 codec_data->ctl[dai->id], codec_data->stream[dai->id]);
532
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700533 mutex_lock(&codec_data->dp_ops_lock);
534 SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
535
536 if (!codec_data->ext_disp_ops.audio_info_setup) {
537 dev_err(dai->dev, "%s: audio_info_setup is null\n",
538 __func__);
539 mutex_unlock(&codec_data->dp_ops_lock);
540 return -EINVAL;
541 }
542 mutex_unlock(&codec_data->dp_ops_lock);
543
544 if (codec_data->cable_status[dai->id] < 0) {
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530545 dev_err_ratelimited(dai->dev,
546 "%s() ext disp core is not ready (ret val = %d)\n",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700547 __func__, codec_data->cable_status[dai->id]);
548 return codec_data->cable_status[dai->id];
549 } else if (!codec_data->cable_status[dai->id]) {
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530550 dev_err_ratelimited(dai->dev,
551 "%s() ext disp cable is not connected (ret val = %d)\n",
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700552 __func__, codec_data->cable_status[dai->id]);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530553 return -ENODEV;
554 }
555
556 /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
557 switch (num_channels) {
558 case 2:
559 channel_allocation = 0;
560 break;
561 case 3:
562 channel_allocation = 0x02;/*default to FL/FR/FC*/
563 audio_setup_params.sample_present = 0x3;
564 break;
565 case 4:
566 channel_allocation = 0x06;/*default to FL/FR/FC/RC*/
567 audio_setup_params.sample_present = 0x7;
568 break;
569 case 5:
570 channel_allocation = 0x0A;/*default to FL/FR/FC/RR/RL*/
571 audio_setup_params.sample_present = 0x7;
572 break;
573 case 6:
574 channel_allocation = 0x0B;
575 audio_setup_params.sample_present = 0x7;
576 break;
577 case 7:
578 channel_allocation = 0x12;/*default to FL/FR/FC/RL/RR/RRC/RLC*/
579 audio_setup_params.sample_present = 0xf;
580 break;
581 case 8:
582 channel_allocation = 0x13;
583 audio_setup_params.sample_present = 0xf;
584 break;
585 default:
586 dev_err(dai->dev, "invalid Channels = %u\n", num_channels);
587 return -EINVAL;
588 }
589
590 dev_dbg(dai->dev,
591 "%s() num_ch %u samplerate %u channel_allocation = %u\n",
592 __func__, num_channels, params_rate(params),
593 channel_allocation);
594
595 audio_setup_params.sample_rate_hz = params_rate(params);
596 audio_setup_params.num_of_channels = num_channels;
597 audio_setup_params.channel_allocation = channel_allocation;
598 audio_setup_params.level_shift = level_shift;
599 audio_setup_params.down_mix = down_mix;
600
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700601 mutex_lock(&codec_data->dp_ops_lock);
602 SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530603 rc = codec_data->ext_disp_ops.audio_info_setup(
604 codec_data->ext_disp_core_pdev, &audio_setup_params);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700605 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530606 if (rc < 0) {
607 dev_err_ratelimited(dai->dev,
608 "%s() ext disp core is not ready, rc: %d\n",
609 __func__, rc);
610 }
611
612 return rc;
613}
614
615static void msm_ext_disp_audio_codec_rx_dai_shutdown(
616 struct snd_pcm_substream *substream,
617 struct snd_soc_dai *dai)
618{
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700619 int rc = 0;
620 struct msm_ext_disp_codec_id codec_info;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530621
622 struct msm_ext_disp_audio_codec_rx_data *codec_data =
Meng Wang15c825d2018-09-06 10:49:18 +0800623 dev_get_drvdata(dai->component->dev);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530624
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700625 if (!codec_data) {
626 dev_err(dai->dev, "%s() codec_data is null\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530627 __func__);
628 return;
629 }
630
Meng Wang15c825d2018-09-06 10:49:18 +0800631 dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n",
632 __func__,
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700633 codec_data->ctl[dai->id], codec_data->stream[dai->id]);
634
635 mutex_lock(&codec_data->dp_ops_lock);
636 SWITCH_DP_CODEC(codec_info, codec_data, dai->id);
Vignesh Kulothunganf86a3552019-07-11 15:46:25 -0700637
638 if (!codec_data->ext_disp_ops.teardown_done ||
639 !codec_data->ext_disp_ops.cable_status) {
640 dev_err(dai->dev, "%s: teardown_done or cable_status is null\n",
641 __func__);
642 mutex_unlock(&codec_data->dp_ops_lock);
643 return;
644 }
645
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530646 rc = codec_data->ext_disp_ops.cable_status(
647 codec_data->ext_disp_core_pdev, 0);
648 if (rc < 0) {
649 dev_err(dai->dev,
650 "%s: ext disp core had problems releasing audio flag\n",
651 __func__);
652 }
653
654 codec_data->ext_disp_ops.teardown_done(
655 codec_data->ext_disp_core_pdev);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700656 mutex_unlock(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530657}
658
Meng Wang15c825d2018-09-06 10:49:18 +0800659static int msm_ext_disp_audio_codec_rx_probe(
660 struct snd_soc_component *component)
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530661{
662 struct msm_ext_disp_audio_codec_rx_data *codec_data;
663 struct device_node *of_node_parent = NULL;
664
665 codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data),
666 GFP_KERNEL);
667
668 if (!codec_data) {
Meng Wang15c825d2018-09-06 10:49:18 +0800669 dev_err(component->dev, "%s(): fail to allocate dai data\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530670 __func__);
671 return -ENOMEM;
672 }
673
Meng Wang15c825d2018-09-06 10:49:18 +0800674 of_node_parent = of_get_parent(component->dev->of_node);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530675 if (!of_node_parent) {
Meng Wang15c825d2018-09-06 10:49:18 +0800676 dev_err(component->dev, "%s(): Parent device tree node not found\n",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530677 __func__);
678 kfree(codec_data);
679 return -ENODEV;
680 }
681
682 codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent);
683 if (!codec_data->ext_disp_core_pdev) {
Meng Wang15c825d2018-09-06 10:49:18 +0800684 dev_err(component->dev, "%s(): can't get parent pdev\n",
685 __func__);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530686 kfree(codec_data);
687 return -ENODEV;
688 }
689
690 if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev,
691 &codec_data->ext_disp_ops)) {
Meng Wang15c825d2018-09-06 10:49:18 +0800692 dev_err(component->dev, "%s(): can't register with ext disp core",
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530693 __func__);
694 kfree(codec_data);
695 return -ENODEV;
696 }
697
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700698 mutex_init(&codec_data->dp_ops_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800699 dev_set_drvdata(component->dev, codec_data);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530700
Meng Wang15c825d2018-09-06 10:49:18 +0800701 dev_dbg(component->dev, "%s(): registered %s with ext disp core\n",
702 __func__, component->name);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530703
704 return 0;
705}
706
Meng Wang15c825d2018-09-06 10:49:18 +0800707static void msm_ext_disp_audio_codec_rx_remove(
708 struct snd_soc_component *component)
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530709{
710 struct msm_ext_disp_audio_codec_rx_data *codec_data;
711
Meng Wang15c825d2018-09-06 10:49:18 +0800712 codec_data = dev_get_drvdata(component->dev);
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700713 mutex_destroy(&codec_data->dp_ops_lock);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530714 kfree(codec_data);
715
Meng Wang15c825d2018-09-06 10:49:18 +0800716 return;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530717}
718
719static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = {
720 .startup = msm_ext_disp_audio_codec_rx_dai_startup,
721 .hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params,
722 .shutdown = msm_ext_disp_audio_codec_rx_dai_shutdown
723};
724
725static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = {
726 {
727 .name = "msm_hdmi_audio_codec_rx_dai",
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700728 .id = HDMI_DAI,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530729 .playback = {
730 .stream_name = "HDMI Playback",
731 .channels_min = 1,
732 .channels_max = 8,
733 .rate_min = 48000,
734 .rate_max = 48000,
735 .rates = MSM_EXT_DISP_PCM_RATES,
736 .formats = SNDRV_PCM_FMTBIT_S16_LE,
737 },
738 .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
739 },
740 {
741 .name = "msm_dp_audio_codec_rx_dai",
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700742 .id = DP_DAI1,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530743 .playback = {
744 .stream_name = "Display Port Playback",
745 .channels_min = 1,
746 .channels_max = 8,
747 .rate_min = 48000,
748 .rate_max = 192000,
749 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700750 SNDRV_PCM_RATE_192000,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530751 .formats = SNDRV_PCM_FMTBIT_S16_LE |
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700752 SNDRV_PCM_FMTBIT_S24_LE |
753 SNDRV_PCM_FMTBIT_S24_3LE,
754 },
755 .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
756 },
757 {
758 .name = "msm_dp_audio_codec_rx1_dai",
759 .id = DP_DAI2,
760 .playback = {
761 .stream_name = "Display Port1 Playback",
762 .channels_min = 1,
763 .channels_max = 8,
764 .rate_min = 48000,
765 .rate_max = 192000,
766 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
767 SNDRV_PCM_RATE_192000,
768 .formats = SNDRV_PCM_FMTBIT_S16_LE |
769 SNDRV_PCM_FMTBIT_S24_LE |
770 SNDRV_PCM_FMTBIT_S24_3LE,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530771 },
772 .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
773 },
774};
775
Meng Wang15c825d2018-09-06 10:49:18 +0800776static const struct snd_soc_component_driver msm_ext_disp_codec_rx_driver = {
777 .name = DRV_NAME,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530778 .probe = msm_ext_disp_audio_codec_rx_probe,
779 .remove = msm_ext_disp_audio_codec_rx_remove,
Meng Wang15c825d2018-09-06 10:49:18 +0800780 .controls = msm_ext_disp_codec_rx_controls,
781 .num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls),
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530782};
783
784static int msm_ext_disp_audio_codec_rx_plat_probe(
785 struct platform_device *pdev)
786{
787 dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__,
788 dev_name(&pdev->dev));
789
Meng Wang15c825d2018-09-06 10:49:18 +0800790 return snd_soc_register_component(&pdev->dev,
791 &msm_ext_disp_codec_rx_driver,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530792 msm_ext_disp_audio_codec_rx_dais,
793 ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais));
794}
795
796static int msm_ext_disp_audio_codec_rx_plat_remove(
797 struct platform_device *pdev)
798{
Meng Wang15c825d2018-09-06 10:49:18 +0800799 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530800 return 0;
801}
802static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = {
803 { .compatible = "qcom,msm-ext-disp-audio-codec-rx", },
804 {}
805};
806MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match);
807
808static struct platform_driver msm_ext_disp_audio_codec_rx_driver = {
809 .driver = {
810 .name = "msm-ext-disp-audio-codec-rx",
811 .owner = THIS_MODULE,
812 .of_match_table = msm_ext_disp_audio_codec_rx_dt_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800813 .suppress_bind_attrs = true,
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530814 },
815 .probe = msm_ext_disp_audio_codec_rx_plat_probe,
816 .remove = msm_ext_disp_audio_codec_rx_plat_remove,
817};
818
819static int __init msm_ext_disp_audio_codec_rx_init(void)
820{
Karthikeyan Manifc1e9722018-05-03 18:38:56 -0700821 int rc = 0;
Asish Bhattacharya366f7502017-07-25 15:15:56 +0530822
823 rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver);
824 if (rc) {
825 pr_err("%s: failed to register ext disp codec driver err:%d\n",
826 __func__, rc);
827 }
828
829 return rc;
830}
831module_init(msm_ext_disp_audio_codec_rx_init);
832
833static void __exit msm_ext_disp_audio_codec_rx_exit(void)
834{
835 platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver);
836}
837module_exit(msm_ext_disp_audio_codec_rx_exit);
838
839MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver");
840MODULE_LICENSE("GPL v2");