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}
v6.9.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.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	/*
122	 * we don't have PLL support for these, don't report an error for now
123	 */
124	case MSM_HDMI_PHY_8x60:
125	case MSM_HDMI_PHY_8x74:
126	default:
127		ret = 0;
128		break;
129	}
130
131	return ret;
132}
133
134static int msm_hdmi_phy_probe(struct platform_device *pdev)
135{
136	struct device *dev = &pdev->dev;
137	struct hdmi_phy *phy;
138	int ret;
139
140	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
141	if (!phy)
142		return -ENODEV;
143
144	phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
145	if (!phy->cfg)
146		return -ENODEV;
147
148	phy->mmio = msm_ioremap(pdev, "hdmi_phy");
149	if (IS_ERR(phy->mmio)) {
150		DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
151		return -ENOMEM;
152	}
153
154	phy->pdev = pdev;
155
156	ret = msm_hdmi_phy_resource_init(phy);
157	if (ret)
158		return ret;
159
160	pm_runtime_enable(&pdev->dev);
161
162	ret = msm_hdmi_phy_resource_enable(phy);
163	if (ret)
164		return ret;
165
166	ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
167	if (ret) {
168		DRM_DEV_ERROR(dev, "couldn't init PLL\n");
169		msm_hdmi_phy_resource_disable(phy);
170		return ret;
171	}
172
173	msm_hdmi_phy_resource_disable(phy);
174
175	platform_set_drvdata(pdev, phy);
176
177	return 0;
178}
179
180static void msm_hdmi_phy_remove(struct platform_device *pdev)
181{
182	pm_runtime_disable(&pdev->dev);
 
 
183}
184
185static const struct of_device_id msm_hdmi_phy_dt_match[] = {
186	{ .compatible = "qcom,hdmi-phy-8660",
187	  .data = &msm_hdmi_phy_8x60_cfg },
188	{ .compatible = "qcom,hdmi-phy-8960",
189	  .data = &msm_hdmi_phy_8960_cfg },
190	{ .compatible = "qcom,hdmi-phy-8974",
191	  .data = &msm_hdmi_phy_8x74_cfg },
192	{ .compatible = "qcom,hdmi-phy-8084",
193	  .data = &msm_hdmi_phy_8x74_cfg },
194	{ .compatible = "qcom,hdmi-phy-8996",
195	  .data = &msm_hdmi_phy_8996_cfg },
196	{}
197};
198
199static struct platform_driver msm_hdmi_phy_platform_driver = {
200	.probe      = msm_hdmi_phy_probe,
201	.remove_new = msm_hdmi_phy_remove,
202	.driver     = {
203		.name   = "msm_hdmi_phy",
204		.of_match_table = msm_hdmi_phy_dt_match,
205	},
206};
207
208void __init msm_hdmi_phy_driver_register(void)
209{
210	platform_driver_register(&msm_hdmi_phy_platform_driver);
211}
212
213void __exit msm_hdmi_phy_driver_unregister(void)
214{
215	platform_driver_unregister(&msm_hdmi_phy_platform_driver);
216}