Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #include <linux/of_device.h>
0007 
0008 #include "hdmi.h"
0009 
0010 static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy)
0011 {
0012     struct hdmi_phy_cfg *cfg = phy->cfg;
0013     struct device *dev = &phy->pdev->dev;
0014     int i, ret;
0015 
0016     phy->regs = devm_kcalloc(dev, cfg->num_regs, sizeof(phy->regs[0]),
0017                  GFP_KERNEL);
0018     if (!phy->regs)
0019         return -ENOMEM;
0020 
0021     phy->clks = devm_kcalloc(dev, cfg->num_clks, sizeof(phy->clks[0]),
0022                  GFP_KERNEL);
0023     if (!phy->clks)
0024         return -ENOMEM;
0025 
0026     for (i = 0; i < cfg->num_regs; i++)
0027         phy->regs[i].supply = cfg->reg_names[i];
0028 
0029     ret = devm_regulator_bulk_get(dev, cfg->num_regs, phy->regs);
0030     if (ret) {
0031         if (ret != -EPROBE_DEFER)
0032             DRM_DEV_ERROR(dev, "failed to get phy regulators: %d\n", ret);
0033 
0034         return ret;
0035     }
0036 
0037     for (i = 0; i < cfg->num_clks; i++) {
0038         struct clk *clk;
0039 
0040         clk = msm_clk_get(phy->pdev, cfg->clk_names[i]);
0041         if (IS_ERR(clk)) {
0042             ret = PTR_ERR(clk);
0043             DRM_DEV_ERROR(dev, "failed to get phy clock: %s (%d)\n",
0044                 cfg->clk_names[i], ret);
0045             return ret;
0046         }
0047 
0048         phy->clks[i] = clk;
0049     }
0050 
0051     return 0;
0052 }
0053 
0054 int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy)
0055 {
0056     struct hdmi_phy_cfg *cfg = phy->cfg;
0057     struct device *dev = &phy->pdev->dev;
0058     int i, ret = 0;
0059 
0060     pm_runtime_get_sync(dev);
0061 
0062     ret = regulator_bulk_enable(cfg->num_regs, phy->regs);
0063     if (ret) {
0064         DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret);
0065         return ret;
0066     }
0067 
0068     for (i = 0; i < cfg->num_clks; i++) {
0069         ret = clk_prepare_enable(phy->clks[i]);
0070         if (ret)
0071             DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n",
0072                 cfg->clk_names[i], ret);
0073     }
0074 
0075     return ret;
0076 }
0077 
0078 void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy)
0079 {
0080     struct hdmi_phy_cfg *cfg = phy->cfg;
0081     struct device *dev = &phy->pdev->dev;
0082     int i;
0083 
0084     for (i = cfg->num_clks - 1; i >= 0; i--)
0085         clk_disable_unprepare(phy->clks[i]);
0086 
0087     regulator_bulk_disable(cfg->num_regs, phy->regs);
0088 
0089     pm_runtime_put_sync(dev);
0090 }
0091 
0092 void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock)
0093 {
0094     if (!phy || !phy->cfg->powerup)
0095         return;
0096 
0097     phy->cfg->powerup(phy, pixclock);
0098 }
0099 
0100 void msm_hdmi_phy_powerdown(struct hdmi_phy *phy)
0101 {
0102     if (!phy || !phy->cfg->powerdown)
0103         return;
0104 
0105     phy->cfg->powerdown(phy);
0106 }
0107 
0108 static int msm_hdmi_phy_pll_init(struct platform_device *pdev,
0109                  enum hdmi_phy_type type)
0110 {
0111     int ret;
0112 
0113     switch (type) {
0114     case MSM_HDMI_PHY_8960:
0115         ret = msm_hdmi_pll_8960_init(pdev);
0116         break;
0117     case MSM_HDMI_PHY_8996:
0118         ret = msm_hdmi_pll_8996_init(pdev);
0119         break;
0120     /*
0121      * we don't have PLL support for these, don't report an error for now
0122      */
0123     case MSM_HDMI_PHY_8x60:
0124     case MSM_HDMI_PHY_8x74:
0125     default:
0126         ret = 0;
0127         break;
0128     }
0129 
0130     return ret;
0131 }
0132 
0133 static int msm_hdmi_phy_probe(struct platform_device *pdev)
0134 {
0135     struct device *dev = &pdev->dev;
0136     struct hdmi_phy *phy;
0137     int ret;
0138 
0139     phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
0140     if (!phy)
0141         return -ENODEV;
0142 
0143     phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
0144     if (!phy->cfg)
0145         return -ENODEV;
0146 
0147     phy->mmio = msm_ioremap(pdev, "hdmi_phy");
0148     if (IS_ERR(phy->mmio)) {
0149         DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
0150         return -ENOMEM;
0151     }
0152 
0153     phy->pdev = pdev;
0154 
0155     ret = msm_hdmi_phy_resource_init(phy);
0156     if (ret)
0157         return ret;
0158 
0159     pm_runtime_enable(&pdev->dev);
0160 
0161     ret = msm_hdmi_phy_resource_enable(phy);
0162     if (ret)
0163         return ret;
0164 
0165     ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
0166     if (ret) {
0167         DRM_DEV_ERROR(dev, "couldn't init PLL\n");
0168         msm_hdmi_phy_resource_disable(phy);
0169         return ret;
0170     }
0171 
0172     msm_hdmi_phy_resource_disable(phy);
0173 
0174     platform_set_drvdata(pdev, phy);
0175 
0176     return 0;
0177 }
0178 
0179 static int msm_hdmi_phy_remove(struct platform_device *pdev)
0180 {
0181     pm_runtime_disable(&pdev->dev);
0182 
0183     return 0;
0184 }
0185 
0186 static const struct of_device_id msm_hdmi_phy_dt_match[] = {
0187     { .compatible = "qcom,hdmi-phy-8660",
0188       .data = &msm_hdmi_phy_8x60_cfg },
0189     { .compatible = "qcom,hdmi-phy-8960",
0190       .data = &msm_hdmi_phy_8960_cfg },
0191     { .compatible = "qcom,hdmi-phy-8974",
0192       .data = &msm_hdmi_phy_8x74_cfg },
0193     { .compatible = "qcom,hdmi-phy-8084",
0194       .data = &msm_hdmi_phy_8x74_cfg },
0195     { .compatible = "qcom,hdmi-phy-8996",
0196       .data = &msm_hdmi_phy_8996_cfg },
0197     {}
0198 };
0199 
0200 static struct platform_driver msm_hdmi_phy_platform_driver = {
0201     .probe      = msm_hdmi_phy_probe,
0202     .remove     = msm_hdmi_phy_remove,
0203     .driver     = {
0204         .name   = "msm_hdmi_phy",
0205         .of_match_table = msm_hdmi_phy_dt_match,
0206     },
0207 };
0208 
0209 void __init msm_hdmi_phy_driver_register(void)
0210 {
0211     platform_driver_register(&msm_hdmi_phy_platform_driver);
0212 }
0213 
0214 void __exit msm_hdmi_phy_driver_unregister(void)
0215 {
0216     platform_driver_unregister(&msm_hdmi_phy_platform_driver);
0217 }