msm_hdmi_codec_rx.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/platform_device.h>
  6. #include <linux/slab.h>
  7. #include <linux/module.h>
  8. #include <linux/of_device.h>
  9. #include <linux/err.h>
  10. #include <sound/core.h>
  11. #include <sound/pcm.h>
  12. #include <sound/soc.h>
  13. #include <linux/soc/qcom/msm_ext_display.h>
  14. #define DRV_NAME "HDMI_codec"
  15. #define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000
  16. #define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT)
  17. #define AUD_EXT_DISP_ACK_CONNECT (AUDIO_ACK_CONNECT)
  18. #define AUD_EXT_DISP_ACK_ENABLE (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE)
  19. #define SOC_EXT_DISP_AUDIO_TYPE(index) \
  20. static SOC_ENUM_SINGLE_DECL(ext_disp_audio_type##index, SND_SOC_NOPM, \
  21. index, ext_disp_audio_type_text)
  22. #define SOC_EXT_DISP_AUDIO_ACK_STATE(index) \
  23. static SOC_ENUM_SINGLE_DECL(ext_disp_audio_ack_state##index, \
  24. SND_SOC_NOPM, index, ext_disp_audio_ack_text)
  25. #define SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type) \
  26. codec_info.type = type; \
  27. codec_info.ctrl_id = codec_data->ctl[dai_id]; \
  28. codec_info.stream_id = codec_data->stream[dai_id]; \
  29. enum {
  30. DP_CONTROLLER0 = 0,
  31. DP_CONTROLLER_MAX,
  32. };
  33. enum {
  34. DP_STREAM0 = 0,
  35. DP_STREAM1,
  36. HDMI,
  37. DP_STREAM_MAX,
  38. };
  39. /*
  40. * Dai id cannot be zero, if component has more than one dai and dai id
  41. * is used to differentiate between them
  42. */
  43. enum {
  44. DP_DAI1 = 1,
  45. DP_DAI2,
  46. HDMI_DAI,
  47. HDMI_MS_DAI,
  48. DP_DAI_MAX,
  49. };
  50. static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"};
  51. static const char *const ext_disp_audio_ack_text[] = {"Disconnect", "Connect",
  52. "Ack_Enable"};
  53. SOC_EXT_DISP_AUDIO_TYPE(1);
  54. SOC_EXT_DISP_AUDIO_ACK_STATE(1);
  55. SOC_EXT_DISP_AUDIO_TYPE(2);
  56. SOC_EXT_DISP_AUDIO_ACK_STATE(2);
  57. SOC_EXT_DISP_AUDIO_TYPE(3);
  58. SOC_EXT_DISP_AUDIO_ACK_STATE(3);
  59. struct msm_ext_disp_audio_codec_rx_data {
  60. struct platform_device *ext_disp_core_pdev;
  61. struct msm_ext_disp_audio_codec_ops ext_disp_ops;
  62. struct mutex dp_ops_lock;
  63. int cable_status[DP_DAI_MAX];
  64. int stream[DP_DAI_MAX];
  65. int ctl[DP_DAI_MAX];
  66. };
  67. static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol,
  68. struct snd_ctl_elem_info *uinfo)
  69. {
  70. struct snd_soc_component *component =
  71. snd_soc_kcontrol_component(kcontrol);
  72. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  73. struct msm_ext_disp_audio_edid_blk edid_blk;
  74. int rc = 0;
  75. struct msm_ext_disp_codec_id codec_info;
  76. int dai_id = kcontrol->private_value;
  77. int type;
  78. codec_data = snd_soc_component_get_drvdata(component);
  79. if (!codec_data) {
  80. dev_err_ratelimited(component->dev, "%s: codec_data is NULL\n", __func__);
  81. return -EINVAL;
  82. }
  83. dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
  84. codec_data->ctl[dai_id], codec_data->stream[dai_id]);
  85. mutex_lock(&codec_data->dp_ops_lock);
  86. if (dai_id == HDMI_MS_DAI)
  87. type = EXT_DISPLAY_TYPE_HDMI;
  88. else
  89. type = EXT_DISPLAY_TYPE_DP;
  90. SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
  91. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  92. &codec_info);
  93. if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) {
  94. dev_dbg(component->dev, "%s: get_audio_edid_blk() is NULL\n",
  95. __func__);
  96. uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
  97. uinfo->count = 0;
  98. mutex_unlock(&codec_data->dp_ops_lock);
  99. return 0;
  100. }
  101. rc = codec_data->ext_disp_ops.get_audio_edid_blk(
  102. codec_data->ext_disp_core_pdev, &edid_blk);
  103. mutex_unlock(&codec_data->dp_ops_lock);
  104. if (rc >= 0) {
  105. uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
  106. uinfo->count = edid_blk.audio_data_blk_size +
  107. edid_blk.spk_alloc_data_blk_size;
  108. }
  109. dev_dbg(component->dev, "%s: count: %d\n", __func__, uinfo->count);
  110. return rc;
  111. }
  112. static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
  113. struct snd_ctl_elem_value *ucontrol) {
  114. struct snd_soc_component *component =
  115. snd_soc_kcontrol_component(kcontrol);
  116. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  117. struct msm_ext_disp_audio_edid_blk edid_blk;
  118. struct msm_ext_disp_codec_id codec_info;
  119. int rc = 0;
  120. int dai_id = kcontrol->private_value;
  121. int type;
  122. codec_data = snd_soc_component_get_drvdata(component);
  123. if (!codec_data) {
  124. dev_err_ratelimited(component->dev, "%s: codec_data is NULL\n",
  125. __func__);
  126. return -EINVAL;
  127. }
  128. dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
  129. codec_data->ctl[dai_id], codec_data->stream[dai_id]);
  130. mutex_lock(&codec_data->dp_ops_lock);
  131. if (dai_id == HDMI_MS_DAI)
  132. type = EXT_DISPLAY_TYPE_HDMI;
  133. else
  134. type = EXT_DISPLAY_TYPE_DP;
  135. SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
  136. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  137. &codec_info);
  138. if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) {
  139. dev_err_ratelimited(component->dev,
  140. "%s: codec_data or get_audio_edid_blk() is NULL\n",
  141. __func__);
  142. mutex_unlock(&codec_data->dp_ops_lock);
  143. return -EINVAL;
  144. }
  145. rc = codec_data->ext_disp_ops.get_audio_edid_blk(
  146. codec_data->ext_disp_core_pdev, &edid_blk);
  147. mutex_unlock(&codec_data->dp_ops_lock);
  148. if (rc >= 0) {
  149. if (sizeof(ucontrol->value.bytes.data) <
  150. (edid_blk.audio_data_blk_size +
  151. edid_blk.spk_alloc_data_blk_size)) {
  152. dev_err_ratelimited(component->dev,
  153. "%s: Not enough memory to copy EDID data\n",
  154. __func__);
  155. return -ENOMEM;
  156. }
  157. memcpy(ucontrol->value.bytes.data,
  158. edid_blk.audio_data_blk,
  159. edid_blk.audio_data_blk_size);
  160. memcpy((ucontrol->value.bytes.data +
  161. edid_blk.audio_data_blk_size),
  162. edid_blk.spk_alloc_data_blk,
  163. edid_blk.spk_alloc_data_blk_size);
  164. dev_dbg(component->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n",
  165. __func__, edid_blk.audio_data_blk_size,
  166. edid_blk.spk_alloc_data_blk_size);
  167. }
  168. return rc;
  169. }
  170. static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
  171. struct snd_ctl_elem_value *ucontrol)
  172. {
  173. struct snd_soc_component *component =
  174. snd_soc_kcontrol_component(kcontrol);
  175. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  176. enum msm_ext_disp_cable_state cable_state;
  177. enum msm_ext_disp_type disp_type;
  178. struct msm_ext_disp_codec_id codec_info;
  179. int rc = 0;
  180. int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
  181. int type;
  182. codec_data = snd_soc_component_get_drvdata(component);
  183. if (!codec_data) {
  184. dev_err_ratelimited(component->dev, "%s: codec_data is NULL\n",
  185. __func__);
  186. return -EINVAL;
  187. }
  188. dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
  189. codec_data->ctl[dai_id], codec_data->stream[dai_id]);
  190. mutex_lock(&codec_data->dp_ops_lock);
  191. if (dai_id == HDMI_MS_DAI)
  192. type = EXT_DISPLAY_TYPE_HDMI;
  193. else
  194. type = EXT_DISPLAY_TYPE_DP;
  195. SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
  196. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  197. &codec_info);
  198. if (!codec_data->ext_disp_ops.get_audio_edid_blk ||
  199. !codec_data->ext_disp_ops.get_intf_id || rc) {
  200. dev_err_ratelimited(component->dev, "%s: get_audio_edid_blk() or get_intf_id is NULL\n",
  201. __func__);
  202. rc = -EINVAL;
  203. goto cable_err;
  204. }
  205. cable_state = codec_data->ext_disp_ops.cable_status(
  206. codec_data->ext_disp_core_pdev, 1);
  207. if (cable_state < 0) {
  208. dev_err_ratelimited(component->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n",
  209. __func__, cable_state);
  210. rc = cable_state;
  211. goto cable_err;
  212. }
  213. codec_data->cable_status[dai_id] = cable_state;
  214. if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) {
  215. dev_err_ratelimited(component->dev, "%s: Display cable disconnected\n",
  216. __func__);
  217. ucontrol->value.integer.value[0] = 0;
  218. rc = 0;
  219. goto cable_err;
  220. }
  221. disp_type = codec_data->ext_disp_ops.get_intf_id(
  222. codec_data->ext_disp_core_pdev);
  223. mutex_unlock(&codec_data->dp_ops_lock);
  224. if (disp_type >= 0) {
  225. switch (disp_type) {
  226. case EXT_DISPLAY_TYPE_DP:
  227. ucontrol->value.integer.value[0] = 2;
  228. rc = 0;
  229. break;
  230. case EXT_DISPLAY_TYPE_HDMI:
  231. ucontrol->value.integer.value[0] = 1;
  232. rc = 0;
  233. break;
  234. default:
  235. rc = -EINVAL;
  236. dev_err_ratelimited(component->dev, "%s: Invalid disp_type:%d\n",
  237. __func__, disp_type);
  238. goto done;
  239. }
  240. dev_dbg(component->dev, "%s: Display type: %d\n",
  241. __func__, disp_type);
  242. } else {
  243. dev_err_ratelimited(component->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n",
  244. __func__, disp_type);
  245. rc = disp_type;
  246. }
  247. return rc;
  248. cable_err:
  249. mutex_unlock(&codec_data->dp_ops_lock);
  250. done:
  251. return rc;
  252. }
  253. static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
  254. struct snd_ctl_elem_value *ucontrol)
  255. {
  256. struct snd_soc_component *component =
  257. snd_soc_kcontrol_component(kcontrol);
  258. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  259. u32 ack_state = 0;
  260. struct msm_ext_disp_codec_id codec_info;
  261. int rc = 0;
  262. int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l;
  263. int type;
  264. codec_data = snd_soc_component_get_drvdata(component);
  265. if (!codec_data) {
  266. dev_err_ratelimited(component->dev,
  267. "%s: codec_data is NULL\n",
  268. __func__);
  269. return -EINVAL;
  270. }
  271. dev_dbg(component->dev, "%s: DP ctl id %d Stream id %d\n", __func__,
  272. codec_data->ctl[dai_id], codec_data->stream[dai_id]);
  273. mutex_lock(&codec_data->dp_ops_lock);
  274. if (dai_id == HDMI_MS_DAI)
  275. type = EXT_DISPLAY_TYPE_HDMI;
  276. else
  277. type = EXT_DISPLAY_TYPE_DP;
  278. SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type);
  279. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  280. &codec_info);
  281. if (!codec_data->ext_disp_ops.acknowledge || rc) {
  282. dev_err_ratelimited(component->dev,
  283. "%s: codec_data ops acknowledge() is NULL\n",
  284. __func__);
  285. rc = -EINVAL;
  286. goto err;
  287. }
  288. switch (ucontrol->value.enumerated.item[0]) {
  289. case 0:
  290. ack_state = AUD_EXT_DISP_ACK_DISCONNECT;
  291. break;
  292. case 1:
  293. ack_state = AUD_EXT_DISP_ACK_CONNECT;
  294. break;
  295. case 2:
  296. ack_state = AUD_EXT_DISP_ACK_ENABLE;
  297. break;
  298. default:
  299. rc = -EINVAL;
  300. dev_err_ratelimited(component->dev,
  301. "%s: invalid value %d for mixer ctl\n",
  302. __func__, ucontrol->value.enumerated.item[0]);
  303. goto err;
  304. }
  305. dev_dbg(component->dev, "%s: control %d, ack set value 0x%x\n",
  306. __func__, ucontrol->value.enumerated.item[0], ack_state);
  307. rc = codec_data->ext_disp_ops.acknowledge(
  308. codec_data->ext_disp_core_pdev, ack_state);
  309. mutex_unlock(&codec_data->dp_ops_lock);
  310. if (rc < 0) {
  311. dev_err_ratelimited(component->dev, "%s: error from acknowledge(), err:%d\n",
  312. __func__, rc);
  313. }
  314. return rc;
  315. err:
  316. mutex_unlock(&codec_data->dp_ops_lock);
  317. return rc;
  318. }
  319. static int msm_ext_disp_audio_device_get(struct snd_kcontrol *kcontrol,
  320. struct snd_ctl_elem_value *ucontrol)
  321. {
  322. struct snd_soc_component *component =
  323. snd_soc_kcontrol_component(kcontrol);
  324. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  325. int rc = 0;
  326. int dai_id = ((struct soc_multi_mixer_control *)
  327. kcontrol->private_value)->shift;
  328. if (dai_id < 0 || dai_id > DP_DAI2) {
  329. dev_err_ratelimited(component->dev,
  330. "%s: invalid dai id: %d\n", __func__, dai_id);
  331. rc = -EINVAL;
  332. goto done;
  333. }
  334. codec_data = snd_soc_component_get_drvdata(component);
  335. if (!codec_data) {
  336. dev_err_ratelimited(component->dev,
  337. "%s: codec_data or ops acknowledge() is NULL\n",
  338. __func__);
  339. rc = -EINVAL;
  340. goto done;
  341. }
  342. ucontrol->value.integer.value[0] = codec_data->ctl[dai_id];
  343. ucontrol->value.integer.value[1] = codec_data->stream[dai_id];
  344. done:
  345. return rc;
  346. }
  347. static int msm_ext_disp_audio_device_set(struct snd_kcontrol *kcontrol,
  348. struct snd_ctl_elem_value *ucontrol)
  349. {
  350. struct snd_soc_component *component =
  351. snd_soc_kcontrol_component(kcontrol);
  352. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  353. int rc = 0;
  354. int dai_id = ((struct soc_multi_mixer_control *)
  355. kcontrol->private_value)->shift;
  356. if (dai_id < 0 || dai_id > DP_DAI2) {
  357. dev_err_ratelimited(component->dev,
  358. "%s: invalid dai id: %d\n", __func__, dai_id);
  359. rc = -EINVAL;
  360. goto done;
  361. }
  362. codec_data = snd_soc_component_get_drvdata(component);
  363. if (!codec_data) {
  364. dev_err_ratelimited(component->dev,
  365. "%s: codec_data or ops acknowledge() is NULL\n",
  366. __func__);
  367. rc = -EINVAL;
  368. goto done;
  369. }
  370. if ((ucontrol->value.integer.value[0] > (DP_CONTROLLER_MAX - 1)) ||
  371. (ucontrol->value.integer.value[1] > (DP_STREAM_MAX - 1)) ||
  372. (ucontrol->value.integer.value[0] < 0) ||
  373. (ucontrol->value.integer.value[1] < 0)) {
  374. dev_err_ratelimited(component->dev,
  375. "%s: DP audio control index invalid\n",
  376. __func__);
  377. rc = -EINVAL;
  378. goto done;
  379. }
  380. mutex_lock(&codec_data->dp_ops_lock);
  381. codec_data->ctl[dai_id] = ucontrol->value.integer.value[0];
  382. codec_data->stream[dai_id] = ucontrol->value.integer.value[1];
  383. mutex_unlock(&codec_data->dp_ops_lock);
  384. done:
  385. return rc;
  386. }
  387. static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
  388. {
  389. .access = SNDRV_CTL_ELEM_ACCESS_READ |
  390. SNDRV_CTL_ELEM_ACCESS_VOLATILE,
  391. .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  392. .name = "HDMI EDID",
  393. .info = msm_ext_disp_edid_ctl_info,
  394. .get = msm_ext_disp_edid_get,
  395. .private_value = HDMI_DAI,
  396. },
  397. {
  398. .access = SNDRV_CTL_ELEM_ACCESS_READ |
  399. SNDRV_CTL_ELEM_ACCESS_VOLATILE,
  400. .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  401. .name = "HDMI MS EDID",
  402. .info = msm_ext_disp_edid_ctl_info,
  403. .get = msm_ext_disp_edid_get,
  404. .private_value = HDMI_MS_DAI,
  405. },
  406. {
  407. .access = SNDRV_CTL_ELEM_ACCESS_READ |
  408. SNDRV_CTL_ELEM_ACCESS_VOLATILE,
  409. .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  410. .name = "Display Port EDID",
  411. .info = msm_ext_disp_edid_ctl_info,
  412. .get = msm_ext_disp_edid_get,
  413. .private_value = DP_DAI1,
  414. },
  415. {
  416. .access = SNDRV_CTL_ELEM_ACCESS_READ |
  417. SNDRV_CTL_ELEM_ACCESS_VOLATILE,
  418. .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  419. .name = "Display Port1 EDID",
  420. .info = msm_ext_disp_edid_ctl_info,
  421. .get = msm_ext_disp_edid_get,
  422. .private_value = DP_DAI2,
  423. },
  424. SOC_ENUM_EXT("External Display Type",
  425. ext_disp_audio_type1,
  426. msm_ext_disp_audio_type_get, NULL),
  427. SOC_ENUM_EXT("External Display1 Type",
  428. ext_disp_audio_type2,
  429. msm_ext_disp_audio_type_get, NULL),
  430. SOC_ENUM_EXT("External HDMI Type",
  431. ext_disp_audio_type3,
  432. msm_ext_disp_audio_type_get, NULL),
  433. SOC_ENUM_EXT("External Display Audio Ack",
  434. ext_disp_audio_ack_state1,
  435. NULL, msm_ext_disp_audio_ack_set),
  436. SOC_ENUM_EXT("External Display1 Audio Ack",
  437. ext_disp_audio_ack_state2,
  438. NULL, msm_ext_disp_audio_ack_set),
  439. SOC_ENUM_EXT("External HDMI Audio Ack",
  440. ext_disp_audio_ack_state3,
  441. NULL, msm_ext_disp_audio_ack_set),
  442. SOC_SINGLE_MULTI_EXT("External Display Audio Device",
  443. SND_SOC_NOPM, DP_DAI1, DP_STREAM_MAX - 1, 0, 2,
  444. msm_ext_disp_audio_device_get,
  445. msm_ext_disp_audio_device_set),
  446. SOC_SINGLE_MULTI_EXT("External Display1 Audio Device",
  447. SND_SOC_NOPM, DP_DAI2, DP_STREAM_MAX - 1, 0, 2,
  448. msm_ext_disp_audio_device_get,
  449. msm_ext_disp_audio_device_set),
  450. SOC_SINGLE_MULTI_EXT("External HDMI Device",
  451. SND_SOC_NOPM, HDMI_MS_DAI, DP_STREAM_MAX - 1, 0, 2,
  452. msm_ext_disp_audio_device_get,
  453. msm_ext_disp_audio_device_set),
  454. };
  455. static int msm_ext_disp_audio_codec_rx_dai_startup(
  456. struct snd_pcm_substream *substream,
  457. struct snd_soc_dai *dai)
  458. {
  459. int ret = 0, rc = 0;
  460. struct msm_ext_disp_codec_id codec_info;
  461. struct msm_ext_disp_audio_codec_rx_data *codec_data =
  462. dev_get_drvdata(dai->component->dev);
  463. int type;
  464. if (!codec_data) {
  465. dev_err_ratelimited(dai->dev, "%s() codec_data is null\n",
  466. __func__);
  467. return -EINVAL;
  468. }
  469. dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n",
  470. __func__,
  471. codec_data->ctl[dai->id], codec_data->stream[dai->id]);
  472. mutex_lock(&codec_data->dp_ops_lock);
  473. if (dai->id == HDMI_MS_DAI)
  474. type = EXT_DISPLAY_TYPE_HDMI;
  475. else
  476. type = EXT_DISPLAY_TYPE_DP;
  477. SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
  478. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  479. &codec_info);
  480. if (!codec_data->ext_disp_ops.cable_status || rc) {
  481. dev_err_ratelimited(dai->dev, "%s() cable_status is null\n",
  482. __func__);
  483. mutex_unlock(&codec_data->dp_ops_lock);
  484. return -EINVAL;
  485. }
  486. codec_data->cable_status[dai->id] =
  487. codec_data->ext_disp_ops.cable_status(
  488. codec_data->ext_disp_core_pdev, 1);
  489. mutex_unlock(&codec_data->dp_ops_lock);
  490. if (codec_data->cable_status[dai->id] < 0) {
  491. dev_err_ratelimited(dai->dev,
  492. "%s() ext disp core is not ready (ret val = %d)\n",
  493. __func__, codec_data->cable_status[dai->id]);
  494. ret = codec_data->cable_status[dai->id];
  495. } else if (!codec_data->cable_status[dai->id]) {
  496. dev_err_ratelimited(dai->dev,
  497. "%s() ext disp cable is not connected (ret val = %d)\n",
  498. __func__, codec_data->cable_status[dai->id]);
  499. ret = -ENODEV;
  500. }
  501. return ret;
  502. }
  503. static int msm_ext_disp_audio_codec_rx_dai_hw_params(
  504. struct snd_pcm_substream *substream,
  505. struct snd_pcm_hw_params *params,
  506. struct snd_soc_dai *dai)
  507. {
  508. u32 channel_allocation = 0;
  509. u32 level_shift = 0; /* 0dB */
  510. bool down_mix = 0;
  511. u32 num_channels = params_channels(params);
  512. struct msm_ext_disp_codec_id codec_info;
  513. int rc = 0;
  514. struct msm_ext_disp_audio_setup_params audio_setup_params = {0};
  515. int type;
  516. struct msm_ext_disp_audio_codec_rx_data *codec_data =
  517. dev_get_drvdata(dai->component->dev);
  518. if (!codec_data) {
  519. dev_err_ratelimited(dai->dev, "%s() codec_data is null\n",
  520. __func__);
  521. return -EINVAL;
  522. }
  523. dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n",
  524. __func__,
  525. codec_data->ctl[dai->id], codec_data->stream[dai->id]);
  526. mutex_lock(&codec_data->dp_ops_lock);
  527. if (dai->id == HDMI_MS_DAI)
  528. type = EXT_DISPLAY_TYPE_HDMI;
  529. else
  530. type = EXT_DISPLAY_TYPE_DP;
  531. SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
  532. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  533. &codec_info);
  534. if (!codec_data->ext_disp_ops.audio_info_setup || rc) {
  535. dev_err_ratelimited(dai->dev, "%s: audio_info_setup is null\n",
  536. __func__);
  537. mutex_unlock(&codec_data->dp_ops_lock);
  538. return -EINVAL;
  539. }
  540. mutex_unlock(&codec_data->dp_ops_lock);
  541. if (codec_data->cable_status[dai->id] < 0) {
  542. dev_err_ratelimited(dai->dev,
  543. "%s() ext disp core is not ready (ret val = %d)\n",
  544. __func__, codec_data->cable_status[dai->id]);
  545. return codec_data->cable_status[dai->id];
  546. } else if (!codec_data->cable_status[dai->id]) {
  547. dev_err_ratelimited(dai->dev,
  548. "%s() ext disp cable is not connected (ret val = %d)\n",
  549. __func__, codec_data->cable_status[dai->id]);
  550. return -ENODEV;
  551. }
  552. /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
  553. switch (num_channels) {
  554. case 2:
  555. channel_allocation = 0;
  556. break;
  557. case 3:
  558. channel_allocation = 0x02;/*default to FL/FR/FC*/
  559. audio_setup_params.sample_present = 0x3;
  560. break;
  561. case 4:
  562. channel_allocation = 0x06;/*default to FL/FR/FC/RC*/
  563. audio_setup_params.sample_present = 0x7;
  564. break;
  565. case 5:
  566. channel_allocation = 0x0A;/*default to FL/FR/FC/RR/RL*/
  567. audio_setup_params.sample_present = 0x7;
  568. break;
  569. case 6:
  570. channel_allocation = 0x0B;
  571. audio_setup_params.sample_present = 0x7;
  572. break;
  573. case 7:
  574. channel_allocation = 0x12;/*default to FL/FR/FC/RL/RR/RRC/RLC*/
  575. audio_setup_params.sample_present = 0xf;
  576. break;
  577. case 8:
  578. channel_allocation = 0x13;
  579. audio_setup_params.sample_present = 0xf;
  580. break;
  581. default:
  582. dev_err_ratelimited(dai->dev, "invalid Channels = %u\n", num_channels);
  583. return -EINVAL;
  584. }
  585. dev_dbg(dai->dev,
  586. "%s() num_ch %u samplerate %u channel_allocation = %u\n",
  587. __func__, num_channels, params_rate(params),
  588. channel_allocation);
  589. audio_setup_params.sample_rate_hz = params_rate(params);
  590. audio_setup_params.num_of_channels = num_channels;
  591. audio_setup_params.channel_allocation = channel_allocation;
  592. audio_setup_params.level_shift = level_shift;
  593. audio_setup_params.down_mix = down_mix;
  594. mutex_lock(&codec_data->dp_ops_lock);
  595. SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
  596. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  597. &codec_info);
  598. if (rc)
  599. goto end;
  600. rc = codec_data->ext_disp_ops.audio_info_setup(
  601. codec_data->ext_disp_core_pdev, &audio_setup_params);
  602. end:
  603. mutex_unlock(&codec_data->dp_ops_lock);
  604. if (rc < 0) {
  605. dev_err_ratelimited(dai->dev,
  606. "%s() ext disp core is not ready, rc: %d\n",
  607. __func__, rc);
  608. }
  609. return rc;
  610. }
  611. static void msm_ext_disp_audio_codec_rx_dai_shutdown(
  612. struct snd_pcm_substream *substream,
  613. struct snd_soc_dai *dai)
  614. {
  615. int rc = 0;
  616. struct msm_ext_disp_codec_id codec_info;
  617. struct msm_ext_disp_audio_codec_rx_data *codec_data =
  618. dev_get_drvdata(dai->component->dev);
  619. int type;
  620. if (!codec_data) {
  621. dev_err_ratelimited(dai->dev, "%s() codec_data is null\n",
  622. __func__);
  623. return;
  624. }
  625. dev_dbg(dai->component->dev, "%s: DP ctl id %d Stream id %d\n",
  626. __func__,
  627. codec_data->ctl[dai->id], codec_data->stream[dai->id]);
  628. mutex_lock(&codec_data->dp_ops_lock);
  629. if (dai->id == HDMI_MS_DAI)
  630. type = EXT_DISPLAY_TYPE_HDMI;
  631. else
  632. type = EXT_DISPLAY_TYPE_DP;
  633. SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type);
  634. rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev,
  635. &codec_info);
  636. if (!codec_data->ext_disp_ops.teardown_done ||
  637. !codec_data->ext_disp_ops.cable_status || rc) {
  638. dev_err_ratelimited(dai->dev, "%s: teardown_done or cable_status is null\n",
  639. __func__);
  640. mutex_unlock(&codec_data->dp_ops_lock);
  641. return;
  642. }
  643. rc = codec_data->ext_disp_ops.cable_status(
  644. codec_data->ext_disp_core_pdev, 0);
  645. if (rc < 0) {
  646. dev_err_ratelimited(dai->dev,
  647. "%s: ext disp core had problems releasing audio flag\n",
  648. __func__);
  649. }
  650. codec_data->ext_disp_ops.teardown_done(
  651. codec_data->ext_disp_core_pdev);
  652. mutex_unlock(&codec_data->dp_ops_lock);
  653. }
  654. static int msm_ext_disp_audio_codec_rx_probe(
  655. struct snd_soc_component *component)
  656. {
  657. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  658. struct device_node *of_node_parent = NULL;
  659. codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data),
  660. GFP_KERNEL);
  661. if (!codec_data) {
  662. dev_err(component->dev, "%s(): fail to allocate dai data\n",
  663. __func__);
  664. return -ENOMEM;
  665. }
  666. of_node_parent = of_get_parent(component->dev->of_node);
  667. if (!of_node_parent) {
  668. dev_err(component->dev, "%s(): Parent device tree node not found\n",
  669. __func__);
  670. kfree(codec_data);
  671. return -ENODEV;
  672. }
  673. codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent);
  674. if (!codec_data->ext_disp_core_pdev) {
  675. dev_err(component->dev, "%s(): can't get parent pdev\n",
  676. __func__);
  677. kfree(codec_data);
  678. return -ENODEV;
  679. }
  680. if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev,
  681. &codec_data->ext_disp_ops)) {
  682. dev_err(component->dev, "%s(): can't register with ext disp core",
  683. __func__);
  684. kfree(codec_data);
  685. return -ENODEV;
  686. }
  687. mutex_init(&codec_data->dp_ops_lock);
  688. dev_set_drvdata(component->dev, codec_data);
  689. dev_dbg(component->dev, "%s(): registered %s with ext disp core\n",
  690. __func__, component->name);
  691. return 0;
  692. }
  693. static void msm_ext_disp_audio_codec_rx_remove(
  694. struct snd_soc_component *component)
  695. {
  696. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  697. codec_data = dev_get_drvdata(component->dev);
  698. mutex_destroy(&codec_data->dp_ops_lock);
  699. kfree(codec_data);
  700. return;
  701. }
  702. static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = {
  703. .startup = msm_ext_disp_audio_codec_rx_dai_startup,
  704. .hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params,
  705. .shutdown = msm_ext_disp_audio_codec_rx_dai_shutdown
  706. };
  707. static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = {
  708. {
  709. .name = "msm_hdmi_audio_codec_rx_dai",
  710. .id = HDMI_DAI,
  711. .playback = {
  712. .stream_name = "HDMI Playback",
  713. .channels_min = 1,
  714. .channels_max = 8,
  715. .rate_min = 48000,
  716. .rate_max = 48000,
  717. .rates = MSM_EXT_DISP_PCM_RATES,
  718. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  719. },
  720. .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
  721. },
  722. {
  723. .name = "msm_hdmi_ms_audio_codec_rx_dai",
  724. .id = HDMI_MS_DAI,
  725. .playback = {
  726. .stream_name = "HDMI MS Playback",
  727. .channels_min = 1,
  728. .channels_max = 8,
  729. .rate_min = 48000,
  730. .rate_max = 48000,
  731. .rates = MSM_EXT_DISP_PCM_RATES,
  732. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  733. },
  734. .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
  735. },
  736. {
  737. .name = "msm_dp_audio_codec_rx_dai",
  738. .id = DP_DAI1,
  739. .playback = {
  740. .stream_name = "Display Port Playback",
  741. .channels_min = 1,
  742. .channels_max = 8,
  743. .rate_min = 32000,
  744. .rate_max = 192000,
  745. .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
  746. SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_44100,
  747. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  748. SNDRV_PCM_FMTBIT_S24_LE |
  749. SNDRV_PCM_FMTBIT_S24_3LE,
  750. },
  751. .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
  752. },
  753. {
  754. .name = "msm_dp_audio_codec_rx1_dai",
  755. .id = DP_DAI2,
  756. .playback = {
  757. .stream_name = "Display Port1 Playback",
  758. .channels_min = 1,
  759. .channels_max = 8,
  760. .rate_min = 48000,
  761. .rate_max = 192000,
  762. .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
  763. SNDRV_PCM_RATE_192000,
  764. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  765. SNDRV_PCM_FMTBIT_S24_LE |
  766. SNDRV_PCM_FMTBIT_S24_3LE,
  767. },
  768. .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
  769. },
  770. };
  771. static const struct snd_soc_component_driver msm_ext_disp_codec_rx_driver = {
  772. .name = DRV_NAME,
  773. .probe = msm_ext_disp_audio_codec_rx_probe,
  774. .remove = msm_ext_disp_audio_codec_rx_remove,
  775. .controls = msm_ext_disp_codec_rx_controls,
  776. .num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls),
  777. };
  778. static int msm_ext_disp_audio_codec_rx_plat_probe(
  779. struct platform_device *pdev)
  780. {
  781. dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__,
  782. dev_name(&pdev->dev));
  783. return snd_soc_register_component(&pdev->dev,
  784. &msm_ext_disp_codec_rx_driver,
  785. msm_ext_disp_audio_codec_rx_dais,
  786. ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais));
  787. }
  788. static int msm_ext_disp_audio_codec_rx_plat_remove(
  789. struct platform_device *pdev)
  790. {
  791. snd_soc_unregister_component(&pdev->dev);
  792. return 0;
  793. }
  794. static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = {
  795. { .compatible = "qcom,msm-ext-disp-audio-codec-rx", },
  796. {}
  797. };
  798. MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match);
  799. static struct platform_driver msm_ext_disp_audio_codec_rx_driver = {
  800. .driver = {
  801. .name = "msm-ext-disp-audio-codec-rx",
  802. .owner = THIS_MODULE,
  803. .of_match_table = msm_ext_disp_audio_codec_rx_dt_match,
  804. .suppress_bind_attrs = true,
  805. },
  806. .probe = msm_ext_disp_audio_codec_rx_plat_probe,
  807. .remove = msm_ext_disp_audio_codec_rx_plat_remove,
  808. };
  809. static int __init msm_ext_disp_audio_codec_rx_init(void)
  810. {
  811. int rc = 0;
  812. rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver);
  813. if (rc) {
  814. pr_err("%s: failed to register ext disp codec driver err:%d\n",
  815. __func__, rc);
  816. }
  817. return rc;
  818. }
  819. module_init(msm_ext_disp_audio_codec_rx_init);
  820. static void __exit msm_ext_disp_audio_codec_rx_exit(void)
  821. {
  822. platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver);
  823. }
  824. module_exit(msm_ext_disp_audio_codec_rx_exit);
  825. MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver");
  826. MODULE_LICENSE("GPL v2");