msm_hdmi_codec_rx.c 26 KB

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