]>
Commit | Line | Data |
---|---|---|
6cfc3d66 MV |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Renesas RCar Gen3 USB PHY driver | |
4 | * | |
5 | * Copyright (C) 2018 Marek Vasut <[email protected]> | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <clk.h> | |
10 | #include <div64.h> | |
11 | #include <dm.h> | |
12 | #include <fdtdec.h> | |
13 | #include <generic-phy.h> | |
336d4615 | 14 | #include <malloc.h> |
6cfc3d66 MV |
15 | #include <reset.h> |
16 | #include <syscon.h> | |
17 | #include <usb.h> | |
18 | #include <asm/io.h> | |
19 | #include <linux/bitops.h> | |
20 | #include <power/regulator.h> | |
21 | ||
22 | /* USB2.0 Host registers (original offset is +0x200) */ | |
23 | #define USB2_INT_ENABLE 0x000 | |
24 | #define USB2_USBCTR 0x00c | |
25 | #define USB2_SPD_RSM_TIMSET 0x10c | |
26 | #define USB2_OC_TIMSET 0x110 | |
27 | #define USB2_COMMCTRL 0x600 | |
28 | #define USB2_OBINTSTA 0x604 | |
29 | #define USB2_OBINTEN 0x608 | |
30 | #define USB2_VBCTRL 0x60c | |
31 | #define USB2_LINECTRL1 0x610 | |
32 | #define USB2_ADPCTRL 0x630 | |
33 | ||
34 | /* USBCTR */ | |
35 | #define USB2_USBCTR_PLL_RST BIT(1) | |
36 | ||
37 | /* SPD_RSM_TIMSET */ | |
38 | #define USB2_SPD_RSM_TIMSET_INIT 0x014e029b | |
39 | ||
40 | /* OC_TIMSET */ | |
41 | #define USB2_OC_TIMSET_INIT 0x000209ab | |
42 | ||
43 | /* COMMCTRL */ | |
44 | #define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */ | |
45 | ||
46 | /* LINECTRL1 */ | |
47 | #define USB2_LINECTRL1_DP_RPD BIT(18) | |
48 | #define USB2_LINECTRL1_DM_RPD BIT(16) | |
49 | ||
50 | /* ADPCTRL */ | |
51 | #define USB2_ADPCTRL_DRVVBUS BIT(4) | |
52 | ||
53 | struct rcar_gen3_phy { | |
54 | fdt_addr_t regs; | |
55 | struct clk clk; | |
56 | struct udevice *vbus_supply; | |
57 | }; | |
58 | ||
59 | static int rcar_gen3_phy_phy_init(struct phy *phy) | |
60 | { | |
61 | struct rcar_gen3_phy *priv = dev_get_priv(phy->dev); | |
62 | ||
63 | /* Initialize USB2 part */ | |
64 | writel(0, priv->regs + USB2_INT_ENABLE); | |
65 | writel(USB2_SPD_RSM_TIMSET_INIT, priv->regs + USB2_SPD_RSM_TIMSET); | |
66 | writel(USB2_OC_TIMSET_INIT, priv->regs + USB2_OC_TIMSET); | |
67 | ||
68 | setbits_le32(priv->regs + USB2_LINECTRL1, | |
69 | USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); | |
70 | ||
71 | clrbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI); | |
72 | ||
73 | setbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS); | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
78 | static int rcar_gen3_phy_phy_power_on(struct phy *phy) | |
79 | { | |
80 | struct rcar_gen3_phy *priv = dev_get_priv(phy->dev); | |
81 | int ret; | |
82 | ||
83 | if (priv->vbus_supply) { | |
84 | ret = regulator_set_enable(priv->vbus_supply, true); | |
85 | if (ret) | |
86 | return ret; | |
87 | } | |
88 | ||
89 | setbits_le32(priv->regs + USB2_USBCTR, USB2_USBCTR_PLL_RST); | |
90 | clrbits_le32(priv->regs + USB2_USBCTR, USB2_USBCTR_PLL_RST); | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | static int rcar_gen3_phy_phy_power_off(struct phy *phy) | |
96 | { | |
97 | struct rcar_gen3_phy *priv = dev_get_priv(phy->dev); | |
98 | ||
99 | if (!priv->vbus_supply) | |
100 | return 0; | |
101 | ||
102 | return regulator_set_enable(priv->vbus_supply, false); | |
103 | } | |
104 | ||
105 | static const struct phy_ops rcar_gen3_phy_phy_ops = { | |
106 | .init = rcar_gen3_phy_phy_init, | |
107 | .power_on = rcar_gen3_phy_phy_power_on, | |
108 | .power_off = rcar_gen3_phy_phy_power_off, | |
109 | }; | |
110 | ||
111 | static int rcar_gen3_phy_probe(struct udevice *dev) | |
112 | { | |
113 | struct rcar_gen3_phy *priv = dev_get_priv(dev); | |
114 | int ret; | |
115 | ||
116 | priv->regs = dev_read_addr(dev); | |
117 | if (priv->regs == FDT_ADDR_T_NONE) | |
118 | return -EINVAL; | |
119 | ||
120 | ret = device_get_supply_regulator(dev, "vbus-supply", | |
121 | &priv->vbus_supply); | |
122 | if (ret && ret != -ENOENT) { | |
123 | pr_err("Failed to get PHY regulator\n"); | |
124 | return ret; | |
125 | } | |
126 | ||
127 | /* Enable clock */ | |
128 | ret = clk_get_by_index(dev, 0, &priv->clk); | |
129 | if (ret) | |
130 | return ret; | |
131 | ||
132 | ret = clk_enable(&priv->clk); | |
133 | if (ret) | |
134 | return ret; | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | static int rcar_gen3_phy_remove(struct udevice *dev) | |
140 | { | |
141 | struct rcar_gen3_phy *priv = dev_get_priv(dev); | |
142 | ||
143 | clk_disable(&priv->clk); | |
144 | clk_free(&priv->clk); | |
145 | ||
146 | return 0; | |
147 | } | |
148 | ||
149 | static const struct udevice_id rcar_gen3_phy_of_match[] = { | |
150 | { .compatible = "renesas,rcar-gen3-usb2-phy", }, | |
151 | { }, | |
152 | }; | |
153 | ||
154 | U_BOOT_DRIVER(rcar_gen3_phy) = { | |
155 | .name = "rcar-gen3-phy", | |
156 | .id = UCLASS_PHY, | |
157 | .of_match = rcar_gen3_phy_of_match, | |
158 | .ops = &rcar_gen3_phy_phy_ops, | |
159 | .probe = rcar_gen3_phy_probe, | |
160 | .remove = rcar_gen3_phy_remove, | |
161 | .priv_auto_alloc_size = sizeof(struct rcar_gen3_phy), | |
162 | }; |