1 // SPDX-License-Identifier: GPL-2.0
3 * Meson GXL USB3 PHY and OTG mode detection driver
5 * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
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>
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)
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)
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)
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)
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)
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)
78 /* read-only register */
80 #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
81 #define USB_R6_P30_CR_ACK BIT(16)
83 struct phy_meson_gxl_usb3_priv
{
84 struct regmap
*regmap
;
87 struct clk
*clk_peripheral
;
88 struct reset_control
*reset
;
91 static const struct regmap_config phy_meson_gxl_usb3_regmap_conf
= {
95 .max_register
= USB_R6
,
98 static int phy_meson_gxl_usb3_power_on(struct phy
*phy
)
100 struct phy_meson_gxl_usb3_priv
*priv
= phy_get_drvdata(phy
);
102 regmap_update_bits(priv
->regmap
, USB_R5
, USB_R5_ID_DIG_EN_0
,
104 regmap_update_bits(priv
->regmap
, USB_R5
, 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));
112 static int phy_meson_gxl_usb3_power_off(struct phy
*phy
)
114 struct phy_meson_gxl_usb3_priv
*priv
= phy_get_drvdata(phy
);
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);
122 static int phy_meson_gxl_usb3_set_mode(struct phy
*phy
,
123 enum phy_mode mode
, int submode
)
125 struct phy_meson_gxl_usb3_priv
*priv
= phy_get_drvdata(phy
);
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
,
134 case PHY_MODE_USB_DEVICE
:
135 regmap_update_bits(priv
->regmap
, USB_R0
, USB_R0_U2D_ACT
,
137 regmap_update_bits(priv
->regmap
, USB_R4
, USB_R4_P21_SLEEP_M0
,
138 USB_R4_P21_SLEEP_M0
);
142 dev_err(&phy
->dev
, "unsupported PHY mode %d\n", mode
);
151 static int phy_meson_gxl_usb3_init(struct phy
*phy
)
153 struct phy_meson_gxl_usb3_priv
*priv
= phy_get_drvdata(phy
);
156 ret
= reset_control_reset(priv
->reset
);
160 ret
= clk_prepare_enable(priv
->clk_phy
);
164 ret
= clk_prepare_enable(priv
->clk_peripheral
);
166 goto err_disable_clk_phy
;
168 ret
= phy_meson_gxl_usb3_set_mode(phy
, priv
->mode
, 0);
170 goto err_disable_clk_peripheral
;
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));
178 err_disable_clk_peripheral
:
179 clk_disable_unprepare(priv
->clk_peripheral
);
181 clk_disable_unprepare(priv
->clk_phy
);
186 static int phy_meson_gxl_usb3_exit(struct phy
*phy
)
188 struct phy_meson_gxl_usb3_priv
*priv
= phy_get_drvdata(phy
);
190 clk_disable_unprepare(priv
->clk_peripheral
);
191 clk_disable_unprepare(priv
->clk_phy
);
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
,
205 static int phy_meson_gxl_usb3_probe(struct platform_device
*pdev
)
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
;
212 struct phy_provider
*phy_provider
;
216 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
220 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
221 base
= devm_ioremap_resource(dev
, res
);
223 return PTR_ERR(base
);
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
);
230 priv
->clk_phy
= devm_clk_get(dev
, "phy");
231 if (IS_ERR(priv
->clk_phy
))
232 return PTR_ERR(priv
->clk_phy
);
234 priv
->clk_peripheral
= devm_clk_get(dev
, "peripheral");
235 if (IS_ERR(priv
->clk_peripheral
))
236 return PTR_ERR(priv
->clk_peripheral
);
238 priv
->reset
= devm_reset_control_array_get_shared(dev
);
239 if (IS_ERR(priv
->reset
))
240 return PTR_ERR(priv
->reset
);
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.
248 priv
->mode
= PHY_MODE_USB_HOST
;
250 phy
= devm_phy_create(dev
, np
, &phy_meson_gxl_usb3_ops
);
253 if (ret
!= -EPROBE_DEFER
)
254 dev_err(dev
, "failed to create PHY\n");
259 phy_set_drvdata(phy
, priv
);
261 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
263 return PTR_ERR_OR_ZERO(phy_provider
);
266 static const struct of_device_id phy_meson_gxl_usb3_of_match
[] = {
267 { .compatible
= "amlogic,meson-gxl-usb3-phy", },
270 MODULE_DEVICE_TABLE(of
, phy_meson_gxl_usb3_of_match
);
272 static struct platform_driver phy_meson_gxl_usb3_driver
= {
273 .probe
= phy_meson_gxl_usb3_probe
,
275 .name
= "phy-meson-gxl-usb3",
276 .of_match_table
= phy_meson_gxl_usb3_of_match
,
279 module_platform_driver(phy_meson_gxl_usb3_driver
);
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");