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(7, 5)
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  */
81 struct qcom_snps_hsphy {
82 	struct phy *phy;
83 	void __iomem *base;
84 
85 	struct clk *cfg_ahb_clk;
86 	struct clk *ref_clk;
87 	struct reset_control *phy_reset;
88 	struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS];
89 
90 	bool phy_initialized;
91 };
92 
93 static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
94 						u32 mask, u32 val)
95 {
96 	u32 reg;
97 
98 	reg = readl_relaxed(base + offset);
99 	reg &= ~mask;
100 	reg |= val & mask;
101 	writel_relaxed(reg, base + offset);
102 
103 	/* Ensure above write is completed */
104 	readl_relaxed(base + offset);
105 }
106 
107 static int qcom_snps_hsphy_init(struct phy *phy)
108 {
109 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
110 	int ret;
111 
112 	dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__);
113 
114 	ret = regulator_bulk_enable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
115 	if (ret)
116 		return ret;
117 
118 	ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
119 	if (ret) {
120 		dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
121 		goto poweroff_phy;
122 	}
123 
124 	ret = reset_control_assert(hsphy->phy_reset);
125 	if (ret) {
126 		dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
127 		goto disable_ahb_clk;
128 	}
129 
130 	usleep_range(100, 150);
131 
132 	ret = reset_control_deassert(hsphy->phy_reset);
133 	if (ret) {
134 		dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
135 		goto disable_ahb_clk;
136 	}
137 
138 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
139 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
140 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
141 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
142 							POR, POR);
143 	qcom_snps_hsphy_write_mask(hsphy->base,
144 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
145 					FSEL_MASK, 0);
146 	qcom_snps_hsphy_write_mask(hsphy->base,
147 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
148 					PLLBTUNE, PLLBTUNE);
149 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_REFCLK_CTRL,
150 					REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK);
151 	qcom_snps_hsphy_write_mask(hsphy->base,
152 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
153 					VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
154 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
155 					VBUSVLDEXT0, VBUSVLDEXT0);
156 
157 	qcom_snps_hsphy_write_mask(hsphy->base,
158 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
159 					VREGBYPASS, VREGBYPASS);
160 
161 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
162 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
163 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
164 
165 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
166 					SLEEPM, SLEEPM);
167 
168 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
169 					POR, 0);
170 
171 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
172 					USB2_SUSPEND_N_SEL, 0);
173 
174 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
175 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0);
176 
177 	hsphy->phy_initialized = true;
178 
179 	return 0;
180 
181 disable_ahb_clk:
182 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
183 poweroff_phy:
184 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
185 
186 	return ret;
187 }
188 
189 static int qcom_snps_hsphy_exit(struct phy *phy)
190 {
191 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
192 
193 	reset_control_assert(hsphy->phy_reset);
194 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
195 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
196 	hsphy->phy_initialized = false;
197 
198 	return 0;
199 }
200 
201 static const struct phy_ops qcom_snps_hsphy_gen_ops = {
202 	.init		= qcom_snps_hsphy_init,
203 	.exit		= qcom_snps_hsphy_exit,
204 	.owner		= THIS_MODULE,
205 };
206 
207 static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
208 	{ .compatible	= "qcom,sm8150-usb-hs-phy", },
209 	{ .compatible	= "qcom,usb-snps-hs-7nm-phy", },
210 	{ .compatible	= "qcom,usb-snps-femto-v2-phy",	},
211 	{ }
212 };
213 MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table);
214 
215 static int qcom_snps_hsphy_probe(struct platform_device *pdev)
216 {
217 	struct device *dev = &pdev->dev;
218 	struct qcom_snps_hsphy *hsphy;
219 	struct phy_provider *phy_provider;
220 	struct phy *generic_phy;
221 	int ret, i;
222 	int num;
223 
224 	hsphy = devm_kzalloc(dev, sizeof(*hsphy), GFP_KERNEL);
225 	if (!hsphy)
226 		return -ENOMEM;
227 
228 	hsphy->base = devm_platform_ioremap_resource(pdev, 0);
229 	if (IS_ERR(hsphy->base))
230 		return PTR_ERR(hsphy->base);
231 
232 	hsphy->ref_clk = devm_clk_get(dev, "ref");
233 	if (IS_ERR(hsphy->ref_clk)) {
234 		ret = PTR_ERR(hsphy->ref_clk);
235 		if (ret != -EPROBE_DEFER)
236 			dev_err(dev, "failed to get ref clk, %d\n", ret);
237 		return ret;
238 	}
239 
240 	hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
241 	if (IS_ERR(hsphy->phy_reset)) {
242 		dev_err(dev, "failed to get phy core reset\n");
243 		return PTR_ERR(hsphy->phy_reset);
244 	}
245 
246 	num = ARRAY_SIZE(hsphy->vregs);
247 	for (i = 0; i < num; i++)
248 		hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i];
249 
250 	ret = devm_regulator_bulk_get(dev, num, hsphy->vregs);
251 	if (ret) {
252 		if (ret != -EPROBE_DEFER)
253 			dev_err(dev, "failed to get regulator supplies: %d\n",
254 				ret);
255 		return ret;
256 	}
257 
258 	generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
259 	if (IS_ERR(generic_phy)) {
260 		ret = PTR_ERR(generic_phy);
261 		dev_err(dev, "failed to create phy, %d\n", ret);
262 		return ret;
263 	}
264 	hsphy->phy = generic_phy;
265 
266 	dev_set_drvdata(dev, hsphy);
267 	phy_set_drvdata(generic_phy, hsphy);
268 
269 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
270 	if (!IS_ERR(phy_provider))
271 		dev_dbg(dev, "Registered Qcom-SNPS HS phy\n");
272 
273 	return PTR_ERR_OR_ZERO(phy_provider);
274 }
275 
276 static struct platform_driver qcom_snps_hsphy_driver = {
277 	.probe		= qcom_snps_hsphy_probe,
278 	.driver = {
279 		.name	= "qcom-snps-hs-femto-v2-phy",
280 		.of_match_table = qcom_snps_hsphy_of_match_table,
281 	},
282 };
283 
284 module_platform_driver(qcom_snps_hsphy_driver);
285 
286 MODULE_DESCRIPTION("Qualcomm SNPS FEMTO USB HS PHY V2 driver");
287 MODULE_LICENSE("GPL v2");
288