xref: /linux/drivers/usb/chipidea/ci_hdrc_msm.c (revision 5fd54ace4721fc5ce2bb5aef6318fcf17f421460)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2010, Code Aurora Forum. 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 
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/usb/chipidea.h>
13 #include <linux/clk.h>
14 #include <linux/reset.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/regmap.h>
17 #include <linux/io.h>
18 #include <linux/reset-controller.h>
19 #include <linux/extcon.h>
20 #include <linux/of.h>
21 
22 #include "ci.h"
23 
24 #define HS_PHY_AHB_MODE			0x0098
25 
26 #define HS_PHY_GENCONFIG		0x009c
27 #define HS_PHY_TXFIFO_IDLE_FORCE_DIS	BIT(4)
28 
29 #define HS_PHY_GENCONFIG_2		0x00a0
30 #define HS_PHY_SESS_VLD_CTRL_EN		BIT(7)
31 #define HS_PHY_ULPI_TX_PKT_EN_CLR_FIX	BIT(19)
32 
33 #define HSPHY_SESS_VLD_CTRL		BIT(25)
34 
35 /* Vendor base starts at 0x200 beyond CI base */
36 #define HS_PHY_CTRL			0x0040
37 #define HS_PHY_SEC_CTRL			0x0078
38 #define HS_PHY_DIG_CLAMP_N		BIT(16)
39 #define HS_PHY_POR_ASSERT		BIT(0)
40 
41 struct ci_hdrc_msm {
42 	struct platform_device *ci;
43 	struct clk *core_clk;
44 	struct clk *iface_clk;
45 	struct clk *fs_clk;
46 	struct ci_hdrc_platform_data pdata;
47 	struct reset_controller_dev rcdev;
48 	bool secondary_phy;
49 	bool hsic;
50 	void __iomem *base;
51 };
52 
53 static int
54 ci_hdrc_msm_por_reset(struct reset_controller_dev *r, unsigned long id)
55 {
56 	struct ci_hdrc_msm *ci_msm = container_of(r, struct ci_hdrc_msm, rcdev);
57 	void __iomem *addr = ci_msm->base;
58 	u32 val;
59 
60 	if (id)
61 		addr += HS_PHY_SEC_CTRL;
62 	else
63 		addr += HS_PHY_CTRL;
64 
65 	val = readl_relaxed(addr);
66 	val |= HS_PHY_POR_ASSERT;
67 	writel(val, addr);
68 	/*
69 	 * wait for minimum 10 microseconds as suggested by manual.
70 	 * Use a slightly larger value since the exact value didn't
71 	 * work 100% of the time.
72 	 */
73 	udelay(12);
74 	val &= ~HS_PHY_POR_ASSERT;
75 	writel(val, addr);
76 
77 	return 0;
78 }
79 
80 static const struct reset_control_ops ci_hdrc_msm_reset_ops = {
81 	.reset = ci_hdrc_msm_por_reset,
82 };
83 
84 static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
85 {
86 	struct device *dev = ci->dev->parent;
87 	struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev);
88 	int ret;
89 
90 	switch (event) {
91 	case CI_HDRC_CONTROLLER_RESET_EVENT:
92 		dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
93 
94 		hw_phymode_configure(ci);
95 		if (msm_ci->secondary_phy) {
96 			u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL);
97 			val |= HS_PHY_DIG_CLAMP_N;
98 			writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL);
99 		}
100 
101 		ret = phy_init(ci->phy);
102 		if (ret)
103 			return ret;
104 
105 		ret = phy_power_on(ci->phy);
106 		if (ret) {
107 			phy_exit(ci->phy);
108 			return ret;
109 		}
110 
111 		/* use AHB transactor, allow posted data writes */
112 		hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0xffffffff, 0x8);
113 
114 		/* workaround for rx buffer collision issue */
115 		hw_write_id_reg(ci, HS_PHY_GENCONFIG,
116 				HS_PHY_TXFIFO_IDLE_FORCE_DIS, 0);
117 
118 		if (!msm_ci->hsic)
119 			hw_write_id_reg(ci, HS_PHY_GENCONFIG_2,
120 					HS_PHY_ULPI_TX_PKT_EN_CLR_FIX, 0);
121 
122 		if (!IS_ERR(ci->platdata->vbus_extcon.edev)) {
123 			hw_write_id_reg(ci, HS_PHY_GENCONFIG_2,
124 					HS_PHY_SESS_VLD_CTRL_EN,
125 					HS_PHY_SESS_VLD_CTRL_EN);
126 			hw_write(ci, OP_USBCMD, HSPHY_SESS_VLD_CTRL,
127 				 HSPHY_SESS_VLD_CTRL);
128 
129 		}
130 		break;
131 	case CI_HDRC_CONTROLLER_STOPPED_EVENT:
132 		dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
133 		phy_power_off(ci->phy);
134 		phy_exit(ci->phy);
135 		break;
136 	default:
137 		dev_dbg(dev, "unknown ci_hdrc event\n");
138 		break;
139 	}
140 
141 	return 0;
142 }
143 
144 static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci,
145 			       struct platform_device *pdev)
146 {
147 	struct regmap *regmap;
148 	struct device *dev = &pdev->dev;
149 	struct of_phandle_args args;
150 	u32 val;
151 	int ret;
152 
153 	ret = of_parse_phandle_with_fixed_args(dev->of_node, "phy-select", 2, 0,
154 					       &args);
155 	if (ret)
156 		return 0;
157 
158 	regmap = syscon_node_to_regmap(args.np);
159 	of_node_put(args.np);
160 	if (IS_ERR(regmap))
161 		return PTR_ERR(regmap);
162 
163 	ret = regmap_write(regmap, args.args[0], args.args[1]);
164 	if (ret)
165 		return ret;
166 
167 	ci->secondary_phy = !!args.args[1];
168 	if (ci->secondary_phy) {
169 		val = readl_relaxed(ci->base + HS_PHY_SEC_CTRL);
170 		val |= HS_PHY_DIG_CLAMP_N;
171 		writel_relaxed(val, ci->base + HS_PHY_SEC_CTRL);
172 	}
173 
174 	return 0;
175 }
176 
177 static int ci_hdrc_msm_probe(struct platform_device *pdev)
178 {
179 	struct ci_hdrc_msm *ci;
180 	struct platform_device *plat_ci;
181 	struct clk *clk;
182 	struct reset_control *reset;
183 	struct resource *res;
184 	int ret;
185 	struct device_node *ulpi_node, *phy_node;
186 
187 	dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n");
188 
189 	ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
190 	if (!ci)
191 		return -ENOMEM;
192 	platform_set_drvdata(pdev, ci);
193 
194 	ci->pdata.name = "ci_hdrc_msm";
195 	ci->pdata.capoffset = DEF_CAPOFFSET;
196 	ci->pdata.flags	= CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING |
197 			  CI_HDRC_OVERRIDE_AHB_BURST |
198 			  CI_HDRC_OVERRIDE_PHY_CONTROL;
199 	ci->pdata.notify_event = ci_hdrc_msm_notify_event;
200 
201 	reset = devm_reset_control_get(&pdev->dev, "core");
202 	if (IS_ERR(reset))
203 		return PTR_ERR(reset);
204 
205 	ci->core_clk = clk = devm_clk_get(&pdev->dev, "core");
206 	if (IS_ERR(clk))
207 		return PTR_ERR(clk);
208 
209 	ci->iface_clk = clk = devm_clk_get(&pdev->dev, "iface");
210 	if (IS_ERR(clk))
211 		return PTR_ERR(clk);
212 
213 	ci->fs_clk = clk = devm_clk_get(&pdev->dev, "fs");
214 	if (IS_ERR(clk)) {
215 		if (PTR_ERR(clk) == -EPROBE_DEFER)
216 			return -EPROBE_DEFER;
217 		ci->fs_clk = NULL;
218 	}
219 
220 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
221 	ci->base = devm_ioremap_resource(&pdev->dev, res);
222 	if (IS_ERR(ci->base))
223 		return PTR_ERR(ci->base);
224 
225 	ci->rcdev.owner = THIS_MODULE;
226 	ci->rcdev.ops = &ci_hdrc_msm_reset_ops;
227 	ci->rcdev.of_node = pdev->dev.of_node;
228 	ci->rcdev.nr_resets = 2;
229 	ret = reset_controller_register(&ci->rcdev);
230 	if (ret)
231 		return ret;
232 
233 	ret = clk_prepare_enable(ci->fs_clk);
234 	if (ret)
235 		goto err_fs;
236 
237 	reset_control_assert(reset);
238 	usleep_range(10000, 12000);
239 	reset_control_deassert(reset);
240 
241 	clk_disable_unprepare(ci->fs_clk);
242 
243 	ret = clk_prepare_enable(ci->core_clk);
244 	if (ret)
245 		goto err_fs;
246 
247 	ret = clk_prepare_enable(ci->iface_clk);
248 	if (ret)
249 		goto err_iface;
250 
251 	ret = ci_hdrc_msm_mux_phy(ci, pdev);
252 	if (ret)
253 		goto err_mux;
254 
255 	ulpi_node = of_find_node_by_name(of_node_get(pdev->dev.of_node), "ulpi");
256 	if (ulpi_node) {
257 		phy_node = of_get_next_available_child(ulpi_node, NULL);
258 		ci->hsic = of_device_is_compatible(phy_node, "qcom,usb-hsic-phy");
259 		of_node_put(phy_node);
260 	}
261 	of_node_put(ulpi_node);
262 
263 	plat_ci = ci_hdrc_add_device(&pdev->dev, pdev->resource,
264 				     pdev->num_resources, &ci->pdata);
265 	if (IS_ERR(plat_ci)) {
266 		ret = PTR_ERR(plat_ci);
267 		if (ret != -EPROBE_DEFER)
268 			dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
269 		goto err_mux;
270 	}
271 
272 	ci->ci = plat_ci;
273 
274 	pm_runtime_set_active(&pdev->dev);
275 	pm_runtime_no_callbacks(&pdev->dev);
276 	pm_runtime_enable(&pdev->dev);
277 
278 	return 0;
279 
280 err_mux:
281 	clk_disable_unprepare(ci->iface_clk);
282 err_iface:
283 	clk_disable_unprepare(ci->core_clk);
284 err_fs:
285 	reset_controller_unregister(&ci->rcdev);
286 	return ret;
287 }
288 
289 static int ci_hdrc_msm_remove(struct platform_device *pdev)
290 {
291 	struct ci_hdrc_msm *ci = platform_get_drvdata(pdev);
292 
293 	pm_runtime_disable(&pdev->dev);
294 	ci_hdrc_remove_device(ci->ci);
295 	clk_disable_unprepare(ci->iface_clk);
296 	clk_disable_unprepare(ci->core_clk);
297 	reset_controller_unregister(&ci->rcdev);
298 
299 	return 0;
300 }
301 
302 static const struct of_device_id msm_ci_dt_match[] = {
303 	{ .compatible = "qcom,ci-hdrc", },
304 	{ }
305 };
306 MODULE_DEVICE_TABLE(of, msm_ci_dt_match);
307 
308 static struct platform_driver ci_hdrc_msm_driver = {
309 	.probe = ci_hdrc_msm_probe,
310 	.remove = ci_hdrc_msm_remove,
311 	.driver = {
312 		.name = "msm_hsusb",
313 		.of_match_table = msm_ci_dt_match,
314 	},
315 };
316 
317 module_platform_driver(ci_hdrc_msm_driver);
318 
319 MODULE_ALIAS("platform:msm_hsusb");
320 MODULE_ALIAS("platform:ci13xxx_msm");
321 MODULE_LICENSE("GPL v2");
322