msm_hdmi_codec_rx.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /* Copyright (c) 2012-2013, 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 <mach/msm_hdmi_audio_codec.h>
  21. #define MSM_HDMI_PCM_RATES SNDRV_PCM_RATE_48000
  22. struct msm_hdmi_audio_codec_rx_data {
  23. struct platform_device *hdmi_core_pdev;
  24. struct msm_hdmi_audio_codec_ops hdmi_ops;
  25. };
  26. static int msm_hdmi_edid_ctl_info(struct snd_kcontrol *kcontrol,
  27. struct snd_ctl_elem_info *uinfo)
  28. {
  29. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  30. struct msm_hdmi_audio_codec_rx_data *codec_data;
  31. struct msm_hdmi_audio_edid_blk edid_blk;
  32. int rc;
  33. codec_data = snd_soc_codec_get_drvdata(codec);
  34. rc = codec_data->hdmi_ops.get_audio_edid_blk(codec_data->hdmi_core_pdev,
  35. &edid_blk);
  36. uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
  37. if (!IS_ERR_VALUE(rc)) {
  38. uinfo->count = edid_blk.audio_data_blk_size +
  39. edid_blk.spk_alloc_data_blk_size;
  40. }
  41. return 0;
  42. }
  43. static int msm_hdmi_edid_get(struct snd_kcontrol *kcontrol,
  44. struct snd_ctl_elem_value *ucontrol) {
  45. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  46. struct msm_hdmi_audio_codec_rx_data *codec_data;
  47. struct msm_hdmi_audio_edid_blk edid_blk;
  48. int rc;
  49. codec_data = snd_soc_codec_get_drvdata(codec);
  50. rc = codec_data->hdmi_ops.get_audio_edid_blk(
  51. codec_data->hdmi_core_pdev, &edid_blk);
  52. if (!IS_ERR_VALUE(rc)) {
  53. memcpy(ucontrol->value.bytes.data, edid_blk.audio_data_blk,
  54. edid_blk.audio_data_blk_size);
  55. memcpy((ucontrol->value.bytes.data +
  56. edid_blk.audio_data_blk_size),
  57. edid_blk.spk_alloc_data_blk,
  58. edid_blk.spk_alloc_data_blk_size);
  59. }
  60. return rc;
  61. }
  62. static const struct snd_kcontrol_new msm_hdmi_codec_rx_controls[] = {
  63. {
  64. .access = SNDRV_CTL_ELEM_ACCESS_READ |
  65. SNDRV_CTL_ELEM_ACCESS_VOLATILE,
  66. .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  67. .name = "HDMI EDID",
  68. .info = msm_hdmi_edid_ctl_info,
  69. .get = msm_hdmi_edid_get,
  70. },
  71. };
  72. static int msm_hdmi_audio_codec_rx_dai_startup(
  73. struct snd_pcm_substream *substream,
  74. struct snd_soc_dai *dai)
  75. {
  76. int rv = 0;
  77. struct msm_hdmi_audio_codec_rx_data *codec_data =
  78. dev_get_drvdata(dai->codec->dev);
  79. rv = codec_data->hdmi_ops.hdmi_cable_status(
  80. codec_data->hdmi_core_pdev, 1);
  81. if (IS_ERR_VALUE(rv)) {
  82. dev_err(dai->dev,
  83. "%s() HDMI core is not ready (rv = %d)\n",
  84. __func__, rv);
  85. } else if (!rv) {
  86. dev_err(dai->dev,
  87. "%s() HDMI cable is not connected (ret val = %d)\n",
  88. __func__, rv);
  89. rv = -EAGAIN;
  90. }
  91. return rv;
  92. }
  93. static int msm_hdmi_audio_codec_rx_dai_hw_params(
  94. struct snd_pcm_substream *substream,
  95. struct snd_pcm_hw_params *params,
  96. struct snd_soc_dai *dai)
  97. {
  98. u32 channel_allocation = 0;
  99. u32 level_shift = 0; /* 0dB */
  100. bool down_mix = 0;
  101. u32 num_channels = params_channels(params);
  102. int rv = 0;
  103. struct msm_hdmi_audio_codec_rx_data *codec_data =
  104. dev_get_drvdata(dai->codec->dev);
  105. rv = codec_data->hdmi_ops.hdmi_cable_status(
  106. codec_data->hdmi_core_pdev, 1);
  107. if (IS_ERR_VALUE(rv)) {
  108. dev_err(dai->dev,
  109. "%s() HDMI core is not ready (rv = %d)\n",
  110. __func__, rv);
  111. return rv;
  112. } else if (!rv) {
  113. dev_err(dai->dev,
  114. "%s() HDMI cable is not connected (rv = %d)\n",
  115. __func__, rv);
  116. return -EAGAIN;
  117. }
  118. switch (num_channels) {
  119. case 2:
  120. channel_allocation = 0;
  121. break;
  122. case 3:
  123. channel_allocation = 0x02;//default to FL/FR/FC
  124. break;
  125. case 4:
  126. channel_allocation = 0x06;//default to FL/FR/FC/RC
  127. break;
  128. case 5:
  129. channel_allocation = 0x0A;//default to FL/FR/FC/RR/RL
  130. break;
  131. case 6:
  132. channel_allocation = 0x0B;
  133. break;
  134. case 7:
  135. channel_allocation = 0x12;//default to FL/FR/FC/RL/RR/RRC/RLC
  136. break;
  137. case 8:
  138. channel_allocation = 0x13;
  139. break;
  140. default:
  141. dev_err(dai->dev, "invalid Channels = %u\n", num_channels);
  142. return -EINVAL;
  143. }
  144. dev_dbg(dai->dev,
  145. "%s() num_ch %u samplerate %u channel_allocation = %u\n",
  146. __func__, num_channels, params_rate(params),
  147. channel_allocation);
  148. rv = codec_data->hdmi_ops.audio_info_setup(
  149. codec_data->hdmi_core_pdev,
  150. params_rate(params), num_channels,
  151. channel_allocation, level_shift, down_mix);
  152. if (IS_ERR_VALUE(rv)) {
  153. dev_err(dai->dev,
  154. "%s() HDMI core is not ready\n", __func__);
  155. }
  156. return rv;
  157. }
  158. static void msm_hdmi_audio_codec_rx_dai_shutdown(
  159. struct snd_pcm_substream *substream,
  160. struct snd_soc_dai *dai)
  161. {
  162. int rc;
  163. struct msm_hdmi_audio_codec_rx_data *codec_data =
  164. dev_get_drvdata(dai->codec->dev);
  165. rc = codec_data->hdmi_ops.hdmi_cable_status(
  166. codec_data->hdmi_core_pdev, 0);
  167. if (IS_ERR_VALUE(rc)) {
  168. dev_err(dai->dev,
  169. "%s() HDMI core had problems releasing HDMI audio flag\n",
  170. __func__);
  171. }
  172. return;
  173. }
  174. static struct snd_soc_dai_ops msm_hdmi_audio_codec_rx_dai_ops = {
  175. .startup = msm_hdmi_audio_codec_rx_dai_startup,
  176. .hw_params = msm_hdmi_audio_codec_rx_dai_hw_params,
  177. .shutdown = msm_hdmi_audio_codec_rx_dai_shutdown
  178. };
  179. static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec)
  180. {
  181. struct msm_hdmi_audio_codec_rx_data *codec_data;
  182. struct device_node *of_node_parent = NULL;
  183. codec_data = kzalloc(sizeof(struct msm_hdmi_audio_codec_rx_data),
  184. GFP_KERNEL);
  185. if (!codec_data) {
  186. dev_err(codec->dev, "%s(): fail to allocate dai data\n",
  187. __func__);
  188. return -ENOMEM;
  189. }
  190. of_node_parent = of_get_parent(codec->dev->of_node);
  191. if (!of_node_parent) {
  192. dev_err(codec->dev, "%s(): Parent device tree node not found\n",
  193. __func__);
  194. kfree(codec_data);
  195. return -ENODEV;
  196. }
  197. codec_data->hdmi_core_pdev = of_find_device_by_node(of_node_parent);
  198. if (!codec_data->hdmi_core_pdev) {
  199. dev_err(codec->dev, "%s(): can't get parent pdev\n", __func__);
  200. kfree(codec_data);
  201. return -ENODEV;
  202. }
  203. if (msm_hdmi_register_audio_codec(codec_data->hdmi_core_pdev,
  204. &codec_data->hdmi_ops)) {
  205. dev_err(codec->dev, "%s(): can't register with hdmi core",
  206. __func__);
  207. kfree(codec_data);
  208. return -ENODEV;
  209. }
  210. dev_set_drvdata(codec->dev, codec_data);
  211. dev_dbg(codec->dev, "%s(): registerd %s with HDMI core\n",
  212. __func__, codec->name);
  213. return 0;
  214. }
  215. static int msm_hdmi_audio_codec_rx_remove(struct snd_soc_codec *codec)
  216. {
  217. struct msm_hdmi_audio_codec_rx_data *codec_data;
  218. codec_data = dev_get_drvdata(codec->dev);
  219. kfree(codec_data);
  220. return 0;
  221. }
  222. static struct snd_soc_dai_driver msm_hdmi_audio_codec_rx_dais[] = {
  223. {
  224. .name = "msm_hdmi_audio_codec_rx_dai",
  225. .playback = {
  226. .stream_name = "HDMI Playback",
  227. .channels_min = 1,
  228. .channels_max = 8,
  229. .rate_min = 48000,
  230. .rate_max = 48000,
  231. .rates = MSM_HDMI_PCM_RATES,
  232. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  233. },
  234. .ops = &msm_hdmi_audio_codec_rx_dai_ops,
  235. },
  236. };
  237. static struct snd_soc_codec_driver msm_hdmi_audio_codec_rx_soc_driver = {
  238. .probe = msm_hdmi_audio_codec_rx_probe,
  239. .remove = msm_hdmi_audio_codec_rx_remove,
  240. .controls = msm_hdmi_codec_rx_controls,
  241. .num_controls = ARRAY_SIZE(msm_hdmi_codec_rx_controls),
  242. };
  243. static int __devinit msm_hdmi_audio_codec_rx_plat_probe(
  244. struct platform_device *pdev)
  245. {
  246. dev_dbg(&pdev->dev, "%s(): orginal dev name = %s, id = %d\n",
  247. __func__, dev_name(&pdev->dev), pdev->id);
  248. if (pdev->dev.of_node) {
  249. dev_dbg(&pdev->dev, "%s(): node full name = %s, name = %s\n",
  250. __func__, pdev->dev.of_node->full_name,
  251. pdev->dev.of_node->name);
  252. dev_set_name(&pdev->dev, "%s", "msm-hdmi-audio-codec-rx");
  253. } else
  254. dev_err(&pdev->dev, "%s(): platfrom data not from device tree\n",
  255. __func__);
  256. dev_dbg(&pdev->dev, "%s(): new dev name %s\n", __func__,
  257. dev_name(&pdev->dev));
  258. return snd_soc_register_codec(&pdev->dev,
  259. &msm_hdmi_audio_codec_rx_soc_driver,
  260. msm_hdmi_audio_codec_rx_dais,
  261. ARRAY_SIZE(msm_hdmi_audio_codec_rx_dais));
  262. }
  263. static int __devexit msm_hdmi_audio_codec_rx_plat_remove(
  264. struct platform_device *pdev)
  265. {
  266. snd_soc_unregister_codec(&pdev->dev);
  267. return 0;
  268. }
  269. static const struct of_device_id msm_hdmi_audio_codec_rx_dt_match[] = {
  270. { .compatible = "qcom,msm-hdmi-audio-codec-rx", },
  271. {}
  272. };
  273. MODULE_DEVICE_TABLE(of, msm_hdmi_codec_dt_match);
  274. static struct platform_driver msm_hdmi_audio_codec_rx_driver = {
  275. .driver = {
  276. .name = "msm-hdmi-audio-codec-rx",
  277. .owner = THIS_MODULE,
  278. .of_match_table = msm_hdmi_audio_codec_rx_dt_match,
  279. },
  280. .probe = msm_hdmi_audio_codec_rx_plat_probe,
  281. .remove = __devexit_p(msm_hdmi_audio_codec_rx_plat_remove),
  282. };
  283. static int __init msm_hdmi_audio_codec_rx_init(void)
  284. {
  285. return platform_driver_register(&msm_hdmi_audio_codec_rx_driver);
  286. }
  287. module_init(msm_hdmi_audio_codec_rx_init);
  288. static void __exit msm_hdmi_audio_codec_rx_exit(void)
  289. {
  290. platform_driver_unregister(&msm_hdmi_audio_codec_rx_driver);
  291. }
  292. module_exit(msm_hdmi_audio_codec_rx_exit);
  293. MODULE_DESCRIPTION("MSM HDMI CODEC driver");
  294. MODULE_VERSION("1.0");
  295. MODULE_LICENSE("GPL v2");