• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Meson GXL USB3 PHY and OTG mode detection driver
4  *
5  * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
6  */
7 
8 #include <linux/bitfield.h>
9 #include <linux/bitops.h>
10 #include <linux/clk.h>
11 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/phy/phy.h>
14 #include <linux/regmap.h>
15 #include <linux/reset.h>
16 #include <linux/platform_device.h>
17 
18 #define USB_R0							0x00
19 	#define USB_R0_P30_FSEL_MASK				GENMASK(5, 0)
20 	#define USB_R0_P30_PHY_RESET				BIT(6)
21 	#define USB_R0_P30_TEST_POWERDOWN_HSP			BIT(7)
22 	#define USB_R0_P30_TEST_POWERDOWN_SSP			BIT(8)
23 	#define USB_R0_P30_ACJT_LEVEL_MASK			GENMASK(13, 9)
24 	#define USB_R0_P30_TX_BOOST_LEVEL_MASK			GENMASK(16, 14)
25 	#define USB_R0_P30_LANE0_TX2RX_LOOPBACK			BIT(17)
26 	#define USB_R0_P30_LANE0_EXT_PCLK_REQ			BIT(18)
27 	#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK		GENMASK(28, 19)
28 	#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK		GENMASK(30, 29)
29 	#define USB_R0_U2D_ACT					BIT(31)
30 
31 #define USB_R1							0x04
32 	#define USB_R1_U3H_BIGENDIAN_GS				BIT(0)
33 	#define USB_R1_U3H_PME_ENABLE				BIT(1)
34 	#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK		GENMASK(6, 2)
35 	#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK		GENMASK(11, 7)
36 	#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK		GENMASK(15, 12)
37 	#define USB_R1_U3H_HOST_U3_PORT_DISABLE			BIT(16)
38 	#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT	BIT(17)
39 	#define USB_R1_U3H_HOST_MSI_ENABLE			BIT(18)
40 	#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK			GENMASK(24, 19)
41 	#define USB_R1_P30_PCS_TX_SWING_FULL_MASK		GENMASK(31, 25)
42 
43 #define USB_R2							0x08
44 	#define USB_R2_P30_CR_DATA_IN_MASK			GENMASK(15, 0)
45 	#define USB_R2_P30_CR_READ				BIT(16)
46 	#define USB_R2_P30_CR_WRITE				BIT(17)
47 	#define USB_R2_P30_CR_CAP_ADDR				BIT(18)
48 	#define USB_R2_P30_CR_CAP_DATA				BIT(19)
49 	#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK		GENMASK(25, 20)
50 	#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK		GENMASK(31, 26)
51 
52 #define USB_R3							0x0c
53 	#define USB_R3_P30_SSC_ENABLE				BIT(0)
54 	#define USB_R3_P30_SSC_RANGE_MASK			GENMASK(3, 1)
55 	#define USB_R3_P30_SSC_REF_CLK_SEL_MASK			GENMASK(12, 4)
56 	#define USB_R3_P30_REF_SSP_EN				BIT(13)
57 	#define USB_R3_P30_LOS_BIAS_MASK			GENMASK(18, 16)
58 	#define USB_R3_P30_LOS_LEVEL_MASK			GENMASK(23, 19)
59 	#define USB_R3_P30_MPLL_MULTIPLIER_MASK			GENMASK(30, 24)
60 
61 #define USB_R4							0x10
62 	#define USB_R4_P21_PORT_RESET_0				BIT(0)
63 	#define USB_R4_P21_SLEEP_M0				BIT(1)
64 	#define USB_R4_MEM_PD_MASK				GENMASK(3, 2)
65 	#define USB_R4_P21_ONLY					BIT(4)
66 
67 #define USB_R5							0x14
68 	#define USB_R5_ID_DIG_SYNC				BIT(0)
69 	#define USB_R5_ID_DIG_REG				BIT(1)
70 	#define USB_R5_ID_DIG_CFG_MASK				GENMASK(3, 2)
71 	#define USB_R5_ID_DIG_EN_0				BIT(4)
72 	#define USB_R5_ID_DIG_EN_1				BIT(5)
73 	#define USB_R5_ID_DIG_CURR				BIT(6)
74 	#define USB_R5_ID_DIG_IRQ				BIT(7)
75 	#define USB_R5_ID_DIG_TH_MASK				GENMASK(15, 8)
76 	#define USB_R5_ID_DIG_CNT_MASK				GENMASK(23, 16)
77 
78 /* read-only register */
79 #define USB_R6							0x18
80 	#define USB_R6_P30_CR_DATA_OUT_MASK			GENMASK(15, 0)
81 	#define USB_R6_P30_CR_ACK				BIT(16)
82 
83 struct phy_meson_gxl_usb3_priv {
84 	struct regmap		*regmap;
85 	enum phy_mode		mode;
86 	struct clk		*clk_phy;
87 	struct clk		*clk_peripheral;
88 	struct reset_control	*reset;
89 };
90 
91 static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
92 	.reg_bits = 8,
93 	.val_bits = 32,
94 	.reg_stride = 4,
95 	.max_register = USB_R6,
96 };
97 
phy_meson_gxl_usb3_power_on(struct phy * phy)98 static int phy_meson_gxl_usb3_power_on(struct phy *phy)
99 {
100 	struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
101 
102 	regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
103 			   USB_R5_ID_DIG_EN_0);
104 	regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
105 			   USB_R5_ID_DIG_EN_1);
106 	regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
107 			   FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
108 
109 	return 0;
110 }
111 
phy_meson_gxl_usb3_power_off(struct phy * phy)112 static int phy_meson_gxl_usb3_power_off(struct phy *phy)
113 {
114 	struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
115 
116 	regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0, 0);
117 	regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1, 0);
118 
119 	return 0;
120 }
121 
phy_meson_gxl_usb3_set_mode(struct phy * phy,enum phy_mode mode,int submode)122 static int phy_meson_gxl_usb3_set_mode(struct phy *phy,
123 				       enum phy_mode mode, int submode)
124 {
125 	struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
126 
127 	switch (mode) {
128 	case PHY_MODE_USB_HOST:
129 		regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
130 		regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
131 				   0);
132 		break;
133 
134 	case PHY_MODE_USB_DEVICE:
135 		regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
136 				   USB_R0_U2D_ACT);
137 		regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
138 				   USB_R4_P21_SLEEP_M0);
139 		break;
140 
141 	default:
142 		dev_err(&phy->dev, "unsupported PHY mode %d\n", mode);
143 		return -EINVAL;
144 	}
145 
146 	priv->mode = mode;
147 
148 	return 0;
149 }
150 
phy_meson_gxl_usb3_init(struct phy * phy)151 static int phy_meson_gxl_usb3_init(struct phy *phy)
152 {
153 	struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
154 	int ret;
155 
156 	ret = reset_control_reset(priv->reset);
157 	if (ret)
158 		goto err;
159 
160 	ret = clk_prepare_enable(priv->clk_phy);
161 	if (ret)
162 		goto err;
163 
164 	ret = clk_prepare_enable(priv->clk_peripheral);
165 	if (ret)
166 		goto err_disable_clk_phy;
167 
168 	ret = phy_meson_gxl_usb3_set_mode(phy, priv->mode, 0);
169 	if (ret)
170 		goto err_disable_clk_peripheral;
171 
172 	regmap_update_bits(priv->regmap, USB_R1,
173 			   USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
174 			   FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
175 
176 	return 0;
177 
178 err_disable_clk_peripheral:
179 	clk_disable_unprepare(priv->clk_peripheral);
180 err_disable_clk_phy:
181 	clk_disable_unprepare(priv->clk_phy);
182 err:
183 	return ret;
184 }
185 
phy_meson_gxl_usb3_exit(struct phy * phy)186 static int phy_meson_gxl_usb3_exit(struct phy *phy)
187 {
188 	struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
189 
190 	clk_disable_unprepare(priv->clk_peripheral);
191 	clk_disable_unprepare(priv->clk_phy);
192 
193 	return 0;
194 }
195 
196 static const struct phy_ops phy_meson_gxl_usb3_ops = {
197 	.power_on	= phy_meson_gxl_usb3_power_on,
198 	.power_off	= phy_meson_gxl_usb3_power_off,
199 	.set_mode	= phy_meson_gxl_usb3_set_mode,
200 	.init		= phy_meson_gxl_usb3_init,
201 	.exit		= phy_meson_gxl_usb3_exit,
202 	.owner		= THIS_MODULE,
203 };
204 
phy_meson_gxl_usb3_probe(struct platform_device * pdev)205 static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
206 {
207 	struct device *dev = &pdev->dev;
208 	struct device_node *np = dev->of_node;
209 	struct phy_meson_gxl_usb3_priv *priv;
210 	struct resource *res;
211 	struct phy *phy;
212 	struct phy_provider *phy_provider;
213 	void __iomem *base;
214 	int ret;
215 
216 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
217 	if (!priv)
218 		return -ENOMEM;
219 
220 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
221 	base = devm_ioremap_resource(dev, res);
222 	if (IS_ERR(base))
223 		return PTR_ERR(base);
224 
225 	priv->regmap = devm_regmap_init_mmio(dev, base,
226 					     &phy_meson_gxl_usb3_regmap_conf);
227 	if (IS_ERR(priv->regmap))
228 		return PTR_ERR(priv->regmap);
229 
230 	priv->clk_phy = devm_clk_get(dev, "phy");
231 	if (IS_ERR(priv->clk_phy))
232 		return PTR_ERR(priv->clk_phy);
233 
234 	priv->clk_peripheral = devm_clk_get(dev, "peripheral");
235 	if (IS_ERR(priv->clk_peripheral))
236 		return PTR_ERR(priv->clk_peripheral);
237 
238 	priv->reset = devm_reset_control_array_get_shared(dev);
239 	if (IS_ERR(priv->reset))
240 		return PTR_ERR(priv->reset);
241 
242 	/*
243 	 * default to host mode as hardware defaults and/or boot-loader
244 	 * behavior can result in this PHY starting up in device mode. this
245 	 * default and the initialization in phy_meson_gxl_usb3_init ensure
246 	 * that we reproducibly start in a known mode on all devices.
247 	 */
248 	priv->mode = PHY_MODE_USB_HOST;
249 
250 	phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
251 	if (IS_ERR(phy)) {
252 		ret = PTR_ERR(phy);
253 		if (ret != -EPROBE_DEFER)
254 			dev_err(dev, "failed to create PHY\n");
255 
256 		return ret;
257 	}
258 
259 	phy_set_drvdata(phy, priv);
260 
261 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
262 
263 	return PTR_ERR_OR_ZERO(phy_provider);
264 }
265 
266 static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
267 	{ .compatible = "amlogic,meson-gxl-usb3-phy", },
268 	{ },
269 };
270 MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
271 
272 static struct platform_driver phy_meson_gxl_usb3_driver = {
273 	.probe	= phy_meson_gxl_usb3_probe,
274 	.driver	= {
275 		.name		= "phy-meson-gxl-usb3",
276 		.of_match_table	= phy_meson_gxl_usb3_of_match,
277 	},
278 };
279 module_platform_driver(phy_meson_gxl_usb3_driver);
280 
281 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
282 MODULE_DESCRIPTION("Meson GXL USB3 PHY and OTG detection driver");
283 MODULE_LICENSE("GPL v2");
284