msm_hdmi_codec_rx.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/platform_device.h>
  13. #include <linux/slab.h>
  14. #include <linux/module.h>
  15. #include <linux/of_device.h>
  16. #include <linux/err.h>
  17. #include <sound/core.h>
  18. #include <sound/pcm.h>
  19. #include <sound/soc.h>
  20. #include <linux/msm_ext_display.h>
  21. #define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000
  22. #define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT)
  23. #define AUD_EXT_DISP_ACK_CONNECT (AUDIO_ACK_CONNECT)
  24. #define AUD_EXT_DISP_ACK_ENABLE (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE)
  25. static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"};
  26. static const char *const ext_disp_audio_ack_text[] = {"Disconnect", "Connect",
  27. "Ack_Enable"};
  28. static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_type, ext_disp_audio_type_text);
  29. static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_ack_state,
  30. ext_disp_audio_ack_text);
  31. struct msm_ext_disp_audio_codec_rx_data {
  32. struct platform_device *ext_disp_core_pdev;
  33. struct msm_ext_disp_audio_codec_ops ext_disp_ops;
  34. int cable_status;
  35. };
  36. static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol,
  37. struct snd_ctl_elem_info *uinfo)
  38. {
  39. struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
  40. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  41. struct msm_ext_disp_audio_edid_blk edid_blk;
  42. int rc;
  43. codec_data = snd_soc_codec_get_drvdata(codec);
  44. if (!codec_data) {
  45. dev_err(codec->dev, "%s: codec_data is NULL\n", __func__);
  46. return -EINVAL;
  47. }
  48. if (!codec_data->ext_disp_ops.get_audio_edid_blk) {
  49. dev_dbg(codec->dev, "%s: get_audio_edid_blk() is NULL\n",
  50. __func__);
  51. uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
  52. uinfo->count = 0;
  53. return 0;
  54. }
  55. rc = codec_data->ext_disp_ops.get_audio_edid_blk(
  56. codec_data->ext_disp_core_pdev, &edid_blk);
  57. if (rc >= 0) {
  58. uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
  59. uinfo->count = edid_blk.audio_data_blk_size +
  60. edid_blk.spk_alloc_data_blk_size;
  61. }
  62. dev_dbg(codec->dev, "%s: count: %d\n", __func__, uinfo->count);
  63. return rc;
  64. }
  65. static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
  66. struct snd_ctl_elem_value *ucontrol) {
  67. struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
  68. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  69. struct msm_ext_disp_audio_edid_blk edid_blk;
  70. int rc;
  71. codec_data = snd_soc_codec_get_drvdata(codec);
  72. if (!codec_data || !codec_data->ext_disp_ops.get_audio_edid_blk) {
  73. dev_err(codec->dev, "%s: codec_data or get_audio_edid_blk() is NULL\n",
  74. __func__);
  75. return -EINVAL;
  76. }
  77. rc = codec_data->ext_disp_ops.get_audio_edid_blk(
  78. codec_data->ext_disp_core_pdev, &edid_blk);
  79. if (rc >= 0) {
  80. if (sizeof(ucontrol->value.bytes.data) <
  81. (edid_blk.audio_data_blk_size +
  82. edid_blk.spk_alloc_data_blk_size)) {
  83. dev_err(codec->dev,
  84. "%s: Not enough memory to copy EDID data\n",
  85. __func__);
  86. return -ENOMEM;
  87. }
  88. memcpy(ucontrol->value.bytes.data,
  89. edid_blk.audio_data_blk,
  90. edid_blk.audio_data_blk_size);
  91. memcpy((ucontrol->value.bytes.data +
  92. edid_blk.audio_data_blk_size),
  93. edid_blk.spk_alloc_data_blk,
  94. edid_blk.spk_alloc_data_blk_size);
  95. dev_dbg(codec->dev, "%s: data_blk_size:%d, spk_alloc_data_blk_size:%d\n",
  96. __func__, edid_blk.audio_data_blk_size,
  97. edid_blk.spk_alloc_data_blk_size);
  98. }
  99. return rc;
  100. }
  101. static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol,
  102. struct snd_ctl_elem_value *ucontrol)
  103. {
  104. struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
  105. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  106. enum msm_ext_disp_cable_state cable_state;
  107. enum msm_ext_disp_type disp_type;
  108. int rc;
  109. codec_data = snd_soc_codec_get_drvdata(codec);
  110. if (!codec_data ||
  111. !codec_data->ext_disp_ops.get_audio_edid_blk ||
  112. !codec_data->ext_disp_ops.get_intf_id) {
  113. dev_err(codec->dev, "%s: codec_data, get_audio_edid_blk() or get_intf_id is NULL\n",
  114. __func__);
  115. return -EINVAL;
  116. }
  117. cable_state = codec_data->ext_disp_ops.cable_status(
  118. codec_data->ext_disp_core_pdev, 1);
  119. if (cable_state < 0) {
  120. dev_err(codec->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n",
  121. __func__, cable_state);
  122. rc = cable_state;
  123. goto done;
  124. }
  125. codec_data->cable_status = cable_state;
  126. if (cable_state == EXT_DISPLAY_CABLE_DISCONNECT) {
  127. dev_err(codec->dev, "%s: Display cable disconnected\n",
  128. __func__);
  129. ucontrol->value.integer.value[0] = 0;
  130. rc = 0;
  131. goto done;
  132. }
  133. disp_type = codec_data->ext_disp_ops.get_intf_id(
  134. codec_data->ext_disp_core_pdev);
  135. if (disp_type >= 0) {
  136. switch (disp_type) {
  137. case EXT_DISPLAY_TYPE_DP:
  138. ucontrol->value.integer.value[0] = 2;
  139. rc = 0;
  140. break;
  141. case EXT_DISPLAY_TYPE_HDMI:
  142. ucontrol->value.integer.value[0] = 1;
  143. rc = 0;
  144. break;
  145. default:
  146. rc = -EINVAL;
  147. dev_err(codec->dev, "%s: Invalid disp_type:%d\n",
  148. __func__, disp_type);
  149. goto done;
  150. }
  151. dev_dbg(codec->dev, "%s: Display type: %d\n",
  152. __func__, disp_type);
  153. } else {
  154. dev_err(codec->dev, "%s: Error retrieving disp_type from ext_disp, err:%d\n",
  155. __func__, disp_type);
  156. rc = disp_type;
  157. }
  158. done:
  159. return rc;
  160. }
  161. static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
  162. struct snd_ctl_elem_value *ucontrol)
  163. {
  164. struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
  165. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  166. u32 ack_state = 0;
  167. int rc;
  168. codec_data = snd_soc_codec_get_drvdata(codec);
  169. if (!codec_data ||
  170. !codec_data->ext_disp_ops.acknowledge) {
  171. dev_err(codec->dev,
  172. "%s: codec_data or ops acknowledge() is NULL\n",
  173. __func__);
  174. rc = -EINVAL;
  175. goto done;
  176. }
  177. switch (ucontrol->value.enumerated.item[0]) {
  178. case 0:
  179. ack_state = AUD_EXT_DISP_ACK_DISCONNECT;
  180. break;
  181. case 1:
  182. ack_state = AUD_EXT_DISP_ACK_CONNECT;
  183. break;
  184. case 2:
  185. ack_state = AUD_EXT_DISP_ACK_ENABLE;
  186. break;
  187. default:
  188. rc = -EINVAL;
  189. dev_err(codec->dev,
  190. "%s: invalid value %d for mixer ctl\n",
  191. __func__, ucontrol->value.enumerated.item[0]);
  192. goto done;
  193. }
  194. dev_dbg(codec->dev, "%s: control %d, ack set value 0x%x\n",
  195. __func__, ucontrol->value.enumerated.item[0], ack_state);
  196. rc = codec_data->ext_disp_ops.acknowledge(
  197. codec_data->ext_disp_core_pdev, ack_state);
  198. if (rc < 0) {
  199. dev_err(codec->dev, "%s: error from acknowledge(), err:%d\n",
  200. __func__, rc);
  201. }
  202. done:
  203. return rc;
  204. }
  205. static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
  206. {
  207. .access = SNDRV_CTL_ELEM_ACCESS_READ |
  208. SNDRV_CTL_ELEM_ACCESS_VOLATILE,
  209. .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  210. .name = "HDMI EDID",
  211. .info = msm_ext_disp_edid_ctl_info,
  212. .get = msm_ext_disp_edid_get,
  213. },
  214. {
  215. .access = SNDRV_CTL_ELEM_ACCESS_READ |
  216. SNDRV_CTL_ELEM_ACCESS_VOLATILE,
  217. .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  218. .name = "Display Port EDID",
  219. .info = msm_ext_disp_edid_ctl_info,
  220. .get = msm_ext_disp_edid_get,
  221. },
  222. SOC_ENUM_EXT("External Display Type", ext_disp_audio_type,
  223. msm_ext_disp_audio_type_get, NULL),
  224. SOC_ENUM_EXT("External Display Audio Ack", ext_disp_audio_ack_state,
  225. NULL, msm_ext_disp_audio_ack_set),
  226. };
  227. static int msm_ext_disp_audio_codec_rx_dai_startup(
  228. struct snd_pcm_substream *substream,
  229. struct snd_soc_dai *dai)
  230. {
  231. int ret = 0;
  232. struct msm_ext_disp_audio_codec_rx_data *codec_data =
  233. dev_get_drvdata(dai->codec->dev);
  234. if (!codec_data || !codec_data->ext_disp_ops.cable_status) {
  235. dev_err(dai->dev, "%s() codec_data or cable_status is null\n",
  236. __func__);
  237. return -EINVAL;
  238. }
  239. codec_data->cable_status =
  240. codec_data->ext_disp_ops.cable_status(
  241. codec_data->ext_disp_core_pdev, 1);
  242. if (codec_data->cable_status < 0) {
  243. dev_err(dai->dev,
  244. "%s() ext disp core is not ready (ret val = %d)\n",
  245. __func__, codec_data->cable_status);
  246. ret = codec_data->cable_status;
  247. } else if (!codec_data->cable_status) {
  248. dev_err(dai->dev,
  249. "%s() ext disp cable is not connected (ret val = %d)\n",
  250. __func__, codec_data->cable_status);
  251. ret = -ENODEV;
  252. }
  253. return ret;
  254. }
  255. static int msm_ext_disp_audio_codec_rx_dai_hw_params(
  256. struct snd_pcm_substream *substream,
  257. struct snd_pcm_hw_params *params,
  258. struct snd_soc_dai *dai)
  259. {
  260. u32 channel_allocation = 0;
  261. u32 level_shift = 0; /* 0dB */
  262. bool down_mix = 0;
  263. u32 num_channels = params_channels(params);
  264. int rc = 0;
  265. struct msm_ext_disp_audio_setup_params audio_setup_params = {0};
  266. struct msm_ext_disp_audio_codec_rx_data *codec_data =
  267. dev_get_drvdata(dai->codec->dev);
  268. if (!codec_data || !codec_data->ext_disp_ops.audio_info_setup) {
  269. dev_err(dai->dev, "%s: codec_data or audio_info_setup is null\n",
  270. __func__);
  271. return -EINVAL;
  272. }
  273. if (codec_data->cable_status < 0) {
  274. dev_err_ratelimited(dai->dev,
  275. "%s() ext disp core is not ready (ret val = %d)\n",
  276. __func__, codec_data->cable_status);
  277. return codec_data->cable_status;
  278. } else if (!codec_data->cable_status) {
  279. dev_err_ratelimited(dai->dev,
  280. "%s() ext disp cable is not connected (ret val = %d)\n",
  281. __func__, codec_data->cable_status);
  282. return -ENODEV;
  283. }
  284. /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
  285. switch (num_channels) {
  286. case 2:
  287. channel_allocation = 0;
  288. break;
  289. case 3:
  290. channel_allocation = 0x02;/*default to FL/FR/FC*/
  291. audio_setup_params.sample_present = 0x3;
  292. break;
  293. case 4:
  294. channel_allocation = 0x06;/*default to FL/FR/FC/RC*/
  295. audio_setup_params.sample_present = 0x7;
  296. break;
  297. case 5:
  298. channel_allocation = 0x0A;/*default to FL/FR/FC/RR/RL*/
  299. audio_setup_params.sample_present = 0x7;
  300. break;
  301. case 6:
  302. channel_allocation = 0x0B;
  303. audio_setup_params.sample_present = 0x7;
  304. break;
  305. case 7:
  306. channel_allocation = 0x12;/*default to FL/FR/FC/RL/RR/RRC/RLC*/
  307. audio_setup_params.sample_present = 0xf;
  308. break;
  309. case 8:
  310. channel_allocation = 0x13;
  311. audio_setup_params.sample_present = 0xf;
  312. break;
  313. default:
  314. dev_err(dai->dev, "invalid Channels = %u\n", num_channels);
  315. return -EINVAL;
  316. }
  317. dev_dbg(dai->dev,
  318. "%s() num_ch %u samplerate %u channel_allocation = %u\n",
  319. __func__, num_channels, params_rate(params),
  320. channel_allocation);
  321. audio_setup_params.sample_rate_hz = params_rate(params);
  322. audio_setup_params.num_of_channels = num_channels;
  323. audio_setup_params.channel_allocation = channel_allocation;
  324. audio_setup_params.level_shift = level_shift;
  325. audio_setup_params.down_mix = down_mix;
  326. rc = codec_data->ext_disp_ops.audio_info_setup(
  327. codec_data->ext_disp_core_pdev, &audio_setup_params);
  328. if (rc < 0) {
  329. dev_err_ratelimited(dai->dev,
  330. "%s() ext disp core is not ready, rc: %d\n",
  331. __func__, rc);
  332. }
  333. return rc;
  334. }
  335. static void msm_ext_disp_audio_codec_rx_dai_shutdown(
  336. struct snd_pcm_substream *substream,
  337. struct snd_soc_dai *dai)
  338. {
  339. int rc;
  340. struct msm_ext_disp_audio_codec_rx_data *codec_data =
  341. dev_get_drvdata(dai->codec->dev);
  342. if (!codec_data || !codec_data->ext_disp_ops.teardown_done ||
  343. !codec_data->ext_disp_ops.cable_status) {
  344. dev_err(dai->dev, "%s: codec data or teardown_done or cable_status is null\n",
  345. __func__);
  346. return;
  347. }
  348. rc = codec_data->ext_disp_ops.cable_status(
  349. codec_data->ext_disp_core_pdev, 0);
  350. if (rc < 0) {
  351. dev_err(dai->dev,
  352. "%s: ext disp core had problems releasing audio flag\n",
  353. __func__);
  354. }
  355. codec_data->ext_disp_ops.teardown_done(
  356. codec_data->ext_disp_core_pdev);
  357. }
  358. static int msm_ext_disp_audio_codec_rx_probe(struct snd_soc_codec *codec)
  359. {
  360. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  361. struct device_node *of_node_parent = NULL;
  362. codec_data = kzalloc(sizeof(struct msm_ext_disp_audio_codec_rx_data),
  363. GFP_KERNEL);
  364. if (!codec_data) {
  365. dev_err(codec->dev, "%s(): fail to allocate dai data\n",
  366. __func__);
  367. return -ENOMEM;
  368. }
  369. of_node_parent = of_get_parent(codec->dev->of_node);
  370. if (!of_node_parent) {
  371. dev_err(codec->dev, "%s(): Parent device tree node not found\n",
  372. __func__);
  373. kfree(codec_data);
  374. return -ENODEV;
  375. }
  376. codec_data->ext_disp_core_pdev = of_find_device_by_node(of_node_parent);
  377. if (!codec_data->ext_disp_core_pdev) {
  378. dev_err(codec->dev, "%s(): can't get parent pdev\n", __func__);
  379. kfree(codec_data);
  380. return -ENODEV;
  381. }
  382. if (msm_ext_disp_register_audio_codec(codec_data->ext_disp_core_pdev,
  383. &codec_data->ext_disp_ops)) {
  384. dev_err(codec->dev, "%s(): can't register with ext disp core",
  385. __func__);
  386. kfree(codec_data);
  387. return -ENODEV;
  388. }
  389. dev_set_drvdata(codec->dev, codec_data);
  390. dev_dbg(codec->dev, "%s(): registered %s with ext disp core\n",
  391. __func__, codec->component.name);
  392. return 0;
  393. }
  394. static int msm_ext_disp_audio_codec_rx_remove(struct snd_soc_codec *codec)
  395. {
  396. struct msm_ext_disp_audio_codec_rx_data *codec_data;
  397. codec_data = dev_get_drvdata(codec->dev);
  398. kfree(codec_data);
  399. return 0;
  400. }
  401. static struct snd_soc_dai_ops msm_ext_disp_audio_codec_rx_dai_ops = {
  402. .startup = msm_ext_disp_audio_codec_rx_dai_startup,
  403. .hw_params = msm_ext_disp_audio_codec_rx_dai_hw_params,
  404. .shutdown = msm_ext_disp_audio_codec_rx_dai_shutdown
  405. };
  406. static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = {
  407. {
  408. .name = "msm_hdmi_audio_codec_rx_dai",
  409. .playback = {
  410. .stream_name = "HDMI Playback",
  411. .channels_min = 1,
  412. .channels_max = 8,
  413. .rate_min = 48000,
  414. .rate_max = 48000,
  415. .rates = MSM_EXT_DISP_PCM_RATES,
  416. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  417. },
  418. .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
  419. },
  420. {
  421. .name = "msm_dp_audio_codec_rx_dai",
  422. .playback = {
  423. .stream_name = "Display Port Playback",
  424. .channels_min = 1,
  425. .channels_max = 8,
  426. .rate_min = 48000,
  427. .rate_max = 192000,
  428. .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
  429. SNDRV_PCM_RATE_192000,
  430. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  431. SNDRV_PCM_FMTBIT_S24_LE,
  432. },
  433. .ops = &msm_ext_disp_audio_codec_rx_dai_ops,
  434. },
  435. };
  436. static struct snd_soc_codec_driver msm_ext_disp_audio_codec_rx_soc_driver = {
  437. .probe = msm_ext_disp_audio_codec_rx_probe,
  438. .remove = msm_ext_disp_audio_codec_rx_remove,
  439. .component_driver = {
  440. .controls = msm_ext_disp_codec_rx_controls,
  441. .num_controls = ARRAY_SIZE(msm_ext_disp_codec_rx_controls),
  442. },
  443. };
  444. static int msm_ext_disp_audio_codec_rx_plat_probe(
  445. struct platform_device *pdev)
  446. {
  447. dev_dbg(&pdev->dev, "%s(): dev name %s\n", __func__,
  448. dev_name(&pdev->dev));
  449. return snd_soc_register_codec(&pdev->dev,
  450. &msm_ext_disp_audio_codec_rx_soc_driver,
  451. msm_ext_disp_audio_codec_rx_dais,
  452. ARRAY_SIZE(msm_ext_disp_audio_codec_rx_dais));
  453. }
  454. static int msm_ext_disp_audio_codec_rx_plat_remove(
  455. struct platform_device *pdev)
  456. {
  457. snd_soc_unregister_codec(&pdev->dev);
  458. return 0;
  459. }
  460. static const struct of_device_id msm_ext_disp_audio_codec_rx_dt_match[] = {
  461. { .compatible = "qcom,msm-ext-disp-audio-codec-rx", },
  462. {}
  463. };
  464. MODULE_DEVICE_TABLE(of, msm_ext_disp_audio_codec_rx_dt_match);
  465. static struct platform_driver msm_ext_disp_audio_codec_rx_driver = {
  466. .driver = {
  467. .name = "msm-ext-disp-audio-codec-rx",
  468. .owner = THIS_MODULE,
  469. .of_match_table = msm_ext_disp_audio_codec_rx_dt_match,
  470. },
  471. .probe = msm_ext_disp_audio_codec_rx_plat_probe,
  472. .remove = msm_ext_disp_audio_codec_rx_plat_remove,
  473. };
  474. static int __init msm_ext_disp_audio_codec_rx_init(void)
  475. {
  476. int rc;
  477. rc = platform_driver_register(&msm_ext_disp_audio_codec_rx_driver);
  478. if (rc) {
  479. pr_err("%s: failed to register ext disp codec driver err:%d\n",
  480. __func__, rc);
  481. }
  482. return rc;
  483. }
  484. module_init(msm_ext_disp_audio_codec_rx_init);
  485. static void __exit msm_ext_disp_audio_codec_rx_exit(void)
  486. {
  487. platform_driver_unregister(&msm_ext_disp_audio_codec_rx_driver);
  488. }
  489. module_exit(msm_ext_disp_audio_codec_rx_exit);
  490. MODULE_DESCRIPTION("MSM External Display Audio CODEC Driver");
  491. MODULE_LICENSE("GPL v2");