brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 95b3f75 Raw
222 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2016, The Linux Foundation. All rights reserved.4 */5 6#include <linux/of.h>7#include <linux/platform_device.h>8 9#include "hdmi.h"10 11static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy)12{13	struct hdmi_phy_cfg *cfg = phy->cfg;14	struct device *dev = &phy->pdev->dev;15	int i, ret;16 17	phy->regs = devm_kcalloc(dev, cfg->num_regs, sizeof(phy->regs[0]),18				 GFP_KERNEL);19	if (!phy->regs)20		return -ENOMEM;21 22	phy->clks = devm_kcalloc(dev, cfg->num_clks, sizeof(phy->clks[0]),23				 GFP_KERNEL);24	if (!phy->clks)25		return -ENOMEM;26 27	for (i = 0; i < cfg->num_regs; i++)28		phy->regs[i].supply = cfg->reg_names[i];29 30	ret = devm_regulator_bulk_get(dev, cfg->num_regs, phy->regs);31	if (ret) {32		if (ret != -EPROBE_DEFER)33			DRM_DEV_ERROR(dev, "failed to get phy regulators: %d\n", ret);34 35		return ret;36	}37 38	for (i = 0; i < cfg->num_clks; i++) {39		struct clk *clk;40 41		clk = msm_clk_get(phy->pdev, cfg->clk_names[i]);42		if (IS_ERR(clk)) {43			ret = PTR_ERR(clk);44			DRM_DEV_ERROR(dev, "failed to get phy clock: %s (%d)\n",45				cfg->clk_names[i], ret);46			return ret;47		}48 49		phy->clks[i] = clk;50	}51 52	return 0;53}54 55int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy)56{57	struct hdmi_phy_cfg *cfg = phy->cfg;58	struct device *dev = &phy->pdev->dev;59	int i, ret = 0;60 61	pm_runtime_get_sync(dev);62 63	ret = regulator_bulk_enable(cfg->num_regs, phy->regs);64	if (ret) {65		DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret);66		return ret;67	}68 69	for (i = 0; i < cfg->num_clks; i++) {70		ret = clk_prepare_enable(phy->clks[i]);71		if (ret)72			DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n",73				cfg->clk_names[i], ret);74	}75 76	return ret;77}78 79void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy)80{81	struct hdmi_phy_cfg *cfg = phy->cfg;82	struct device *dev = &phy->pdev->dev;83	int i;84 85	for (i = cfg->num_clks - 1; i >= 0; i--)86		clk_disable_unprepare(phy->clks[i]);87 88	regulator_bulk_disable(cfg->num_regs, phy->regs);89 90	pm_runtime_put_sync(dev);91}92 93void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock)94{95	if (!phy || !phy->cfg->powerup)96		return;97 98	phy->cfg->powerup(phy, pixclock);99}100 101void msm_hdmi_phy_powerdown(struct hdmi_phy *phy)102{103	if (!phy || !phy->cfg->powerdown)104		return;105 106	phy->cfg->powerdown(phy);107}108 109static int msm_hdmi_phy_pll_init(struct platform_device *pdev,110			     enum hdmi_phy_type type)111{112	int ret;113 114	switch (type) {115	case MSM_HDMI_PHY_8960:116		ret = msm_hdmi_pll_8960_init(pdev);117		break;118	case MSM_HDMI_PHY_8996:119		ret = msm_hdmi_pll_8996_init(pdev);120		break;121	case MSM_HDMI_PHY_8998:122		ret = msm_hdmi_pll_8998_init(pdev);123		break;124	/*125	 * we don't have PLL support for these, don't report an error for now126	 */127	case MSM_HDMI_PHY_8x60:128	case MSM_HDMI_PHY_8x74:129	default:130		ret = 0;131		break;132	}133 134	return ret;135}136 137static int msm_hdmi_phy_probe(struct platform_device *pdev)138{139	struct device *dev = &pdev->dev;140	struct hdmi_phy *phy;141	int ret;142 143	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);144	if (!phy)145		return -ENODEV;146 147	phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);148	if (!phy->cfg)149		return -ENODEV;150 151	phy->mmio = msm_ioremap(pdev, "hdmi_phy");152	if (IS_ERR(phy->mmio)) {153		DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);154		return -ENOMEM;155	}156 157	phy->pdev = pdev;158 159	ret = msm_hdmi_phy_resource_init(phy);160	if (ret)161		return ret;162 163	pm_runtime_enable(&pdev->dev);164 165	ret = msm_hdmi_phy_resource_enable(phy);166	if (ret)167		return ret;168 169	ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);170	if (ret) {171		DRM_DEV_ERROR(dev, "couldn't init PLL\n");172		msm_hdmi_phy_resource_disable(phy);173		return ret;174	}175 176	msm_hdmi_phy_resource_disable(phy);177 178	platform_set_drvdata(pdev, phy);179 180	return 0;181}182 183static void msm_hdmi_phy_remove(struct platform_device *pdev)184{185	pm_runtime_disable(&pdev->dev);186}187 188static const struct of_device_id msm_hdmi_phy_dt_match[] = {189	{ .compatible = "qcom,hdmi-phy-8660",190	  .data = &msm_hdmi_phy_8x60_cfg },191	{ .compatible = "qcom,hdmi-phy-8960",192	  .data = &msm_hdmi_phy_8960_cfg },193	{ .compatible = "qcom,hdmi-phy-8974",194	  .data = &msm_hdmi_phy_8x74_cfg },195	{ .compatible = "qcom,hdmi-phy-8084",196	  .data = &msm_hdmi_phy_8x74_cfg },197	{ .compatible = "qcom,hdmi-phy-8996",198	  .data = &msm_hdmi_phy_8996_cfg },199	{ .compatible = "qcom,hdmi-phy-8998",200	  .data = &msm_hdmi_phy_8998_cfg },201	{}202};203 204static struct platform_driver msm_hdmi_phy_platform_driver = {205	.probe      = msm_hdmi_phy_probe,206	.remove_new = msm_hdmi_phy_remove,207	.driver     = {208		.name   = "msm_hdmi_phy",209		.of_match_table = msm_hdmi_phy_dt_match,210	},211};212 213void __init msm_hdmi_phy_driver_register(void)214{215	platform_driver_register(&msm_hdmi_phy_platform_driver);216}217 218void __exit msm_hdmi_phy_driver_unregister(void)219{220	platform_driver_unregister(&msm_hdmi_phy_platform_driver);221}222