1c8afe684SRob Clark /* 2c8afe684SRob Clark * Copyright (C) 2013 Red Hat 3c8afe684SRob Clark * Author: Rob Clark <robdclark@gmail.com> 4c8afe684SRob Clark * 5c8afe684SRob Clark * This program is free software; you can redistribute it and/or modify it 6c8afe684SRob Clark * under the terms of the GNU General Public License version 2 as published by 7c8afe684SRob Clark * the Free Software Foundation. 8c8afe684SRob Clark * 9c8afe684SRob Clark * This program is distributed in the hope that it will be useful, but WITHOUT 10c8afe684SRob Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11c8afe684SRob Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12c8afe684SRob Clark * more details. 13c8afe684SRob Clark * 14c8afe684SRob Clark * You should have received a copy of the GNU General Public License along with 15c8afe684SRob Clark * this program. If not, see <http://www.gnu.org/licenses/>. 16c8afe684SRob Clark */ 17c8afe684SRob Clark 18c8afe684SRob Clark #include "hdmi.h" 19c8afe684SRob Clark 20c8afe684SRob Clark void hdmi_set_mode(struct hdmi *hdmi, bool power_on) 21c8afe684SRob Clark { 22c8afe684SRob Clark uint32_t ctrl = 0; 23c8afe684SRob Clark 24c8afe684SRob Clark if (power_on) { 25c8afe684SRob Clark ctrl |= HDMI_CTRL_ENABLE; 26c8afe684SRob Clark if (!hdmi->hdmi_mode) { 27c8afe684SRob Clark ctrl |= HDMI_CTRL_HDMI; 28c8afe684SRob Clark hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 29c8afe684SRob Clark ctrl &= ~HDMI_CTRL_HDMI; 30c8afe684SRob Clark } else { 31c8afe684SRob Clark ctrl |= HDMI_CTRL_HDMI; 32c8afe684SRob Clark } 33c8afe684SRob Clark } else { 34c8afe684SRob Clark ctrl = HDMI_CTRL_HDMI; 35c8afe684SRob Clark } 36c8afe684SRob Clark 37c8afe684SRob Clark hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 38c8afe684SRob Clark DBG("HDMI Core: %s, HDMI_CTRL=0x%08x", 39c8afe684SRob Clark power_on ? "Enable" : "Disable", ctrl); 40c8afe684SRob Clark } 41c8afe684SRob Clark 42dada25bdSRob Clark irqreturn_t hdmi_irq(int irq, void *dev_id) 43c8afe684SRob Clark { 44c8afe684SRob Clark struct hdmi *hdmi = dev_id; 45c8afe684SRob Clark 46c8afe684SRob Clark /* Process HPD: */ 47c8afe684SRob Clark hdmi_connector_irq(hdmi->connector); 48c8afe684SRob Clark 49c8afe684SRob Clark /* Process DDC: */ 50c8afe684SRob Clark hdmi_i2c_irq(hdmi->i2c); 51c8afe684SRob Clark 52c8afe684SRob Clark /* TODO audio.. */ 53c8afe684SRob Clark 54c8afe684SRob Clark return IRQ_HANDLED; 55c8afe684SRob Clark } 56c8afe684SRob Clark 57a3376e3eSRob Clark void hdmi_destroy(struct kref *kref) 58c8afe684SRob Clark { 59a3376e3eSRob Clark struct hdmi *hdmi = container_of(kref, struct hdmi, refcount); 60c8afe684SRob Clark struct hdmi_phy *phy = hdmi->phy; 61c8afe684SRob Clark 62c8afe684SRob Clark if (phy) 63c8afe684SRob Clark phy->funcs->destroy(phy); 64c8afe684SRob Clark 65c8afe684SRob Clark if (hdmi->i2c) 66c8afe684SRob Clark hdmi_i2c_destroy(hdmi->i2c); 67c8afe684SRob Clark 68c0c0d9eeSRob Clark platform_set_drvdata(hdmi->pdev, NULL); 69c8afe684SRob Clark } 70c8afe684SRob Clark 71c8afe684SRob Clark /* initialize connector */ 72dada25bdSRob Clark struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) 73c8afe684SRob Clark { 74a3376e3eSRob Clark struct hdmi *hdmi = NULL; 75a3376e3eSRob Clark struct msm_drm_private *priv = dev->dev_private; 76060530f1SRob Clark struct platform_device *pdev = priv->hdmi_pdev; 77c8afe684SRob Clark struct hdmi_platform_config *config; 78dada25bdSRob Clark int i, ret; 79c8afe684SRob Clark 80c8afe684SRob Clark if (!pdev) { 81c8afe684SRob Clark dev_err(dev->dev, "no hdmi device\n"); 82c8afe684SRob Clark ret = -ENXIO; 83c8afe684SRob Clark goto fail; 84c8afe684SRob Clark } 85c8afe684SRob Clark 86c8afe684SRob Clark config = pdev->dev.platform_data; 87c8afe684SRob Clark 88a3376e3eSRob Clark hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); 89a3376e3eSRob Clark if (!hdmi) { 90a3376e3eSRob Clark ret = -ENOMEM; 91a3376e3eSRob Clark goto fail; 92a3376e3eSRob Clark } 93a3376e3eSRob Clark 94a3376e3eSRob Clark kref_init(&hdmi->refcount); 95a3376e3eSRob Clark 96c8afe684SRob Clark hdmi->dev = dev; 97c8afe684SRob Clark hdmi->pdev = pdev; 98dada25bdSRob Clark hdmi->config = config; 99a3376e3eSRob Clark hdmi->encoder = encoder; 100c8afe684SRob Clark 101c0c0d9eeSRob Clark hdmi_audio_infoframe_init(&hdmi->audio.infoframe); 102c0c0d9eeSRob Clark 103c8afe684SRob Clark /* not sure about which phy maps to which msm.. probably I miss some */ 104c8afe684SRob Clark if (config->phy_init) 105c8afe684SRob Clark hdmi->phy = config->phy_init(hdmi); 106c8afe684SRob Clark else 107c8afe684SRob Clark hdmi->phy = ERR_PTR(-ENXIO); 108c8afe684SRob Clark 109c8afe684SRob Clark if (IS_ERR(hdmi->phy)) { 110c8afe684SRob Clark ret = PTR_ERR(hdmi->phy); 111c8afe684SRob Clark dev_err(dev->dev, "failed to load phy: %d\n", ret); 112c8afe684SRob Clark hdmi->phy = NULL; 113c8afe684SRob Clark goto fail; 114c8afe684SRob Clark } 115c8afe684SRob Clark 116dada25bdSRob Clark hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); 117c8afe684SRob Clark if (IS_ERR(hdmi->mmio)) { 118c8afe684SRob Clark ret = PTR_ERR(hdmi->mmio); 119c8afe684SRob Clark goto fail; 120c8afe684SRob Clark } 121c8afe684SRob Clark 122dada25bdSRob Clark BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs)); 123dada25bdSRob Clark for (i = 0; i < config->hpd_reg_cnt; i++) { 124dada25bdSRob Clark struct regulator *reg; 125dada25bdSRob Clark 1263e87599bSRob Clark reg = devm_regulator_get(&pdev->dev, 12741e69778SRob Clark config->hpd_reg_names[i]); 128dada25bdSRob Clark if (IS_ERR(reg)) { 129dada25bdSRob Clark ret = PTR_ERR(reg); 130dada25bdSRob Clark dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n", 131dada25bdSRob Clark config->hpd_reg_names[i], ret); 132c8afe684SRob Clark goto fail; 133c8afe684SRob Clark } 134c8afe684SRob Clark 135dada25bdSRob Clark hdmi->hpd_regs[i] = reg; 136dada25bdSRob Clark } 137c8afe684SRob Clark 138dada25bdSRob Clark BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs)); 139dada25bdSRob Clark for (i = 0; i < config->pwr_reg_cnt; i++) { 140dada25bdSRob Clark struct regulator *reg; 141dada25bdSRob Clark 1423e87599bSRob Clark reg = devm_regulator_get(&pdev->dev, 14341e69778SRob Clark config->pwr_reg_names[i]); 144dada25bdSRob Clark if (IS_ERR(reg)) { 145dada25bdSRob Clark ret = PTR_ERR(reg); 146dada25bdSRob Clark dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n", 147dada25bdSRob Clark config->pwr_reg_names[i], ret); 148c8afe684SRob Clark goto fail; 149c8afe684SRob Clark } 150c8afe684SRob Clark 151dada25bdSRob Clark hdmi->pwr_regs[i] = reg; 152dada25bdSRob Clark } 153dada25bdSRob Clark 154dada25bdSRob Clark BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks)); 155dada25bdSRob Clark for (i = 0; i < config->hpd_clk_cnt; i++) { 156dada25bdSRob Clark struct clk *clk; 157dada25bdSRob Clark 158dada25bdSRob Clark clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]); 159dada25bdSRob Clark if (IS_ERR(clk)) { 160dada25bdSRob Clark ret = PTR_ERR(clk); 161dada25bdSRob Clark dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n", 162dada25bdSRob Clark config->hpd_clk_names[i], ret); 163c8afe684SRob Clark goto fail; 164c8afe684SRob Clark } 165c8afe684SRob Clark 166dada25bdSRob Clark hdmi->hpd_clks[i] = clk; 167dada25bdSRob Clark } 168dada25bdSRob Clark 169dada25bdSRob Clark BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks)); 170dada25bdSRob Clark for (i = 0; i < config->pwr_clk_cnt; i++) { 171dada25bdSRob Clark struct clk *clk; 172dada25bdSRob Clark 173dada25bdSRob Clark clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]); 174dada25bdSRob Clark if (IS_ERR(clk)) { 175dada25bdSRob Clark ret = PTR_ERR(clk); 176dada25bdSRob Clark dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n", 177dada25bdSRob Clark config->pwr_clk_names[i], ret); 178c8afe684SRob Clark goto fail; 179c8afe684SRob Clark } 180c8afe684SRob Clark 181dada25bdSRob Clark hdmi->pwr_clks[i] = clk; 182dada25bdSRob Clark } 183dada25bdSRob Clark 184c8afe684SRob Clark hdmi->i2c = hdmi_i2c_init(hdmi); 185c8afe684SRob Clark if (IS_ERR(hdmi->i2c)) { 186c8afe684SRob Clark ret = PTR_ERR(hdmi->i2c); 187c8afe684SRob Clark dev_err(dev->dev, "failed to get i2c: %d\n", ret); 188c8afe684SRob Clark hdmi->i2c = NULL; 189c8afe684SRob Clark goto fail; 190c8afe684SRob Clark } 191c8afe684SRob Clark 192a3376e3eSRob Clark hdmi->bridge = hdmi_bridge_init(hdmi); 193a3376e3eSRob Clark if (IS_ERR(hdmi->bridge)) { 194a3376e3eSRob Clark ret = PTR_ERR(hdmi->bridge); 195a3376e3eSRob Clark dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); 196a3376e3eSRob Clark hdmi->bridge = NULL; 197a3376e3eSRob Clark goto fail; 198a3376e3eSRob Clark } 199a3376e3eSRob Clark 200a3376e3eSRob Clark hdmi->connector = hdmi_connector_init(hdmi); 201a3376e3eSRob Clark if (IS_ERR(hdmi->connector)) { 202a3376e3eSRob Clark ret = PTR_ERR(hdmi->connector); 203a3376e3eSRob Clark dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); 204a3376e3eSRob Clark hdmi->connector = NULL; 205a3376e3eSRob Clark goto fail; 206a3376e3eSRob Clark } 207a3376e3eSRob Clark 208dada25bdSRob Clark if (!config->shared_irq) { 209c8afe684SRob Clark hdmi->irq = platform_get_irq(pdev, 0); 210c8afe684SRob Clark if (hdmi->irq < 0) { 211c8afe684SRob Clark ret = hdmi->irq; 212c8afe684SRob Clark dev_err(dev->dev, "failed to get irq: %d\n", ret); 213c8afe684SRob Clark goto fail; 214c8afe684SRob Clark } 215c8afe684SRob Clark 216c8afe684SRob Clark ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, 217c8afe684SRob Clark NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 218c8afe684SRob Clark "hdmi_isr", hdmi); 219c8afe684SRob Clark if (ret < 0) { 220c8afe684SRob Clark dev_err(dev->dev, "failed to request IRQ%u: %d\n", 221c8afe684SRob Clark hdmi->irq, ret); 222c8afe684SRob Clark goto fail; 223c8afe684SRob Clark } 224dada25bdSRob Clark } 225c8afe684SRob Clark 226a3376e3eSRob Clark encoder->bridge = hdmi->bridge; 227a3376e3eSRob Clark 228a3376e3eSRob Clark priv->bridges[priv->num_bridges++] = hdmi->bridge; 229a3376e3eSRob Clark priv->connectors[priv->num_connectors++] = hdmi->connector; 230a3376e3eSRob Clark 231c0c0d9eeSRob Clark platform_set_drvdata(pdev, hdmi); 232c0c0d9eeSRob Clark 233dada25bdSRob Clark return hdmi; 234c8afe684SRob Clark 235c8afe684SRob Clark fail: 236a3376e3eSRob Clark if (hdmi) { 237a3376e3eSRob Clark /* bridge/connector are normally destroyed by drm: */ 238a3376e3eSRob Clark if (hdmi->bridge) 239a3376e3eSRob Clark hdmi->bridge->funcs->destroy(hdmi->bridge); 240a3376e3eSRob Clark if (hdmi->connector) 241a3376e3eSRob Clark hdmi->connector->funcs->destroy(hdmi->connector); 242a3376e3eSRob Clark hdmi_destroy(&hdmi->refcount); 243a3376e3eSRob Clark } 244c8afe684SRob Clark 245dada25bdSRob Clark return ERR_PTR(ret); 246c8afe684SRob Clark } 247c8afe684SRob Clark 248c8afe684SRob Clark /* 249c8afe684SRob Clark * The hdmi device: 250c8afe684SRob Clark */ 251c8afe684SRob Clark 252dada25bdSRob Clark #include <linux/of_gpio.h> 253dada25bdSRob Clark 254060530f1SRob Clark static void set_hdmi_pdev(struct drm_device *dev, 255060530f1SRob Clark struct platform_device *pdev) 256060530f1SRob Clark { 257060530f1SRob Clark struct msm_drm_private *priv = dev->dev_private; 258060530f1SRob Clark priv->hdmi_pdev = pdev; 259060530f1SRob Clark } 260060530f1SRob Clark 261060530f1SRob Clark static int hdmi_bind(struct device *dev, struct device *master, void *data) 262c8afe684SRob Clark { 263c8afe684SRob Clark static struct hdmi_platform_config config = {}; 264c8afe684SRob Clark #ifdef CONFIG_OF 265060530f1SRob Clark struct device_node *of_node = dev->of_node; 266dada25bdSRob Clark 267dada25bdSRob Clark int get_gpio(const char *name) 268dada25bdSRob Clark { 269dada25bdSRob Clark int gpio = of_get_named_gpio(of_node, name, 0); 270dada25bdSRob Clark if (gpio < 0) { 27141e69778SRob Clark char name2[32]; 27241e69778SRob Clark snprintf(name2, sizeof(name2), "%s-gpio", name); 27341e69778SRob Clark gpio = of_get_named_gpio(of_node, name2, 0); 27441e69778SRob Clark if (gpio < 0) { 275060530f1SRob Clark dev_err(dev, "failed to get gpio: %s (%d)\n", 276dada25bdSRob Clark name, gpio); 277dada25bdSRob Clark gpio = -1; 278dada25bdSRob Clark } 27941e69778SRob Clark } 280dada25bdSRob Clark return gpio; 281dada25bdSRob Clark } 282dada25bdSRob Clark 28341e69778SRob Clark if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) { 284dada25bdSRob Clark static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"}; 285dada25bdSRob Clark static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"}; 286dada25bdSRob Clark static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"}; 287b77f47e7SStephane Viau static unsigned long hpd_clk_freq[] = {0, 19200000, 0}; 288dada25bdSRob Clark static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"}; 289dada25bdSRob Clark config.phy_init = hdmi_phy_8x74_init; 290dada25bdSRob Clark config.hpd_reg_names = hpd_reg_names; 291dada25bdSRob Clark config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 292dada25bdSRob Clark config.pwr_reg_names = pwr_reg_names; 293dada25bdSRob Clark config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names); 294dada25bdSRob Clark config.hpd_clk_names = hpd_clk_names; 295b77f47e7SStephane Viau config.hpd_freq = hpd_clk_freq; 296dada25bdSRob Clark config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 297dada25bdSRob Clark config.pwr_clk_names = pwr_clk_names; 298dada25bdSRob Clark config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names); 29941e69778SRob Clark config.shared_irq = true; 30041e69778SRob Clark } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) { 30141e69778SRob Clark static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"}; 30241e69778SRob Clark static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"}; 30341e69778SRob Clark config.phy_init = hdmi_phy_8960_init; 30441e69778SRob Clark config.hpd_reg_names = hpd_reg_names; 30541e69778SRob Clark config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 30641e69778SRob Clark config.hpd_clk_names = hpd_clk_names; 30741e69778SRob Clark config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 30841e69778SRob Clark } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8660")) { 30941e69778SRob Clark config.phy_init = hdmi_phy_8x60_init; 31041e69778SRob Clark } else { 31141e69778SRob Clark dev_err(dev, "unknown phy: %s\n", of_node->name); 31241e69778SRob Clark } 31341e69778SRob Clark 31441e69778SRob Clark config.mmio_name = "core_physical"; 315dada25bdSRob Clark config.ddc_clk_gpio = get_gpio("qcom,hdmi-tx-ddc-clk"); 316dada25bdSRob Clark config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data"); 317dada25bdSRob Clark config.hpd_gpio = get_gpio("qcom,hdmi-tx-hpd"); 318dada25bdSRob Clark config.mux_en_gpio = get_gpio("qcom,hdmi-tx-mux-en"); 319dada25bdSRob Clark config.mux_sel_gpio = get_gpio("qcom,hdmi-tx-mux-sel"); 3201930f38aSBeeresh Gopal config.mux_lpm_gpio = get_gpio("qcom,hdmi-tx-mux-lpm"); 321dada25bdSRob Clark 322c8afe684SRob Clark #else 323dada25bdSRob Clark static const char *hpd_clk_names[] = { 324dada25bdSRob Clark "core_clk", "master_iface_clk", "slave_iface_clk", 325dada25bdSRob Clark }; 326c8afe684SRob Clark if (cpu_is_apq8064()) { 327dada25bdSRob Clark static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; 328c8afe684SRob Clark config.phy_init = hdmi_phy_8960_init; 329dada25bdSRob Clark config.mmio_name = "hdmi_msm_hdmi_addr"; 330dada25bdSRob Clark config.hpd_reg_names = hpd_reg_names; 331dada25bdSRob Clark config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 332dada25bdSRob Clark config.hpd_clk_names = hpd_clk_names; 333dada25bdSRob Clark config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 334c8afe684SRob Clark config.ddc_clk_gpio = 70; 335c8afe684SRob Clark config.ddc_data_gpio = 71; 336c8afe684SRob Clark config.hpd_gpio = 72; 337dada25bdSRob Clark config.mux_en_gpio = -1; 338c0c0d9eeSRob Clark config.mux_sel_gpio = -1; 339e529c7e6SRob Clark } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { 340dada25bdSRob Clark static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; 341c8afe684SRob Clark config.phy_init = hdmi_phy_8960_init; 342dada25bdSRob Clark config.mmio_name = "hdmi_msm_hdmi_addr"; 343dada25bdSRob Clark config.hpd_reg_names = hpd_reg_names; 344dada25bdSRob Clark config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 345dada25bdSRob Clark config.hpd_clk_names = hpd_clk_names; 346dada25bdSRob Clark config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 347c8afe684SRob Clark config.ddc_clk_gpio = 100; 348c8afe684SRob Clark config.ddc_data_gpio = 101; 349c8afe684SRob Clark config.hpd_gpio = 102; 350dada25bdSRob Clark config.mux_en_gpio = -1; 351dada25bdSRob Clark config.mux_sel_gpio = -1; 352c8afe684SRob Clark } else if (cpu_is_msm8x60()) { 353dada25bdSRob Clark static const char *hpd_reg_names[] = { 354dada25bdSRob Clark "8901_hdmi_mvs", "8901_mpp0" 355dada25bdSRob Clark }; 356c8afe684SRob Clark config.phy_init = hdmi_phy_8x60_init; 357dada25bdSRob Clark config.mmio_name = "hdmi_msm_hdmi_addr"; 358dada25bdSRob Clark config.hpd_reg_names = hpd_reg_names; 359dada25bdSRob Clark config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 360dada25bdSRob Clark config.hpd_clk_names = hpd_clk_names; 361dada25bdSRob Clark config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 362c8afe684SRob Clark config.ddc_clk_gpio = 170; 363c8afe684SRob Clark config.ddc_data_gpio = 171; 364c8afe684SRob Clark config.hpd_gpio = 172; 365dada25bdSRob Clark config.mux_en_gpio = -1; 366dada25bdSRob Clark config.mux_sel_gpio = -1; 367c8afe684SRob Clark } 368c8afe684SRob Clark #endif 369060530f1SRob Clark dev->platform_data = &config; 370060530f1SRob Clark set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev)); 371c8afe684SRob Clark return 0; 372c8afe684SRob Clark } 373c8afe684SRob Clark 374060530f1SRob Clark static void hdmi_unbind(struct device *dev, struct device *master, 375060530f1SRob Clark void *data) 376060530f1SRob Clark { 377060530f1SRob Clark set_hdmi_pdev(dev_get_drvdata(master), NULL); 378060530f1SRob Clark } 379060530f1SRob Clark 380060530f1SRob Clark static const struct component_ops hdmi_ops = { 381060530f1SRob Clark .bind = hdmi_bind, 382060530f1SRob Clark .unbind = hdmi_unbind, 383060530f1SRob Clark }; 384060530f1SRob Clark 385060530f1SRob Clark static int hdmi_dev_probe(struct platform_device *pdev) 386060530f1SRob Clark { 387060530f1SRob Clark return component_add(&pdev->dev, &hdmi_ops); 388060530f1SRob Clark } 389060530f1SRob Clark 390c8afe684SRob Clark static int hdmi_dev_remove(struct platform_device *pdev) 391c8afe684SRob Clark { 392060530f1SRob Clark component_del(&pdev->dev, &hdmi_ops); 393c8afe684SRob Clark return 0; 394c8afe684SRob Clark } 395c8afe684SRob Clark 396dada25bdSRob Clark static const struct of_device_id dt_match[] = { 39741e69778SRob Clark { .compatible = "qcom,hdmi-tx-8074" }, 39841e69778SRob Clark { .compatible = "qcom,hdmi-tx-8960" }, 39941e69778SRob Clark { .compatible = "qcom,hdmi-tx-8660" }, 400dada25bdSRob Clark {} 401dada25bdSRob Clark }; 402dada25bdSRob Clark 403c8afe684SRob Clark static struct platform_driver hdmi_driver = { 404c8afe684SRob Clark .probe = hdmi_dev_probe, 405c8afe684SRob Clark .remove = hdmi_dev_remove, 406dada25bdSRob Clark .driver = { 407dada25bdSRob Clark .name = "hdmi_msm", 408dada25bdSRob Clark .of_match_table = dt_match, 409dada25bdSRob Clark }, 410c8afe684SRob Clark }; 411c8afe684SRob Clark 412c8afe684SRob Clark void __init hdmi_register(void) 413c8afe684SRob Clark { 414c8afe684SRob Clark platform_driver_register(&hdmi_driver); 415c8afe684SRob Clark } 416c8afe684SRob Clark 417c8afe684SRob Clark void __exit hdmi_unregister(void) 418c8afe684SRob Clark { 419c8afe684SRob Clark platform_driver_unregister(&hdmi_driver); 420c8afe684SRob Clark } 421