Linux Audio

Check our new training course

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