msm_hdmi_codec_rx.c 24 KB

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