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 18 #include "hdmi.h" 19 20 static struct platform_device *hdmi_pdev; 21 22 void hdmi_set_mode(struct hdmi *hdmi, bool power_on) 23 { 24 uint32_t ctrl = 0; 25 26 if (power_on) { 27 ctrl |= HDMI_CTRL_ENABLE; 28 if (!hdmi->hdmi_mode) { 29 ctrl |= HDMI_CTRL_HDMI; 30 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 31 ctrl &= ~HDMI_CTRL_HDMI; 32 } else { 33 ctrl |= HDMI_CTRL_HDMI; 34 } 35 } else { 36 ctrl = HDMI_CTRL_HDMI; 37 } 38 39 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 40 DBG("HDMI Core: %s, HDMI_CTRL=0x%08x", 41 power_on ? "Enable" : "Disable", ctrl); 42 } 43 44 static irqreturn_t hdmi_irq(int irq, void *dev_id) 45 { 46 struct hdmi *hdmi = dev_id; 47 48 /* Process HPD: */ 49 hdmi_connector_irq(hdmi->connector); 50 51 /* Process DDC: */ 52 hdmi_i2c_irq(hdmi->i2c); 53 54 /* TODO audio.. */ 55 56 return IRQ_HANDLED; 57 } 58 59 void hdmi_destroy(struct kref *kref) 60 { 61 struct hdmi *hdmi = container_of(kref, struct hdmi, refcount); 62 struct hdmi_phy *phy = hdmi->phy; 63 64 if (phy) 65 phy->funcs->destroy(phy); 66 67 if (hdmi->i2c) 68 hdmi_i2c_destroy(hdmi->i2c); 69 70 put_device(&hdmi->pdev->dev); 71 } 72 73 /* initialize connector */ 74 int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) 75 { 76 struct hdmi *hdmi = NULL; 77 struct msm_drm_private *priv = dev->dev_private; 78 struct platform_device *pdev = hdmi_pdev; 79 struct hdmi_platform_config *config; 80 int ret; 81 82 if (!pdev) { 83 dev_err(dev->dev, "no hdmi device\n"); 84 ret = -ENXIO; 85 goto fail; 86 } 87 88 config = pdev->dev.platform_data; 89 90 hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); 91 if (!hdmi) { 92 ret = -ENOMEM; 93 goto fail; 94 } 95 96 kref_init(&hdmi->refcount); 97 98 get_device(&pdev->dev); 99 100 hdmi->dev = dev; 101 hdmi->pdev = pdev; 102 hdmi->encoder = encoder; 103 104 /* not sure about which phy maps to which msm.. probably I miss some */ 105 if (config->phy_init) 106 hdmi->phy = config->phy_init(hdmi); 107 else 108 hdmi->phy = ERR_PTR(-ENXIO); 109 110 if (IS_ERR(hdmi->phy)) { 111 ret = PTR_ERR(hdmi->phy); 112 dev_err(dev->dev, "failed to load phy: %d\n", ret); 113 hdmi->phy = NULL; 114 goto fail; 115 } 116 117 hdmi->mmio = msm_ioremap(pdev, "hdmi_msm_hdmi_addr", "HDMI"); 118 if (IS_ERR(hdmi->mmio)) { 119 ret = PTR_ERR(hdmi->mmio); 120 goto fail; 121 } 122 123 hdmi->mvs = devm_regulator_get(&pdev->dev, "8901_hdmi_mvs"); 124 if (IS_ERR(hdmi->mvs)) 125 hdmi->mvs = devm_regulator_get(&pdev->dev, "hdmi_mvs"); 126 if (IS_ERR(hdmi->mvs)) { 127 ret = PTR_ERR(hdmi->mvs); 128 dev_err(dev->dev, "failed to get mvs regulator: %d\n", ret); 129 goto fail; 130 } 131 132 hdmi->mpp0 = devm_regulator_get(&pdev->dev, "8901_mpp0"); 133 if (IS_ERR(hdmi->mpp0)) 134 hdmi->mpp0 = NULL; 135 136 hdmi->clk = devm_clk_get(&pdev->dev, "core_clk"); 137 if (IS_ERR(hdmi->clk)) { 138 ret = PTR_ERR(hdmi->clk); 139 dev_err(dev->dev, "failed to get 'clk': %d\n", ret); 140 goto fail; 141 } 142 143 hdmi->m_pclk = devm_clk_get(&pdev->dev, "master_iface_clk"); 144 if (IS_ERR(hdmi->m_pclk)) { 145 ret = PTR_ERR(hdmi->m_pclk); 146 dev_err(dev->dev, "failed to get 'm_pclk': %d\n", ret); 147 goto fail; 148 } 149 150 hdmi->s_pclk = devm_clk_get(&pdev->dev, "slave_iface_clk"); 151 if (IS_ERR(hdmi->s_pclk)) { 152 ret = PTR_ERR(hdmi->s_pclk); 153 dev_err(dev->dev, "failed to get 's_pclk': %d\n", ret); 154 goto fail; 155 } 156 157 hdmi->i2c = hdmi_i2c_init(hdmi); 158 if (IS_ERR(hdmi->i2c)) { 159 ret = PTR_ERR(hdmi->i2c); 160 dev_err(dev->dev, "failed to get i2c: %d\n", ret); 161 hdmi->i2c = NULL; 162 goto fail; 163 } 164 165 hdmi->bridge = hdmi_bridge_init(hdmi); 166 if (IS_ERR(hdmi->bridge)) { 167 ret = PTR_ERR(hdmi->bridge); 168 dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); 169 hdmi->bridge = NULL; 170 goto fail; 171 } 172 173 hdmi->connector = hdmi_connector_init(hdmi); 174 if (IS_ERR(hdmi->connector)) { 175 ret = PTR_ERR(hdmi->connector); 176 dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); 177 hdmi->connector = NULL; 178 goto fail; 179 } 180 181 hdmi->irq = platform_get_irq(pdev, 0); 182 if (hdmi->irq < 0) { 183 ret = hdmi->irq; 184 dev_err(dev->dev, "failed to get irq: %d\n", ret); 185 goto fail; 186 } 187 188 ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, 189 NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 190 "hdmi_isr", hdmi); 191 if (ret < 0) { 192 dev_err(dev->dev, "failed to request IRQ%u: %d\n", 193 hdmi->irq, ret); 194 goto fail; 195 } 196 197 encoder->bridge = hdmi->bridge; 198 199 priv->bridges[priv->num_bridges++] = hdmi->bridge; 200 priv->connectors[priv->num_connectors++] = hdmi->connector; 201 202 return 0; 203 204 fail: 205 if (hdmi) { 206 /* bridge/connector are normally destroyed by drm: */ 207 if (hdmi->bridge) 208 hdmi->bridge->funcs->destroy(hdmi->bridge); 209 if (hdmi->connector) 210 hdmi->connector->funcs->destroy(hdmi->connector); 211 hdmi_destroy(&hdmi->refcount); 212 } 213 214 return ret; 215 } 216 217 /* 218 * The hdmi device: 219 */ 220 221 static int hdmi_dev_probe(struct platform_device *pdev) 222 { 223 static struct hdmi_platform_config config = {}; 224 #ifdef CONFIG_OF 225 /* TODO */ 226 #else 227 if (cpu_is_apq8064()) { 228 config.phy_init = hdmi_phy_8960_init; 229 config.ddc_clk_gpio = 70; 230 config.ddc_data_gpio = 71; 231 config.hpd_gpio = 72; 232 config.pmic_gpio = 13 + NR_GPIO_IRQS; 233 } else if (cpu_is_msm8960()) { 234 config.phy_init = hdmi_phy_8960_init; 235 config.ddc_clk_gpio = 100; 236 config.ddc_data_gpio = 101; 237 config.hpd_gpio = 102; 238 config.pmic_gpio = -1; 239 } else if (cpu_is_msm8x60()) { 240 config.phy_init = hdmi_phy_8x60_init; 241 config.ddc_clk_gpio = 170; 242 config.ddc_data_gpio = 171; 243 config.hpd_gpio = 172; 244 config.pmic_gpio = -1; 245 } 246 #endif 247 pdev->dev.platform_data = &config; 248 hdmi_pdev = pdev; 249 return 0; 250 } 251 252 static int hdmi_dev_remove(struct platform_device *pdev) 253 { 254 hdmi_pdev = NULL; 255 return 0; 256 } 257 258 static struct platform_driver hdmi_driver = { 259 .probe = hdmi_dev_probe, 260 .remove = hdmi_dev_remove, 261 .driver.name = "hdmi_msm", 262 }; 263 264 void __init hdmi_register(void) 265 { 266 platform_driver_register(&hdmi_driver); 267 } 268 269 void __exit hdmi_unregister(void) 270 { 271 platform_driver_unregister(&hdmi_driver); 272 } 273