• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/clk.h>
7 #include <linux/delay.h>
8 #include <linux/err.h>
9 #include <linux/io.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/of_device.h>
14 #include <linux/phy/phy.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <linux/regulator/consumer.h>
18 #include <linux/reset.h>
19 #include <linux/slab.h>
20 
21 #define USB2_PHY_USB_PHY_UTMI_CTRL0		(0x3c)
22 #define SLEEPM					BIT(0)
23 #define OPMODE_MASK				GENMASK(4, 3)
24 #define OPMODE_NORMAL				(0x00)
25 #define OPMODE_NONDRIVING			BIT(3)
26 #define TERMSEL					BIT(5)
27 
28 #define USB2_PHY_USB_PHY_UTMI_CTRL1		(0x40)
29 #define XCVRSEL					BIT(0)
30 
31 #define USB2_PHY_USB_PHY_UTMI_CTRL5		(0x50)
32 #define POR					BIT(1)
33 
34 #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0	(0x54)
35 #define RETENABLEN				BIT(3)
36 #define FSEL_MASK				GENMASK(6, 4)
37 #define FSEL_DEFAULT				(0x3 << 4)
38 
39 #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1	(0x58)
40 #define VBUSVLDEXTSEL0				BIT(4)
41 #define PLLBTUNE				BIT(5)
42 
43 #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2	(0x5c)
44 #define VREGBYPASS				BIT(0)
45 
46 #define USB2_PHY_USB_PHY_HS_PHY_CTRL1		(0x60)
47 #define VBUSVLDEXT0				BIT(0)
48 
49 #define USB2_PHY_USB_PHY_HS_PHY_CTRL2		(0x64)
50 #define USB2_AUTO_RESUME			BIT(0)
51 #define USB2_SUSPEND_N				BIT(2)
52 #define USB2_SUSPEND_N_SEL			BIT(3)
53 
54 #define USB2_PHY_USB_PHY_CFG0			(0x94)
55 #define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN	BIT(0)
56 #define UTMI_PHY_CMN_CTRL_OVERRIDE_EN		BIT(1)
57 
58 #define USB2_PHY_USB_PHY_REFCLK_CTRL		(0xa0)
59 #define REFCLK_SEL_MASK				GENMASK(1, 0)
60 #define REFCLK_SEL_DEFAULT			(0x2 << 0)
61 
62 static const char * const qcom_snps_hsphy_vreg_names[] = {
63 	"vdda-pll", "vdda33", "vdda18",
64 };
65 
66 #define SNPS_HS_NUM_VREGS		ARRAY_SIZE(qcom_snps_hsphy_vreg_names)
67 
68 /**
69  * struct qcom_snps_hsphy - snps hs phy attributes
70  *
71  * @phy: generic phy
72  * @base: iomapped memory space for snps hs phy
73  *
74  * @cfg_ahb_clk: AHB2PHY interface clock
75  * @ref_clk: phy reference clock
76  * @iface_clk: phy interface clock
77  * @phy_reset: phy reset control
78  * @vregs: regulator supplies bulk data
79  * @phy_initialized: if PHY has been initialized correctly
80  * @mode: contains the current mode the PHY is in
81  */
82 struct qcom_snps_hsphy {
83 	struct phy *phy;
84 	void __iomem *base;
85 
86 	struct clk *cfg_ahb_clk;
87 	struct clk *ref_clk;
88 	struct reset_control *phy_reset;
89 	struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS];
90 
91 	bool phy_initialized;
92 	enum phy_mode mode;
93 };
94 
qcom_snps_hsphy_write_mask(void __iomem * base,u32 offset,u32 mask,u32 val)95 static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
96 						u32 mask, u32 val)
97 {
98 	u32 reg;
99 
100 	reg = readl_relaxed(base + offset);
101 	reg &= ~mask;
102 	reg |= val & mask;
103 	writel_relaxed(reg, base + offset);
104 
105 	/* Ensure above write is completed */
106 	readl_relaxed(base + offset);
107 }
108 
qcom_snps_hsphy_suspend(struct qcom_snps_hsphy * hsphy)109 static int qcom_snps_hsphy_suspend(struct qcom_snps_hsphy *hsphy)
110 {
111 	dev_dbg(&hsphy->phy->dev, "Suspend QCOM SNPS PHY\n");
112 
113 	if (hsphy->mode == PHY_MODE_USB_HOST) {
114 		/* Enable auto-resume to meet remote wakeup timing */
115 		qcom_snps_hsphy_write_mask(hsphy->base,
116 					   USB2_PHY_USB_PHY_HS_PHY_CTRL2,
117 					   USB2_AUTO_RESUME,
118 					   USB2_AUTO_RESUME);
119 		usleep_range(500, 1000);
120 		qcom_snps_hsphy_write_mask(hsphy->base,
121 					   USB2_PHY_USB_PHY_HS_PHY_CTRL2,
122 					   0, USB2_AUTO_RESUME);
123 	}
124 
125 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
126 	return 0;
127 }
128 
qcom_snps_hsphy_resume(struct qcom_snps_hsphy * hsphy)129 static int qcom_snps_hsphy_resume(struct qcom_snps_hsphy *hsphy)
130 {
131 	int ret;
132 
133 	dev_dbg(&hsphy->phy->dev, "Resume QCOM SNPS PHY, mode\n");
134 
135 	ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
136 	if (ret) {
137 		dev_err(&hsphy->phy->dev, "failed to enable cfg ahb clock\n");
138 		return ret;
139 	}
140 
141 	return 0;
142 }
143 
qcom_snps_hsphy_runtime_suspend(struct device * dev)144 static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev)
145 {
146 	struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
147 
148 	if (!hsphy->phy_initialized)
149 		return 0;
150 
151 	qcom_snps_hsphy_suspend(hsphy);
152 	return 0;
153 }
154 
qcom_snps_hsphy_runtime_resume(struct device * dev)155 static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev)
156 {
157 	struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
158 
159 	if (!hsphy->phy_initialized)
160 		return 0;
161 
162 	qcom_snps_hsphy_resume(hsphy);
163 	return 0;
164 }
165 
qcom_snps_hsphy_set_mode(struct phy * phy,enum phy_mode mode,int submode)166 static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
167 				    int submode)
168 {
169 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
170 
171 	hsphy->mode = mode;
172 	return 0;
173 }
174 
qcom_snps_hsphy_init(struct phy * phy)175 static int qcom_snps_hsphy_init(struct phy *phy)
176 {
177 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
178 	int ret;
179 
180 	dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__);
181 
182 	ret = regulator_bulk_enable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
183 	if (ret)
184 		return ret;
185 
186 	ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
187 	if (ret) {
188 		dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
189 		goto poweroff_phy;
190 	}
191 
192 	ret = reset_control_assert(hsphy->phy_reset);
193 	if (ret) {
194 		dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
195 		goto disable_ahb_clk;
196 	}
197 
198 	usleep_range(100, 150);
199 
200 	ret = reset_control_deassert(hsphy->phy_reset);
201 	if (ret) {
202 		dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
203 		goto disable_ahb_clk;
204 	}
205 
206 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
207 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
208 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
209 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
210 							POR, POR);
211 	qcom_snps_hsphy_write_mask(hsphy->base,
212 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
213 					FSEL_MASK, 0);
214 	qcom_snps_hsphy_write_mask(hsphy->base,
215 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
216 					PLLBTUNE, PLLBTUNE);
217 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_REFCLK_CTRL,
218 					REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK);
219 	qcom_snps_hsphy_write_mask(hsphy->base,
220 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
221 					VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
222 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
223 					VBUSVLDEXT0, VBUSVLDEXT0);
224 
225 	qcom_snps_hsphy_write_mask(hsphy->base,
226 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
227 					VREGBYPASS, VREGBYPASS);
228 
229 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
230 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
231 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
232 
233 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
234 					SLEEPM, SLEEPM);
235 
236 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
237 					POR, 0);
238 
239 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
240 					USB2_SUSPEND_N_SEL, 0);
241 
242 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
243 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0);
244 
245 	hsphy->phy_initialized = true;
246 
247 	return 0;
248 
249 disable_ahb_clk:
250 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
251 poweroff_phy:
252 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
253 
254 	return ret;
255 }
256 
qcom_snps_hsphy_exit(struct phy * phy)257 static int qcom_snps_hsphy_exit(struct phy *phy)
258 {
259 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
260 
261 	reset_control_assert(hsphy->phy_reset);
262 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
263 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
264 	hsphy->phy_initialized = false;
265 
266 	return 0;
267 }
268 
269 static const struct phy_ops qcom_snps_hsphy_gen_ops = {
270 	.init		= qcom_snps_hsphy_init,
271 	.exit		= qcom_snps_hsphy_exit,
272 	.set_mode	= qcom_snps_hsphy_set_mode,
273 	.owner		= THIS_MODULE,
274 };
275 
276 static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
277 	{ .compatible	= "qcom,sm8150-usb-hs-phy", },
278 	{ .compatible	= "qcom,usb-snps-hs-7nm-phy", },
279 	{ .compatible	= "qcom,usb-snps-femto-v2-phy",	},
280 	{ }
281 };
282 MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table);
283 
284 static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = {
285 	SET_RUNTIME_PM_OPS(qcom_snps_hsphy_runtime_suspend,
286 			   qcom_snps_hsphy_runtime_resume, NULL)
287 };
288 
qcom_snps_hsphy_probe(struct platform_device * pdev)289 static int qcom_snps_hsphy_probe(struct platform_device *pdev)
290 {
291 	struct device *dev = &pdev->dev;
292 	struct qcom_snps_hsphy *hsphy;
293 	struct phy_provider *phy_provider;
294 	struct phy *generic_phy;
295 	int ret, i;
296 	int num;
297 
298 	hsphy = devm_kzalloc(dev, sizeof(*hsphy), GFP_KERNEL);
299 	if (!hsphy)
300 		return -ENOMEM;
301 
302 	hsphy->base = devm_platform_ioremap_resource(pdev, 0);
303 	if (IS_ERR(hsphy->base))
304 		return PTR_ERR(hsphy->base);
305 
306 	hsphy->ref_clk = devm_clk_get(dev, "ref");
307 	if (IS_ERR(hsphy->ref_clk)) {
308 		ret = PTR_ERR(hsphy->ref_clk);
309 		if (ret != -EPROBE_DEFER)
310 			dev_err(dev, "failed to get ref clk, %d\n", ret);
311 		return ret;
312 	}
313 
314 	hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
315 	if (IS_ERR(hsphy->phy_reset)) {
316 		dev_err(dev, "failed to get phy core reset\n");
317 		return PTR_ERR(hsphy->phy_reset);
318 	}
319 
320 	num = ARRAY_SIZE(hsphy->vregs);
321 	for (i = 0; i < num; i++)
322 		hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i];
323 
324 	ret = devm_regulator_bulk_get(dev, num, hsphy->vregs);
325 	if (ret) {
326 		if (ret != -EPROBE_DEFER)
327 			dev_err(dev, "failed to get regulator supplies: %d\n",
328 				ret);
329 		return ret;
330 	}
331 
332 	pm_runtime_set_active(dev);
333 	pm_runtime_enable(dev);
334 	/*
335 	 * Prevent runtime pm from being ON by default. Users can enable
336 	 * it using power/control in sysfs.
337 	 */
338 	pm_runtime_forbid(dev);
339 
340 	generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
341 	if (IS_ERR(generic_phy)) {
342 		ret = PTR_ERR(generic_phy);
343 		dev_err(dev, "failed to create phy, %d\n", ret);
344 		return ret;
345 	}
346 	hsphy->phy = generic_phy;
347 
348 	dev_set_drvdata(dev, hsphy);
349 	phy_set_drvdata(generic_phy, hsphy);
350 
351 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
352 	if (!IS_ERR(phy_provider))
353 		dev_dbg(dev, "Registered Qcom-SNPS HS phy\n");
354 	else
355 		pm_runtime_disable(dev);
356 
357 	return PTR_ERR_OR_ZERO(phy_provider);
358 }
359 
360 static struct platform_driver qcom_snps_hsphy_driver = {
361 	.probe		= qcom_snps_hsphy_probe,
362 	.driver = {
363 		.name	= "qcom-snps-hs-femto-v2-phy",
364 		.pm = &qcom_snps_hsphy_pm_ops,
365 		.of_match_table = qcom_snps_hsphy_of_match_table,
366 	},
367 };
368 
369 module_platform_driver(qcom_snps_hsphy_driver);
370 
371 MODULE_DESCRIPTION("Qualcomm SNPS FEMTO USB HS PHY V2 driver");
372 MODULE_LICENSE("GPL v2");
373