hdmi.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright (C) 2013 Red Hat
  3. * Author: Rob Clark <robdclark@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 as published by
  7. * the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "hdmi.h"
  18. static struct platform_device *hdmi_pdev;
  19. void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
  20. {
  21. uint32_t ctrl = 0;
  22. if (power_on) {
  23. ctrl |= HDMI_CTRL_ENABLE;
  24. if (!hdmi->hdmi_mode) {
  25. ctrl |= HDMI_CTRL_HDMI;
  26. hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
  27. ctrl &= ~HDMI_CTRL_HDMI;
  28. } else {
  29. ctrl |= HDMI_CTRL_HDMI;
  30. }
  31. } else {
  32. ctrl = HDMI_CTRL_HDMI;
  33. }
  34. hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
  35. DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
  36. power_on ? "Enable" : "Disable", ctrl);
  37. }
  38. static irqreturn_t hdmi_irq(int irq, void *dev_id)
  39. {
  40. struct hdmi *hdmi = dev_id;
  41. /* Process HPD: */
  42. hdmi_connector_irq(hdmi->connector);
  43. /* Process DDC: */
  44. hdmi_i2c_irq(hdmi->i2c);
  45. /* TODO audio.. */
  46. return IRQ_HANDLED;
  47. }
  48. void hdmi_destroy(struct kref *kref)
  49. {
  50. struct hdmi *hdmi = container_of(kref, struct hdmi, refcount);
  51. struct hdmi_phy *phy = hdmi->phy;
  52. if (phy)
  53. phy->funcs->destroy(phy);
  54. if (hdmi->i2c)
  55. hdmi_i2c_destroy(hdmi->i2c);
  56. put_device(&hdmi->pdev->dev);
  57. }
  58. /* initialize connector */
  59. int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
  60. {
  61. struct hdmi *hdmi = NULL;
  62. struct msm_drm_private *priv = dev->dev_private;
  63. struct platform_device *pdev = hdmi_pdev;
  64. struct hdmi_platform_config *config;
  65. int ret;
  66. if (!pdev) {
  67. dev_err(dev->dev, "no hdmi device\n");
  68. ret = -ENXIO;
  69. goto fail;
  70. }
  71. config = pdev->dev.platform_data;
  72. hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
  73. if (!hdmi) {
  74. ret = -ENOMEM;
  75. goto fail;
  76. }
  77. kref_init(&hdmi->refcount);
  78. get_device(&pdev->dev);
  79. hdmi->dev = dev;
  80. hdmi->pdev = pdev;
  81. hdmi->encoder = encoder;
  82. /* not sure about which phy maps to which msm.. probably I miss some */
  83. if (config->phy_init)
  84. hdmi->phy = config->phy_init(hdmi);
  85. else
  86. hdmi->phy = ERR_PTR(-ENXIO);
  87. if (IS_ERR(hdmi->phy)) {
  88. ret = PTR_ERR(hdmi->phy);
  89. dev_err(dev->dev, "failed to load phy: %d\n", ret);
  90. hdmi->phy = NULL;
  91. goto fail;
  92. }
  93. hdmi->mmio = msm_ioremap(pdev, "hdmi_msm_hdmi_addr", "HDMI");
  94. if (IS_ERR(hdmi->mmio)) {
  95. ret = PTR_ERR(hdmi->mmio);
  96. goto fail;
  97. }
  98. hdmi->mvs = devm_regulator_get(&pdev->dev, "8901_hdmi_mvs");
  99. if (IS_ERR(hdmi->mvs))
  100. hdmi->mvs = devm_regulator_get(&pdev->dev, "hdmi_mvs");
  101. if (IS_ERR(hdmi->mvs)) {
  102. ret = PTR_ERR(hdmi->mvs);
  103. dev_err(dev->dev, "failed to get mvs regulator: %d\n", ret);
  104. goto fail;
  105. }
  106. hdmi->mpp0 = devm_regulator_get(&pdev->dev, "8901_mpp0");
  107. if (IS_ERR(hdmi->mpp0))
  108. hdmi->mpp0 = NULL;
  109. hdmi->clk = devm_clk_get(&pdev->dev, "core_clk");
  110. if (IS_ERR(hdmi->clk)) {
  111. ret = PTR_ERR(hdmi->clk);
  112. dev_err(dev->dev, "failed to get 'clk': %d\n", ret);
  113. goto fail;
  114. }
  115. hdmi->m_pclk = devm_clk_get(&pdev->dev, "master_iface_clk");
  116. if (IS_ERR(hdmi->m_pclk)) {
  117. ret = PTR_ERR(hdmi->m_pclk);
  118. dev_err(dev->dev, "failed to get 'm_pclk': %d\n", ret);
  119. goto fail;
  120. }
  121. hdmi->s_pclk = devm_clk_get(&pdev->dev, "slave_iface_clk");
  122. if (IS_ERR(hdmi->s_pclk)) {
  123. ret = PTR_ERR(hdmi->s_pclk);
  124. dev_err(dev->dev, "failed to get 's_pclk': %d\n", ret);
  125. goto fail;
  126. }
  127. hdmi->i2c = hdmi_i2c_init(hdmi);
  128. if (IS_ERR(hdmi->i2c)) {
  129. ret = PTR_ERR(hdmi->i2c);
  130. dev_err(dev->dev, "failed to get i2c: %d\n", ret);
  131. hdmi->i2c = NULL;
  132. goto fail;
  133. }
  134. hdmi->bridge = hdmi_bridge_init(hdmi);
  135. if (IS_ERR(hdmi->bridge)) {
  136. ret = PTR_ERR(hdmi->bridge);
  137. dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret);
  138. hdmi->bridge = NULL;
  139. goto fail;
  140. }
  141. hdmi->connector = hdmi_connector_init(hdmi);
  142. if (IS_ERR(hdmi->connector)) {
  143. ret = PTR_ERR(hdmi->connector);
  144. dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret);
  145. hdmi->connector = NULL;
  146. goto fail;
  147. }
  148. hdmi->irq = platform_get_irq(pdev, 0);
  149. if (hdmi->irq < 0) {
  150. ret = hdmi->irq;
  151. dev_err(dev->dev, "failed to get irq: %d\n", ret);
  152. goto fail;
  153. }
  154. ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq,
  155. NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
  156. "hdmi_isr", hdmi);
  157. if (ret < 0) {
  158. dev_err(dev->dev, "failed to request IRQ%u: %d\n",
  159. hdmi->irq, ret);
  160. goto fail;
  161. }
  162. encoder->bridge = hdmi->bridge;
  163. priv->bridges[priv->num_bridges++] = hdmi->bridge;
  164. priv->connectors[priv->num_connectors++] = hdmi->connector;
  165. return 0;
  166. fail:
  167. if (hdmi) {
  168. /* bridge/connector are normally destroyed by drm: */
  169. if (hdmi->bridge)
  170. hdmi->bridge->funcs->destroy(hdmi->bridge);
  171. if (hdmi->connector)
  172. hdmi->connector->funcs->destroy(hdmi->connector);
  173. hdmi_destroy(&hdmi->refcount);
  174. }
  175. return ret;
  176. }
  177. /*
  178. * The hdmi device:
  179. */
  180. static int hdmi_dev_probe(struct platform_device *pdev)
  181. {
  182. static struct hdmi_platform_config config = {};
  183. #ifdef CONFIG_OF
  184. /* TODO */
  185. #else
  186. if (cpu_is_apq8064()) {
  187. config.phy_init = hdmi_phy_8960_init;
  188. config.ddc_clk_gpio = 70;
  189. config.ddc_data_gpio = 71;
  190. config.hpd_gpio = 72;
  191. config.pmic_gpio = 13 + NR_GPIO_IRQS;
  192. } else if (cpu_is_msm8960()) {
  193. config.phy_init = hdmi_phy_8960_init;
  194. config.ddc_clk_gpio = 100;
  195. config.ddc_data_gpio = 101;
  196. config.hpd_gpio = 102;
  197. config.pmic_gpio = -1;
  198. } else if (cpu_is_msm8x60()) {
  199. config.phy_init = hdmi_phy_8x60_init;
  200. config.ddc_clk_gpio = 170;
  201. config.ddc_data_gpio = 171;
  202. config.hpd_gpio = 172;
  203. config.pmic_gpio = -1;
  204. }
  205. #endif
  206. pdev->dev.platform_data = &config;
  207. hdmi_pdev = pdev;
  208. return 0;
  209. }
  210. static int hdmi_dev_remove(struct platform_device *pdev)
  211. {
  212. hdmi_pdev = NULL;
  213. return 0;
  214. }
  215. static struct platform_driver hdmi_driver = {
  216. .probe = hdmi_dev_probe,
  217. .remove = hdmi_dev_remove,
  218. .driver.name = "hdmi_msm",
  219. };
  220. void __init hdmi_register(void)
  221. {
  222. platform_driver_register(&hdmi_driver);
  223. }
  224. void __exit hdmi_unregister(void)
  225. {
  226. platform_driver_unregister(&hdmi_driver);
  227. }