1c8afe684SRob Clark /* 25eba5d87SStephane Viau * Copyright (c) 2014 The Linux Foundation. All rights reserved. 3c8afe684SRob Clark * Copyright (C) 2013 Red Hat 4c8afe684SRob Clark * Author: Rob Clark <robdclark@gmail.com> 5c8afe684SRob Clark * 6c8afe684SRob Clark * This program is free software; you can redistribute it and/or modify it 7c8afe684SRob Clark * under the terms of the GNU General Public License version 2 as published by 8c8afe684SRob Clark * the Free Software Foundation. 9c8afe684SRob Clark * 10c8afe684SRob Clark * This program is distributed in the hope that it will be useful, but WITHOUT 11c8afe684SRob Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12c8afe684SRob Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13c8afe684SRob Clark * more details. 14c8afe684SRob Clark * 15c8afe684SRob Clark * You should have received a copy of the GNU General Public License along with 16c8afe684SRob Clark * this program. If not, see <http://www.gnu.org/licenses/>. 17c8afe684SRob Clark */ 18c8afe684SRob Clark 19f6a8eacaSRob Clark #include <linux/of_irq.h> 201fd6a441SArchit Taneja #include <linux/of_gpio.h> 211fd6a441SArchit Taneja 22c8afe684SRob Clark #include "hdmi.h" 23c8afe684SRob Clark 24c8afe684SRob Clark void hdmi_set_mode(struct hdmi *hdmi, bool power_on) 25c8afe684SRob Clark { 26c8afe684SRob Clark uint32_t ctrl = 0; 27c6a57a50Sjilai wang unsigned long flags; 28c8afe684SRob Clark 29c6a57a50Sjilai wang spin_lock_irqsave(&hdmi->reg_lock, flags); 30c8afe684SRob Clark if (power_on) { 31c8afe684SRob Clark ctrl |= HDMI_CTRL_ENABLE; 32c8afe684SRob Clark if (!hdmi->hdmi_mode) { 33c8afe684SRob Clark ctrl |= HDMI_CTRL_HDMI; 34c8afe684SRob Clark hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 35c8afe684SRob Clark ctrl &= ~HDMI_CTRL_HDMI; 36c8afe684SRob Clark } else { 37c8afe684SRob Clark ctrl |= HDMI_CTRL_HDMI; 38c8afe684SRob Clark } 39c8afe684SRob Clark } else { 40c8afe684SRob Clark ctrl = HDMI_CTRL_HDMI; 41c8afe684SRob Clark } 42c8afe684SRob Clark 43c8afe684SRob Clark hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 44c6a57a50Sjilai wang spin_unlock_irqrestore(&hdmi->reg_lock, flags); 45c8afe684SRob Clark DBG("HDMI Core: %s, HDMI_CTRL=0x%08x", 46c8afe684SRob Clark power_on ? "Enable" : "Disable", ctrl); 47c8afe684SRob Clark } 48c8afe684SRob Clark 49f6a8eacaSRob Clark static irqreturn_t hdmi_irq(int irq, void *dev_id) 50c8afe684SRob Clark { 51c8afe684SRob Clark struct hdmi *hdmi = dev_id; 52c8afe684SRob Clark 53c8afe684SRob Clark /* Process HPD: */ 54c8afe684SRob Clark hdmi_connector_irq(hdmi->connector); 55c8afe684SRob Clark 56c8afe684SRob Clark /* Process DDC: */ 57c8afe684SRob Clark hdmi_i2c_irq(hdmi->i2c); 58c8afe684SRob Clark 59c6a57a50Sjilai wang /* Process HDCP: */ 60c6a57a50Sjilai wang if (hdmi->hdcp_ctrl) 61c6a57a50Sjilai wang hdmi_hdcp_irq(hdmi->hdcp_ctrl); 62c6a57a50Sjilai wang 63c8afe684SRob Clark /* TODO audio.. */ 64c8afe684SRob Clark 65c8afe684SRob Clark return IRQ_HANDLED; 66c8afe684SRob Clark } 67c8afe684SRob Clark 68d1a717bdSRob Clark static void hdmi_destroy(struct hdmi *hdmi) 69c8afe684SRob Clark { 70c8afe684SRob Clark struct hdmi_phy *phy = hdmi->phy; 71c8afe684SRob Clark 72c6a57a50Sjilai wang /* 73c6a57a50Sjilai wang * at this point, hpd has been disabled, 74c6a57a50Sjilai wang * after flush workq, it's safe to deinit hdcp 75c6a57a50Sjilai wang */ 76c6a57a50Sjilai wang if (hdmi->workq) { 77c6a57a50Sjilai wang flush_workqueue(hdmi->workq); 78c6a57a50Sjilai wang destroy_workqueue(hdmi->workq); 79c6a57a50Sjilai wang } 80c6a57a50Sjilai wang hdmi_hdcp_destroy(hdmi); 81c8afe684SRob Clark if (phy) 82c8afe684SRob Clark phy->funcs->destroy(phy); 83c8afe684SRob Clark 84c8afe684SRob Clark if (hdmi->i2c) 85c8afe684SRob Clark hdmi_i2c_destroy(hdmi->i2c); 86c8afe684SRob Clark 87c0c0d9eeSRob Clark platform_set_drvdata(hdmi->pdev, NULL); 88c8afe684SRob Clark } 89c8afe684SRob Clark 90067fef37SRob Clark /* construct hdmi at bind/probe time, grab all the resources. If 91067fef37SRob Clark * we are to EPROBE_DEFER we want to do it here, rather than later 92067fef37SRob Clark * at modeset_init() time 93067fef37SRob Clark */ 94067fef37SRob Clark static struct hdmi *hdmi_init(struct platform_device *pdev) 95c8afe684SRob Clark { 96067fef37SRob Clark struct hdmi_platform_config *config = pdev->dev.platform_data; 97a3376e3eSRob Clark struct hdmi *hdmi = NULL; 98c6a57a50Sjilai wang struct resource *res; 99dada25bdSRob Clark int i, ret; 100c8afe684SRob Clark 101067fef37SRob Clark hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); 102a3376e3eSRob Clark if (!hdmi) { 103a3376e3eSRob Clark ret = -ENOMEM; 104a3376e3eSRob Clark goto fail; 105a3376e3eSRob Clark } 106a3376e3eSRob Clark 107c8afe684SRob Clark hdmi->pdev = pdev; 108dada25bdSRob Clark hdmi->config = config; 109c6a57a50Sjilai wang spin_lock_init(&hdmi->reg_lock); 110c0c0d9eeSRob Clark 111c8afe684SRob Clark /* not sure about which phy maps to which msm.. probably I miss some */ 1123a84f846SStephane Viau if (config->phy_init) { 113c8afe684SRob Clark hdmi->phy = config->phy_init(hdmi); 114c8afe684SRob Clark 115c8afe684SRob Clark if (IS_ERR(hdmi->phy)) { 116c8afe684SRob Clark ret = PTR_ERR(hdmi->phy); 117067fef37SRob Clark dev_err(&pdev->dev, "failed to load phy: %d\n", ret); 118c8afe684SRob Clark hdmi->phy = NULL; 119c8afe684SRob Clark goto fail; 120c8afe684SRob Clark } 1213a84f846SStephane Viau } 122c8afe684SRob Clark 123dada25bdSRob Clark hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); 124c8afe684SRob Clark if (IS_ERR(hdmi->mmio)) { 125c8afe684SRob Clark ret = PTR_ERR(hdmi->mmio); 126c8afe684SRob Clark goto fail; 127c8afe684SRob Clark } 128c8afe684SRob Clark 129c6a57a50Sjilai wang /* HDCP needs physical address of hdmi register */ 130c6a57a50Sjilai wang res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 131c6a57a50Sjilai wang config->mmio_name); 132c6a57a50Sjilai wang hdmi->mmio_phy_addr = res->start; 133c6a57a50Sjilai wang 134c6a57a50Sjilai wang hdmi->qfprom_mmio = msm_ioremap(pdev, 135c6a57a50Sjilai wang config->qfprom_mmio_name, "HDMI_QFPROM"); 136c6a57a50Sjilai wang if (IS_ERR(hdmi->qfprom_mmio)) { 137c6a57a50Sjilai wang dev_info(&pdev->dev, "can't find qfprom resource\n"); 138c6a57a50Sjilai wang hdmi->qfprom_mmio = NULL; 139c6a57a50Sjilai wang } 140c6a57a50Sjilai wang 141447fa529SStephane Viau hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) * 142447fa529SStephane Viau config->hpd_reg_cnt, GFP_KERNEL); 143447fa529SStephane Viau if (!hdmi->hpd_regs) { 144447fa529SStephane Viau ret = -ENOMEM; 145447fa529SStephane Viau goto fail; 146447fa529SStephane Viau } 147dada25bdSRob Clark for (i = 0; i < config->hpd_reg_cnt; i++) { 148dada25bdSRob Clark struct regulator *reg; 149dada25bdSRob Clark 1503e87599bSRob Clark reg = devm_regulator_get(&pdev->dev, 15141e69778SRob Clark config->hpd_reg_names[i]); 152dada25bdSRob Clark if (IS_ERR(reg)) { 153dada25bdSRob Clark ret = PTR_ERR(reg); 154067fef37SRob Clark dev_err(&pdev->dev, "failed to get hpd regulator: %s (%d)\n", 155dada25bdSRob Clark config->hpd_reg_names[i], ret); 156c8afe684SRob Clark goto fail; 157c8afe684SRob Clark } 158c8afe684SRob Clark 159dada25bdSRob Clark hdmi->hpd_regs[i] = reg; 160dada25bdSRob Clark } 161c8afe684SRob Clark 162447fa529SStephane Viau hdmi->pwr_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_regs[0]) * 163447fa529SStephane Viau config->pwr_reg_cnt, GFP_KERNEL); 164447fa529SStephane Viau if (!hdmi->pwr_regs) { 165447fa529SStephane Viau ret = -ENOMEM; 166447fa529SStephane Viau goto fail; 167447fa529SStephane Viau } 168dada25bdSRob Clark for (i = 0; i < config->pwr_reg_cnt; i++) { 169dada25bdSRob Clark struct regulator *reg; 170dada25bdSRob Clark 1713e87599bSRob Clark reg = devm_regulator_get(&pdev->dev, 17241e69778SRob Clark config->pwr_reg_names[i]); 173dada25bdSRob Clark if (IS_ERR(reg)) { 174dada25bdSRob Clark ret = PTR_ERR(reg); 175067fef37SRob Clark dev_err(&pdev->dev, "failed to get pwr regulator: %s (%d)\n", 176dada25bdSRob Clark config->pwr_reg_names[i], ret); 177c8afe684SRob Clark goto fail; 178c8afe684SRob Clark } 179c8afe684SRob Clark 180dada25bdSRob Clark hdmi->pwr_regs[i] = reg; 181dada25bdSRob Clark } 182dada25bdSRob Clark 183447fa529SStephane Viau hdmi->hpd_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_clks[0]) * 184447fa529SStephane Viau config->hpd_clk_cnt, GFP_KERNEL); 185447fa529SStephane Viau if (!hdmi->hpd_clks) { 186447fa529SStephane Viau ret = -ENOMEM; 187447fa529SStephane Viau goto fail; 188447fa529SStephane Viau } 189dada25bdSRob Clark for (i = 0; i < config->hpd_clk_cnt; i++) { 190dada25bdSRob Clark struct clk *clk; 191dada25bdSRob Clark 192dada25bdSRob Clark clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]); 193dada25bdSRob Clark if (IS_ERR(clk)) { 194dada25bdSRob Clark ret = PTR_ERR(clk); 195067fef37SRob Clark dev_err(&pdev->dev, "failed to get hpd clk: %s (%d)\n", 196dada25bdSRob Clark config->hpd_clk_names[i], ret); 197c8afe684SRob Clark goto fail; 198c8afe684SRob Clark } 199c8afe684SRob Clark 200dada25bdSRob Clark hdmi->hpd_clks[i] = clk; 201dada25bdSRob Clark } 202dada25bdSRob Clark 203447fa529SStephane Viau hdmi->pwr_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_clks[0]) * 204447fa529SStephane Viau config->pwr_clk_cnt, GFP_KERNEL); 205447fa529SStephane Viau if (!hdmi->pwr_clks) { 206447fa529SStephane Viau ret = -ENOMEM; 207447fa529SStephane Viau goto fail; 208447fa529SStephane Viau } 209dada25bdSRob Clark for (i = 0; i < config->pwr_clk_cnt; i++) { 210dada25bdSRob Clark struct clk *clk; 211dada25bdSRob Clark 212dada25bdSRob Clark clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]); 213dada25bdSRob Clark if (IS_ERR(clk)) { 214dada25bdSRob Clark ret = PTR_ERR(clk); 215067fef37SRob Clark dev_err(&pdev->dev, "failed to get pwr clk: %s (%d)\n", 216dada25bdSRob Clark config->pwr_clk_names[i], ret); 217c8afe684SRob Clark goto fail; 218c8afe684SRob Clark } 219c8afe684SRob Clark 220dada25bdSRob Clark hdmi->pwr_clks[i] = clk; 221dada25bdSRob Clark } 222dada25bdSRob Clark 223c6a57a50Sjilai wang hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0); 224c6a57a50Sjilai wang 225c8afe684SRob Clark hdmi->i2c = hdmi_i2c_init(hdmi); 226c8afe684SRob Clark if (IS_ERR(hdmi->i2c)) { 227c8afe684SRob Clark ret = PTR_ERR(hdmi->i2c); 228067fef37SRob Clark dev_err(&pdev->dev, "failed to get i2c: %d\n", ret); 229c8afe684SRob Clark hdmi->i2c = NULL; 230c8afe684SRob Clark goto fail; 231c8afe684SRob Clark } 232c8afe684SRob Clark 233c6a57a50Sjilai wang hdmi->hdcp_ctrl = hdmi_hdcp_init(hdmi); 234c6a57a50Sjilai wang if (IS_ERR(hdmi->hdcp_ctrl)) { 235c6a57a50Sjilai wang dev_warn(&pdev->dev, "failed to init hdcp: disabled\n"); 236c6a57a50Sjilai wang hdmi->hdcp_ctrl = NULL; 237c6a57a50Sjilai wang } 238c6a57a50Sjilai wang 239067fef37SRob Clark return hdmi; 240067fef37SRob Clark 241067fef37SRob Clark fail: 242067fef37SRob Clark if (hdmi) 243d1a717bdSRob Clark hdmi_destroy(hdmi); 244067fef37SRob Clark 245067fef37SRob Clark return ERR_PTR(ret); 246067fef37SRob Clark } 247067fef37SRob Clark 248067fef37SRob Clark /* Second part of initialization, the drm/kms level modeset_init, 249067fef37SRob Clark * constructs/initializes mode objects, etc, is called from master 250067fef37SRob Clark * driver (not hdmi sub-device's probe/bind!) 251067fef37SRob Clark * 252067fef37SRob Clark * Any resource (regulator/clk/etc) which could be missing at boot 253067fef37SRob Clark * should be handled in hdmi_init() so that failure happens from 254067fef37SRob Clark * hdmi sub-device's probe. 255067fef37SRob Clark */ 256067fef37SRob Clark int hdmi_modeset_init(struct hdmi *hdmi, 257067fef37SRob Clark struct drm_device *dev, struct drm_encoder *encoder) 258067fef37SRob Clark { 259067fef37SRob Clark struct msm_drm_private *priv = dev->dev_private; 260067fef37SRob Clark struct platform_device *pdev = hdmi->pdev; 261067fef37SRob Clark int ret; 262067fef37SRob Clark 263067fef37SRob Clark hdmi->dev = dev; 264067fef37SRob Clark hdmi->encoder = encoder; 265067fef37SRob Clark 266067fef37SRob Clark hdmi_audio_infoframe_init(&hdmi->audio.infoframe); 267067fef37SRob Clark 268a3376e3eSRob Clark hdmi->bridge = hdmi_bridge_init(hdmi); 269a3376e3eSRob Clark if (IS_ERR(hdmi->bridge)) { 270a3376e3eSRob Clark ret = PTR_ERR(hdmi->bridge); 271a3376e3eSRob Clark dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); 272a3376e3eSRob Clark hdmi->bridge = NULL; 273a3376e3eSRob Clark goto fail; 274a3376e3eSRob Clark } 275a3376e3eSRob Clark 276a3376e3eSRob Clark hdmi->connector = hdmi_connector_init(hdmi); 277a3376e3eSRob Clark if (IS_ERR(hdmi->connector)) { 278a3376e3eSRob Clark ret = PTR_ERR(hdmi->connector); 279a3376e3eSRob Clark dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); 280a3376e3eSRob Clark hdmi->connector = NULL; 281a3376e3eSRob Clark goto fail; 282a3376e3eSRob Clark } 283a3376e3eSRob Clark 284f6a8eacaSRob Clark hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 285c8afe684SRob Clark if (hdmi->irq < 0) { 286c8afe684SRob Clark ret = hdmi->irq; 287c8afe684SRob Clark dev_err(dev->dev, "failed to get irq: %d\n", ret); 288c8afe684SRob Clark goto fail; 289c8afe684SRob Clark } 290c8afe684SRob Clark 291f6a8eacaSRob Clark ret = devm_request_irq(&pdev->dev, hdmi->irq, 292f6a8eacaSRob Clark hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 293c8afe684SRob Clark "hdmi_isr", hdmi); 294c8afe684SRob Clark if (ret < 0) { 295c8afe684SRob Clark dev_err(dev->dev, "failed to request IRQ%u: %d\n", 296c8afe684SRob Clark hdmi->irq, ret); 297c8afe684SRob Clark goto fail; 298c8afe684SRob Clark } 299c8afe684SRob Clark 300a3376e3eSRob Clark encoder->bridge = hdmi->bridge; 301a3376e3eSRob Clark 302a3376e3eSRob Clark priv->bridges[priv->num_bridges++] = hdmi->bridge; 303a3376e3eSRob Clark priv->connectors[priv->num_connectors++] = hdmi->connector; 304a3376e3eSRob Clark 305c0c0d9eeSRob Clark platform_set_drvdata(pdev, hdmi); 306c0c0d9eeSRob Clark 307067fef37SRob Clark return 0; 308c8afe684SRob Clark 309c8afe684SRob Clark fail: 3103d3f8b1fSAjay Kumar /* bridge is normally destroyed by drm: */ 311067fef37SRob Clark if (hdmi->bridge) { 3123d3f8b1fSAjay Kumar hdmi_bridge_destroy(hdmi->bridge); 313067fef37SRob Clark hdmi->bridge = NULL; 314067fef37SRob Clark } 315067fef37SRob Clark if (hdmi->connector) { 316a3376e3eSRob Clark hdmi->connector->funcs->destroy(hdmi->connector); 317067fef37SRob Clark hdmi->connector = NULL; 318a3376e3eSRob Clark } 319c8afe684SRob Clark 320067fef37SRob Clark return ret; 321c8afe684SRob Clark } 322c8afe684SRob Clark 323c8afe684SRob Clark /* 324c8afe684SRob Clark * The hdmi device: 325c8afe684SRob Clark */ 326c8afe684SRob Clark 3275eba5d87SStephane Viau #define HDMI_CFG(item, entry) \ 3285eba5d87SStephane Viau .item ## _names = item ##_names_ ## entry, \ 3295eba5d87SStephane Viau .item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry) 3305eba5d87SStephane Viau 3310afbe59eSStephane Viau static const char *pwr_reg_names_none[] = {}; 3320afbe59eSStephane Viau static const char *hpd_reg_names_none[] = {}; 3330afbe59eSStephane Viau 3345eba5d87SStephane Viau static struct hdmi_platform_config hdmi_tx_8660_config = { 3355eba5d87SStephane Viau .phy_init = hdmi_phy_8x60_init, 3365eba5d87SStephane Viau }; 3375eba5d87SStephane Viau 3385eba5d87SStephane Viau static const char *hpd_reg_names_8960[] = {"core-vdda", "hdmi-mux"}; 3395eba5d87SStephane Viau static const char *hpd_clk_names_8960[] = {"core_clk", "master_iface_clk", "slave_iface_clk"}; 3405eba5d87SStephane Viau 3415eba5d87SStephane Viau static struct hdmi_platform_config hdmi_tx_8960_config = { 3425eba5d87SStephane Viau .phy_init = hdmi_phy_8960_init, 3435eba5d87SStephane Viau HDMI_CFG(hpd_reg, 8960), 3445eba5d87SStephane Viau HDMI_CFG(hpd_clk, 8960), 3455eba5d87SStephane Viau }; 3465eba5d87SStephane Viau 3475eba5d87SStephane Viau static const char *pwr_reg_names_8x74[] = {"core-vdda", "core-vcc"}; 3485eba5d87SStephane Viau static const char *hpd_reg_names_8x74[] = {"hpd-gdsc", "hpd-5v"}; 3495eba5d87SStephane Viau static const char *pwr_clk_names_8x74[] = {"extp_clk", "alt_iface_clk"}; 3505eba5d87SStephane Viau static const char *hpd_clk_names_8x74[] = {"iface_clk", "core_clk", "mdp_core_clk"}; 3515eba5d87SStephane Viau static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0}; 3525eba5d87SStephane Viau 3535cf3a455SRob Clark static struct hdmi_platform_config hdmi_tx_8974_config = { 3545eba5d87SStephane Viau .phy_init = hdmi_phy_8x74_init, 3555eba5d87SStephane Viau HDMI_CFG(pwr_reg, 8x74), 3565eba5d87SStephane Viau HDMI_CFG(hpd_reg, 8x74), 3575eba5d87SStephane Viau HDMI_CFG(pwr_clk, 8x74), 3585eba5d87SStephane Viau HDMI_CFG(hpd_clk, 8x74), 3595eba5d87SStephane Viau .hpd_freq = hpd_clk_freq_8x74, 3605eba5d87SStephane Viau }; 3615eba5d87SStephane Viau 3625eba5d87SStephane Viau static const char *hpd_reg_names_8084[] = {"hpd-gdsc", "hpd-5v", "hpd-5v-en"}; 3635eba5d87SStephane Viau 3645eba5d87SStephane Viau static struct hdmi_platform_config hdmi_tx_8084_config = { 3655eba5d87SStephane Viau .phy_init = hdmi_phy_8x74_init, 3665eba5d87SStephane Viau HDMI_CFG(pwr_reg, 8x74), 3675eba5d87SStephane Viau HDMI_CFG(hpd_reg, 8084), 3685eba5d87SStephane Viau HDMI_CFG(pwr_clk, 8x74), 3695eba5d87SStephane Viau HDMI_CFG(hpd_clk, 8x74), 3705eba5d87SStephane Viau .hpd_freq = hpd_clk_freq_8x74, 3715eba5d87SStephane Viau }; 3725eba5d87SStephane Viau 3735cf3a455SRob Clark static struct hdmi_platform_config hdmi_tx_8994_config = { 3743a84f846SStephane Viau .phy_init = NULL, /* nothing to do for this HDMI PHY 20nm */ 3753a84f846SStephane Viau HDMI_CFG(pwr_reg, 8x74), 3760afbe59eSStephane Viau HDMI_CFG(hpd_reg, none), 3770afbe59eSStephane Viau HDMI_CFG(pwr_clk, 8x74), 3780afbe59eSStephane Viau HDMI_CFG(hpd_clk, 8x74), 3790afbe59eSStephane Viau .hpd_freq = hpd_clk_freq_8x74, 3800afbe59eSStephane Viau }; 3810afbe59eSStephane Viau 3820afbe59eSStephane Viau static struct hdmi_platform_config hdmi_tx_8996_config = { 3830afbe59eSStephane Viau .phy_init = NULL, 3840afbe59eSStephane Viau HDMI_CFG(pwr_reg, none), 3850afbe59eSStephane Viau HDMI_CFG(hpd_reg, none), 3863a84f846SStephane Viau HDMI_CFG(pwr_clk, 8x74), 3873a84f846SStephane Viau HDMI_CFG(hpd_clk, 8x74), 3883a84f846SStephane Viau .hpd_freq = hpd_clk_freq_8x74, 3893a84f846SStephane Viau }; 3903a84f846SStephane Viau 391dc50f782SArchit Taneja static const struct { 392dc50f782SArchit Taneja const char *name; 393dc50f782SArchit Taneja const bool output; 394dc50f782SArchit Taneja const int value; 395dc50f782SArchit Taneja const char *label; 396dc50f782SArchit Taneja } hdmi_gpio_pdata[] = { 397dc50f782SArchit Taneja { "qcom,hdmi-tx-ddc-clk", true, 1, "HDMI_DDC_CLK" }, 398dc50f782SArchit Taneja { "qcom,hdmi-tx-ddc-data", true, 1, "HDMI_DDC_DATA" }, 399dc50f782SArchit Taneja { "qcom,hdmi-tx-hpd", false, 1, "HDMI_HPD" }, 400dc50f782SArchit Taneja { "qcom,hdmi-tx-mux-en", true, 1, "HDMI_MUX_EN" }, 401dc50f782SArchit Taneja { "qcom,hdmi-tx-mux-sel", true, 0, "HDMI_MUX_SEL" }, 402dc50f782SArchit Taneja { "qcom,hdmi-tx-mux-lpm", true, 1, "HDMI_MUX_LPM" }, 403dc50f782SArchit Taneja }; 404dc50f782SArchit Taneja 405dc50f782SArchit Taneja static int get_gpio(struct device_node *of_node, const char *name) 406dada25bdSRob Clark { 407dada25bdSRob Clark int gpio = of_get_named_gpio(of_node, name, 0); 408dada25bdSRob Clark if (gpio < 0) { 40941e69778SRob Clark char name2[32]; 41041e69778SRob Clark snprintf(name2, sizeof(name2), "%s-gpio", name); 41141e69778SRob Clark gpio = of_get_named_gpio(of_node, name2, 0); 41241e69778SRob Clark if (gpio < 0) { 4133a84f846SStephane Viau DBG("failed to get gpio: %s (%d)", name, gpio); 414dada25bdSRob Clark gpio = -1; 415dada25bdSRob Clark } 41641e69778SRob Clark } 417dada25bdSRob Clark return gpio; 418dada25bdSRob Clark } 419fc886107SMark Charlebois 420fc886107SMark Charlebois static int hdmi_bind(struct device *dev, struct device *master, void *data) 421fc886107SMark Charlebois { 422d1a717bdSRob Clark struct drm_device *drm = dev_get_drvdata(master); 423d1a717bdSRob Clark struct msm_drm_private *priv = drm->dev_private; 4245eba5d87SStephane Viau static struct hdmi_platform_config *hdmi_cfg; 425067fef37SRob Clark struct hdmi *hdmi; 426fc886107SMark Charlebois struct device_node *of_node = dev->of_node; 427dc50f782SArchit Taneja int i; 428dada25bdSRob Clark 4291fd6a441SArchit Taneja hdmi_cfg = (struct hdmi_platform_config *) 4301fd6a441SArchit Taneja of_device_get_match_data(dev); 4311fd6a441SArchit Taneja if (!hdmi_cfg) { 4321fd6a441SArchit Taneja dev_err(dev, "unknown hdmi_cfg: %s\n", of_node->name); 4335eba5d87SStephane Viau return -ENXIO; 43441e69778SRob Clark } 43541e69778SRob Clark 4365eba5d87SStephane Viau hdmi_cfg->mmio_name = "core_physical"; 437c6a57a50Sjilai wang hdmi_cfg->qfprom_mmio_name = "qfprom_physical"; 438dc50f782SArchit Taneja 439dc50f782SArchit Taneja for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { 440dc50f782SArchit Taneja hdmi_cfg->gpios[i].num = get_gpio(of_node, 441dc50f782SArchit Taneja hdmi_gpio_pdata[i].name); 442dc50f782SArchit Taneja hdmi_cfg->gpios[i].output = hdmi_gpio_pdata[i].output; 443dc50f782SArchit Taneja hdmi_cfg->gpios[i].value = hdmi_gpio_pdata[i].value; 444dc50f782SArchit Taneja hdmi_cfg->gpios[i].label = hdmi_gpio_pdata[i].label; 445dc50f782SArchit Taneja } 446dada25bdSRob Clark 4475eba5d87SStephane Viau dev->platform_data = hdmi_cfg; 4485eba5d87SStephane Viau 449067fef37SRob Clark hdmi = hdmi_init(to_platform_device(dev)); 450067fef37SRob Clark if (IS_ERR(hdmi)) 451067fef37SRob Clark return PTR_ERR(hdmi); 452d1a717bdSRob Clark priv->hdmi = hdmi; 4535eba5d87SStephane Viau 454c8afe684SRob Clark return 0; 455c8afe684SRob Clark } 456c8afe684SRob Clark 457060530f1SRob Clark static void hdmi_unbind(struct device *dev, struct device *master, 458060530f1SRob Clark void *data) 459060530f1SRob Clark { 460d1a717bdSRob Clark struct drm_device *drm = dev_get_drvdata(master); 461d1a717bdSRob Clark struct msm_drm_private *priv = drm->dev_private; 462d1a717bdSRob Clark if (priv->hdmi) { 463d1a717bdSRob Clark hdmi_destroy(priv->hdmi); 464d1a717bdSRob Clark priv->hdmi = NULL; 465d1a717bdSRob Clark } 466060530f1SRob Clark } 467060530f1SRob Clark 468060530f1SRob Clark static const struct component_ops hdmi_ops = { 469060530f1SRob Clark .bind = hdmi_bind, 470060530f1SRob Clark .unbind = hdmi_unbind, 471060530f1SRob Clark }; 472060530f1SRob Clark 473060530f1SRob Clark static int hdmi_dev_probe(struct platform_device *pdev) 474060530f1SRob Clark { 475060530f1SRob Clark return component_add(&pdev->dev, &hdmi_ops); 476060530f1SRob Clark } 477060530f1SRob Clark 478c8afe684SRob Clark static int hdmi_dev_remove(struct platform_device *pdev) 479c8afe684SRob Clark { 480060530f1SRob Clark component_del(&pdev->dev, &hdmi_ops); 481c8afe684SRob Clark return 0; 482c8afe684SRob Clark } 483c8afe684SRob Clark 4841fd6a441SArchit Taneja static const struct of_device_id dt_match[] = { 4851fd6a441SArchit Taneja { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config }, 4861fd6a441SArchit Taneja { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config }, 4871fd6a441SArchit Taneja { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config }, 4881fd6a441SArchit Taneja { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config }, 4891fd6a441SArchit Taneja { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config }, 4901fd6a441SArchit Taneja { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config }, 4911fd6a441SArchit Taneja {} 4921fd6a441SArchit Taneja }; 4931fd6a441SArchit Taneja 494c8afe684SRob Clark static struct platform_driver hdmi_driver = { 495c8afe684SRob Clark .probe = hdmi_dev_probe, 496c8afe684SRob Clark .remove = hdmi_dev_remove, 497dada25bdSRob Clark .driver = { 498dada25bdSRob Clark .name = "hdmi_msm", 499dada25bdSRob Clark .of_match_table = dt_match, 500dada25bdSRob Clark }, 501c8afe684SRob Clark }; 502c8afe684SRob Clark 503c8afe684SRob Clark void __init hdmi_register(void) 504c8afe684SRob Clark { 50515b4a452SArchit Taneja hdmi_phy_driver_register(); 506c8afe684SRob Clark platform_driver_register(&hdmi_driver); 507c8afe684SRob Clark } 508c8afe684SRob Clark 509c8afe684SRob Clark void __exit hdmi_unregister(void) 510c8afe684SRob Clark { 511c8afe684SRob Clark platform_driver_unregister(&hdmi_driver); 51215b4a452SArchit Taneja hdmi_phy_driver_unregister(); 513c8afe684SRob Clark } 514