Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2018 MediaTek Inc.
  4 * Author: Jie Qiu <jie.qiu@mediatek.com>
  5 */
  6
  7#include "mtk_hdmi_phy.h"
  8
  9static int mtk_hdmi_phy_power_on(struct phy *phy);
 10static int mtk_hdmi_phy_power_off(struct phy *phy);
 11
 12static const struct phy_ops mtk_hdmi_phy_dev_ops = {
 13	.power_on = mtk_hdmi_phy_power_on,
 14	.power_off = mtk_hdmi_phy_power_off,
 15	.owner = THIS_MODULE,
 16};
 17
 18void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
 19			     u32 bits)
 20{
 21	void __iomem *reg = hdmi_phy->regs + offset;
 22	u32 tmp;
 23
 24	tmp = readl(reg);
 25	tmp &= ~bits;
 26	writel(tmp, reg);
 27}
 28
 29void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
 30			   u32 bits)
 31{
 32	void __iomem *reg = hdmi_phy->regs + offset;
 33	u32 tmp;
 34
 35	tmp = readl(reg);
 36	tmp |= bits;
 37	writel(tmp, reg);
 38}
 39
 40void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
 41		       u32 val, u32 mask)
 42{
 43	void __iomem *reg = hdmi_phy->regs + offset;
 44	u32 tmp;
 45
 46	tmp = readl(reg);
 47	tmp = (tmp & ~mask) | (val & mask);
 48	writel(tmp, reg);
 49}
 50
 51inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw)
 52{
 53	return container_of(hw, struct mtk_hdmi_phy, pll_hw);
 54}
 55
 56static int mtk_hdmi_phy_power_on(struct phy *phy)
 57{
 58	struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
 59	int ret;
 60
 61	ret = clk_prepare_enable(hdmi_phy->pll);
 62	if (ret < 0)
 63		return ret;
 64
 65	hdmi_phy->conf->hdmi_phy_enable_tmds(hdmi_phy);
 66	return 0;
 67}
 68
 69static int mtk_hdmi_phy_power_off(struct phy *phy)
 70{
 71	struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
 72
 73	hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy);
 74	clk_disable_unprepare(hdmi_phy->pll);
 75
 76	return 0;
 77}
 78
 79static const struct phy_ops *
 80mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy)
 81{
 82	if (hdmi_phy && hdmi_phy->conf &&
 83	    hdmi_phy->conf->hdmi_phy_enable_tmds &&
 84	    hdmi_phy->conf->hdmi_phy_disable_tmds)
 85		return &mtk_hdmi_phy_dev_ops;
 86
 87	dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n");
 88		return NULL;
 89}
 90
 91static void mtk_hdmi_phy_clk_get_data(struct mtk_hdmi_phy *hdmi_phy,
 92				      struct clk_init_data *clk_init)
 93{
 94	clk_init->flags = hdmi_phy->conf->flags;
 95	clk_init->ops = hdmi_phy->conf->hdmi_phy_clk_ops;
 96}
 97
 98static int mtk_hdmi_phy_probe(struct platform_device *pdev)
 99{
100	struct device *dev = &pdev->dev;
101	struct mtk_hdmi_phy *hdmi_phy;
102	struct resource *mem;
103	struct clk *ref_clk;
104	const char *ref_clk_name;
105	struct clk_init_data clk_init = {
106		.num_parents = 1,
107		.parent_names = (const char * const *)&ref_clk_name,
108	};
109
110	struct phy *phy;
111	struct phy_provider *phy_provider;
112	int ret;
113
114	hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
115	if (!hdmi_phy)
116		return -ENOMEM;
117
118	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
119	hdmi_phy->regs = devm_ioremap_resource(dev, mem);
120	if (IS_ERR(hdmi_phy->regs)) {
121		ret = PTR_ERR(hdmi_phy->regs);
122		dev_err(dev, "Failed to get memory resource: %d\n", ret);
123		return ret;
124	}
125
126	ref_clk = devm_clk_get(dev, "pll_ref");
127	if (IS_ERR(ref_clk)) {
128		ret = PTR_ERR(ref_clk);
129		dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
130			ret);
131		return ret;
132	}
133	ref_clk_name = __clk_get_name(ref_clk);
134
135	ret = of_property_read_string(dev->of_node, "clock-output-names",
136				      &clk_init.name);
137	if (ret < 0) {
138		dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
139		return ret;
140	}
141
142	hdmi_phy->dev = dev;
143	hdmi_phy->conf =
144		(struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev);
145	mtk_hdmi_phy_clk_get_data(hdmi_phy, &clk_init);
146	hdmi_phy->pll_hw.init = &clk_init;
147	hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
148	if (IS_ERR(hdmi_phy->pll)) {
149		ret = PTR_ERR(hdmi_phy->pll);
150		dev_err(dev, "Failed to register PLL: %d\n", ret);
151		return ret;
152	}
153
154	ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
155				   &hdmi_phy->ibias);
156	if (ret < 0) {
157		dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
158		return ret;
159	}
160
161	ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
162				   &hdmi_phy->ibias_up);
163	if (ret < 0) {
164		dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
165		return ret;
166	}
167
168	dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
169	hdmi_phy->drv_imp_clk = 0x30;
170	hdmi_phy->drv_imp_d2 = 0x30;
171	hdmi_phy->drv_imp_d1 = 0x30;
172	hdmi_phy->drv_imp_d0 = 0x30;
173
174	phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy));
175	if (IS_ERR(phy)) {
176		dev_err(dev, "Failed to create HDMI PHY\n");
177		return PTR_ERR(phy);
178	}
179	phy_set_drvdata(phy, hdmi_phy);
180
181	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
182	if (IS_ERR(phy_provider)) {
183		dev_err(dev, "Failed to register HDMI PHY\n");
184		return PTR_ERR(phy_provider);
185	}
186
187	return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
188				   hdmi_phy->pll);
189}
190
191static const struct of_device_id mtk_hdmi_phy_match[] = {
192	{ .compatible = "mediatek,mt2701-hdmi-phy",
193	  .data = &mtk_hdmi_phy_2701_conf,
194	},
195	{ .compatible = "mediatek,mt8173-hdmi-phy",
196	  .data = &mtk_hdmi_phy_8173_conf,
197	},
198	{},
199};
200
201struct platform_driver mtk_hdmi_phy_driver = {
202	.probe = mtk_hdmi_phy_probe,
203	.driver = {
204		.name = "mediatek-hdmi-phy",
205		.of_match_table = mtk_hdmi_phy_match,
206	},
207};
208
209MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
210MODULE_LICENSE("GPL v2");