1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Rockchip USB2.0 PHY with Naneng IP block driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2020 Fuzhou Rockchip Electronics Co., Ltd
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <dm.h>
10*4882a593Smuzhiyun #include <dm/lists.h>
11*4882a593Smuzhiyun #include <generic-phy.h>
12*4882a593Smuzhiyun #include <syscon.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun #include <asm/arch/clock.h>
15*4882a593Smuzhiyun #include <reset-uclass.h>
16*4882a593Smuzhiyun #include <power/regulator.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define U2PHY_BIT_WRITEABLE_SHIFT 16
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun struct rockchip_usb2phy;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun enum power_supply_type {
23*4882a593Smuzhiyun POWER_SUPPLY_TYPE_UNKNOWN = 0,
24*4882a593Smuzhiyun POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */
25*4882a593Smuzhiyun POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */
26*4882a593Smuzhiyun POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */
27*4882a593Smuzhiyun POWER_SUPPLY_TYPE_USB_FLOATING, /* DCP without shorting D+/D- */
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun enum rockchip_usb2phy_port_id {
31*4882a593Smuzhiyun USB2PHY_PORT_OTG,
32*4882a593Smuzhiyun USB2PHY_PORT_HOST,
33*4882a593Smuzhiyun USB2PHY_NUM_PORTS,
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun struct usb2phy_reg {
37*4882a593Smuzhiyun u32 offset;
38*4882a593Smuzhiyun u32 bitend;
39*4882a593Smuzhiyun u32 bitstart;
40*4882a593Smuzhiyun u32 disable;
41*4882a593Smuzhiyun u32 enable;
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /**
45*4882a593Smuzhiyun * struct rockchip_chg_det_reg: usb charger detect registers
46*4882a593Smuzhiyun * @chg_valid: charge valid signal.
47*4882a593Smuzhiyun * @phy_connect: PHY start handshake signal.
48*4882a593Smuzhiyun * @chg_en: charge detector enable signal.
49*4882a593Smuzhiyun * @chg_rst: charge detector reset signal, active high.
50*4882a593Smuzhiyun */
51*4882a593Smuzhiyun struct rockchip_chg_det_reg {
52*4882a593Smuzhiyun struct usb2phy_reg chg_valid;
53*4882a593Smuzhiyun struct usb2phy_reg phy_connect;
54*4882a593Smuzhiyun struct usb2phy_reg chg_en;
55*4882a593Smuzhiyun struct usb2phy_reg chg_rst;
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /**
59*4882a593Smuzhiyun * struct rockchip_usb2phy_port_cfg: usb phy port configuration.
60*4882a593Smuzhiyun * @bypass_otgsuspendm: otg-suspendm bypass control register.
61*4882a593Smuzhiyun * 0: iddig; 1: grf.
62*4882a593Smuzhiyun * @bvalidfall_det_en: vbus valid fall detection enable register.
63*4882a593Smuzhiyun * @bvalidfall_det_st: vbus valid fall detection status register.
64*4882a593Smuzhiyun * @bvalidfall_det_clr: vbus valid fall detection clear register.
65*4882a593Smuzhiyun * @bvalidrise_det_en: vbus valid rise detection enable register.
66*4882a593Smuzhiyun * @bvalidrise_det_st: vbus valid rise detection status register.
67*4882a593Smuzhiyun * @bvalidrise_det_clr: vbus valid rise detection clear register.
68*4882a593Smuzhiyun * @disconfall_det_en: host connect detection enable register.
69*4882a593Smuzhiyun * @disconfall_det_st: host connect detection status register.
70*4882a593Smuzhiyun * @disconfall_det_clr: host connect detection clear register.
71*4882a593Smuzhiyun * @disconrise_det_en: host disconnect detection enable register.
72*4882a593Smuzhiyun * @disconrise_det_st: host disconnect detection status register.
73*4882a593Smuzhiyun * @disconrise_det_clr: host disconnect detection clear register.
74*4882a593Smuzhiyun * @idfall_det_en: id fall detection enable register.
75*4882a593Smuzhiyun * @idfall_det_st: id fall detection state register.
76*4882a593Smuzhiyun * @idfall_det_clr: id fall detection clear register.
77*4882a593Smuzhiyun * @idpullup: id pin pullup or pulldown control register.
78*4882a593Smuzhiyun * @idrise_det_en: id rise detection enable register.
79*4882a593Smuzhiyun * @idrise_det_st: id rise detection state register.
80*4882a593Smuzhiyun * @idrise_det_clr: id rise detection clear register.
81*4882a593Smuzhiyun * @ls_det_en: linestate detection enable register.
82*4882a593Smuzhiyun * @ls_det_st: linestate detection state register.
83*4882a593Smuzhiyun * @ls_det_clr: linestate detection clear register.
84*4882a593Smuzhiyun * @phy_sus: phy suspend register.
85*4882a593Smuzhiyun * @utmi_bvalid: utmi vbus bvalid status register.
86*4882a593Smuzhiyun * @utmi_iddig: otg port id pin status register.
87*4882a593Smuzhiyun * @utmi_hostdet: utmi host disconnect status register.
88*4882a593Smuzhiyun */
89*4882a593Smuzhiyun struct rockchip_usb2phy_port_cfg {
90*4882a593Smuzhiyun struct usb2phy_reg bypass_otgsuspendm;
91*4882a593Smuzhiyun struct usb2phy_reg bvalidfall_det_en;
92*4882a593Smuzhiyun struct usb2phy_reg bvalidfall_det_st;
93*4882a593Smuzhiyun struct usb2phy_reg bvalidfall_det_clr;
94*4882a593Smuzhiyun struct usb2phy_reg bvalidrise_det_en;
95*4882a593Smuzhiyun struct usb2phy_reg bvalidrise_det_st;
96*4882a593Smuzhiyun struct usb2phy_reg bvalidrise_det_clr;
97*4882a593Smuzhiyun struct usb2phy_reg disconfall_det_en;
98*4882a593Smuzhiyun struct usb2phy_reg disconfall_det_st;
99*4882a593Smuzhiyun struct usb2phy_reg disconfall_det_clr;
100*4882a593Smuzhiyun struct usb2phy_reg disconrise_det_en;
101*4882a593Smuzhiyun struct usb2phy_reg disconrise_det_st;
102*4882a593Smuzhiyun struct usb2phy_reg disconrise_det_clr;
103*4882a593Smuzhiyun struct usb2phy_reg idfall_det_en;
104*4882a593Smuzhiyun struct usb2phy_reg idfall_det_st;
105*4882a593Smuzhiyun struct usb2phy_reg idfall_det_clr;
106*4882a593Smuzhiyun struct usb2phy_reg idpullup;
107*4882a593Smuzhiyun struct usb2phy_reg idrise_det_en;
108*4882a593Smuzhiyun struct usb2phy_reg idrise_det_st;
109*4882a593Smuzhiyun struct usb2phy_reg idrise_det_clr;
110*4882a593Smuzhiyun struct usb2phy_reg ls_det_en;
111*4882a593Smuzhiyun struct usb2phy_reg ls_det_st;
112*4882a593Smuzhiyun struct usb2phy_reg ls_det_clr;
113*4882a593Smuzhiyun struct usb2phy_reg phy_sus;
114*4882a593Smuzhiyun struct usb2phy_reg utmi_bvalid;
115*4882a593Smuzhiyun struct usb2phy_reg utmi_iddig;
116*4882a593Smuzhiyun struct usb2phy_reg utmi_hostdet;
117*4882a593Smuzhiyun };
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /**
120*4882a593Smuzhiyun * struct rockchip_usb2phy_cfg: usb phy configuration.
121*4882a593Smuzhiyun * @reg: the address offset of grf for usb-phy config.
122*4882a593Smuzhiyun * @num_ports: specify how many ports that the phy has.
123*4882a593Smuzhiyun * @phy_tuning: phy default parameters tuning.
124*4882a593Smuzhiyun * @clkout_ctl: keep on/turn off output clk of phy.
125*4882a593Smuzhiyun * @port_cfgs: ports register configuration, assigned by driver data.
126*4882a593Smuzhiyun * @chg_det: charger detection registers.
127*4882a593Smuzhiyun * @last: indicate the last one.
128*4882a593Smuzhiyun */
129*4882a593Smuzhiyun struct rockchip_usb2phy_cfg {
130*4882a593Smuzhiyun unsigned int reg;
131*4882a593Smuzhiyun unsigned int num_ports;
132*4882a593Smuzhiyun int (*phy_tuning)(struct rockchip_usb2phy *rphy);
133*4882a593Smuzhiyun struct usb2phy_reg clkout_ctl;
134*4882a593Smuzhiyun const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
135*4882a593Smuzhiyun const struct rockchip_chg_det_reg chg_det;
136*4882a593Smuzhiyun bool last;
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /**
140*4882a593Smuzhiyun * struct rockchip_usb2phy: usb2.0 phy driver data.
141*4882a593Smuzhiyun * @grf: General Register Files register base.
142*4882a593Smuzhiyun * @reset: power reset signal for phy.
143*4882a593Smuzhiyun * @vbus_supply: vbus supply for usb host.
144*4882a593Smuzhiyun * @phy_cfg: phy register configuration, assigned by driver data.
145*4882a593Smuzhiyun */
146*4882a593Smuzhiyun struct rockchip_usb2phy {
147*4882a593Smuzhiyun void __iomem *grf;
148*4882a593Smuzhiyun struct reset_ctl *reset;
149*4882a593Smuzhiyun struct udevice *vbus_supply[USB2PHY_NUM_PORTS];
150*4882a593Smuzhiyun const struct rockchip_usb2phy_cfg *phy_cfg;
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun
property_enable(void __iomem * base,const struct usb2phy_reg * reg,bool en)153*4882a593Smuzhiyun static inline int property_enable(void __iomem *base,
154*4882a593Smuzhiyun const struct usb2phy_reg *reg, bool en)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun u32 val, mask, tmp;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun tmp = en ? reg->enable : reg->disable;
159*4882a593Smuzhiyun mask = GENMASK(reg->bitend, reg->bitstart);
160*4882a593Smuzhiyun val = (tmp << reg->bitstart) | (mask << U2PHY_BIT_WRITEABLE_SHIFT);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun writel(val, base + reg->offset);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun return 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
property_enabled(void __iomem * base,const struct usb2phy_reg * reg)167*4882a593Smuzhiyun static inline bool property_enabled(void __iomem *base,
168*4882a593Smuzhiyun const struct usb2phy_reg *reg)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun u32 tmp, orig;
171*4882a593Smuzhiyun u32 mask = GENMASK(reg->bitend, reg->bitstart);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun orig = readl(base + reg->offset);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun tmp = (orig & mask) >> reg->bitstart;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun return tmp == reg->enable;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
chg_to_string(enum power_supply_type chg_type)180*4882a593Smuzhiyun static const char *chg_to_string(enum power_supply_type chg_type)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun switch (chg_type) {
183*4882a593Smuzhiyun case POWER_SUPPLY_TYPE_USB:
184*4882a593Smuzhiyun return "USB_SDP_CHARGER";
185*4882a593Smuzhiyun case POWER_SUPPLY_TYPE_USB_DCP:
186*4882a593Smuzhiyun return "USB_DCP_CHARGER";
187*4882a593Smuzhiyun case POWER_SUPPLY_TYPE_USB_CDP:
188*4882a593Smuzhiyun return "USB_CDP_CHARGER";
189*4882a593Smuzhiyun case POWER_SUPPLY_TYPE_USB_FLOATING:
190*4882a593Smuzhiyun return "USB_FLOATING_CHARGER";
191*4882a593Smuzhiyun default:
192*4882a593Smuzhiyun return "INVALID_CHARGER";
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
rockchip_chg_get_type(void)196*4882a593Smuzhiyun int rockchip_chg_get_type(void)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun const struct rockchip_usb2phy_port_cfg *port_cfg;
199*4882a593Smuzhiyun enum power_supply_type chg_type;
200*4882a593Smuzhiyun struct rockchip_usb2phy *rphy;
201*4882a593Smuzhiyun struct udevice *udev;
202*4882a593Smuzhiyun bool chg_valid, phy_connect;
203*4882a593Smuzhiyun int cnt;
204*4882a593Smuzhiyun int ret;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun ret = uclass_get_device_by_name(UCLASS_PHY, "usb2-phy", &udev);
207*4882a593Smuzhiyun if (ret == -ENODEV) {
208*4882a593Smuzhiyun ret = uclass_get_device_by_name(UCLASS_PHY, "usb2phy", &udev);
209*4882a593Smuzhiyun if (ret) {
210*4882a593Smuzhiyun pr_err("%s: get usb2 phy node failed: %d\n", __func__, ret);
211*4882a593Smuzhiyun return ret;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun rphy = dev_get_priv(udev);
216*4882a593Smuzhiyun port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* Check USB-Vbus status first */
219*4882a593Smuzhiyun if (!property_enabled(rphy->grf, &port_cfg->utmi_bvalid)) {
220*4882a593Smuzhiyun pr_info("%s: no charger found\n", __func__);
221*4882a593Smuzhiyun return POWER_SUPPLY_TYPE_UNKNOWN;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun reset_assert(rphy->reset);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* CHG_RST is set to 1'b0 to start charge detection */
227*4882a593Smuzhiyun property_enable(rphy->grf, &rphy->phy_cfg->chg_det.chg_en, true);
228*4882a593Smuzhiyun property_enable(rphy->grf, &rphy->phy_cfg->chg_det.chg_rst, false);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun for (cnt = 0; cnt < 12; cnt++) {
231*4882a593Smuzhiyun mdelay(100);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun chg_valid = property_enabled(rphy->grf,
234*4882a593Smuzhiyun &rphy->phy_cfg->chg_det.chg_valid);
235*4882a593Smuzhiyun phy_connect =
236*4882a593Smuzhiyun property_enabled(rphy->grf,
237*4882a593Smuzhiyun &rphy->phy_cfg->chg_det.phy_connect);
238*4882a593Smuzhiyun chg_type = (chg_valid << 1) | phy_connect;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun if (chg_type)
241*4882a593Smuzhiyun goto compeleted;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun compeleted:
245*4882a593Smuzhiyun debug("charger = %s\n", chg_to_string(chg_type));
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun mdelay(1);
248*4882a593Smuzhiyun reset_deassert(rphy->reset);
249*4882a593Smuzhiyun /* disable the chg detection module */
250*4882a593Smuzhiyun property_enable(rphy->grf, &rphy->phy_cfg->chg_det.chg_rst, true);
251*4882a593Smuzhiyun property_enable(rphy->grf, &rphy->phy_cfg->chg_det.chg_en, false);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun return chg_type;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
rockchip_u2phy_vbus_detect(void)256*4882a593Smuzhiyun int rockchip_u2phy_vbus_detect(void)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun int chg_type;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun chg_type = rockchip_chg_get_type();
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun return (chg_type == POWER_SUPPLY_TYPE_USB ||
263*4882a593Smuzhiyun chg_type == POWER_SUPPLY_TYPE_USB_CDP) ? 1 : 0;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
rockchip_usb2phy_check_vbus(struct phy * phy)266*4882a593Smuzhiyun static struct udevice *rockchip_usb2phy_check_vbus(struct phy *phy)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun struct udevice *parent = phy->dev->parent;
269*4882a593Smuzhiyun struct rockchip_usb2phy *rphy = dev_get_priv(parent);
270*4882a593Smuzhiyun const struct rockchip_usb2phy_port_cfg *port_cfg;
271*4882a593Smuzhiyun void __iomem *base = rphy->grf;
272*4882a593Smuzhiyun struct udevice *vbus = NULL;
273*4882a593Smuzhiyun bool iddig = true;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (phy->id == USB2PHY_PORT_HOST) {
276*4882a593Smuzhiyun vbus = rphy->vbus_supply[USB2PHY_PORT_HOST];
277*4882a593Smuzhiyun } else if (phy->id == USB2PHY_PORT_OTG) {
278*4882a593Smuzhiyun port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
279*4882a593Smuzhiyun if (port_cfg->utmi_iddig.offset) {
280*4882a593Smuzhiyun iddig = property_enabled(base, &port_cfg->utmi_iddig);
281*4882a593Smuzhiyun if (!iddig)
282*4882a593Smuzhiyun vbus = rphy->vbus_supply[USB2PHY_PORT_OTG];
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun return vbus;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
rockchip_usb2phy_init(struct phy * phy)289*4882a593Smuzhiyun static int rockchip_usb2phy_init(struct phy *phy)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun struct udevice *parent = phy->dev->parent;
292*4882a593Smuzhiyun struct rockchip_usb2phy *rphy = dev_get_priv(parent);
293*4882a593Smuzhiyun const struct rockchip_usb2phy_port_cfg *port_cfg;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (phy->id == USB2PHY_PORT_OTG) {
296*4882a593Smuzhiyun port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
297*4882a593Smuzhiyun } else if (phy->id == USB2PHY_PORT_HOST) {
298*4882a593Smuzhiyun port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
299*4882a593Smuzhiyun } else {
300*4882a593Smuzhiyun dev_err(phy->dev, "phy id %lu not support", phy->id);
301*4882a593Smuzhiyun return -EINVAL;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun property_enable(rphy->grf, &port_cfg->phy_sus, false);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /* waiting for the utmi_clk to become stable */
307*4882a593Smuzhiyun udelay(2000);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun return 0;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
rockchip_usb2phy_exit(struct phy * phy)312*4882a593Smuzhiyun static int rockchip_usb2phy_exit(struct phy *phy)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun struct udevice *parent = phy->dev->parent;
315*4882a593Smuzhiyun struct rockchip_usb2phy *rphy = dev_get_priv(parent);
316*4882a593Smuzhiyun const struct rockchip_usb2phy_port_cfg *port_cfg;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (phy->id == USB2PHY_PORT_OTG) {
319*4882a593Smuzhiyun port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
320*4882a593Smuzhiyun } else if (phy->id == USB2PHY_PORT_HOST) {
321*4882a593Smuzhiyun port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
322*4882a593Smuzhiyun } else {
323*4882a593Smuzhiyun dev_err(phy->dev, "phy id %lu not support", phy->id);
324*4882a593Smuzhiyun return -EINVAL;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun property_enable(rphy->grf, &port_cfg->phy_sus, true);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun return 0;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
rockchip_usb2phy_power_on(struct phy * phy)332*4882a593Smuzhiyun static int rockchip_usb2phy_power_on(struct phy *phy)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun struct udevice *vbus = NULL;
335*4882a593Smuzhiyun int ret;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun vbus = rockchip_usb2phy_check_vbus(phy);
338*4882a593Smuzhiyun if (vbus) {
339*4882a593Smuzhiyun ret = regulator_set_enable(vbus, true);
340*4882a593Smuzhiyun if (ret) {
341*4882a593Smuzhiyun pr_err("%s: Failed to en VBus supply\n", __func__);
342*4882a593Smuzhiyun return ret;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
rockchip_usb2phy_power_off(struct phy * phy)349*4882a593Smuzhiyun static int rockchip_usb2phy_power_off(struct phy *phy)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct udevice *vbus = NULL;
352*4882a593Smuzhiyun int ret;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun vbus = rockchip_usb2phy_check_vbus(phy);
355*4882a593Smuzhiyun if (vbus) {
356*4882a593Smuzhiyun ret = regulator_set_enable(vbus, false);
357*4882a593Smuzhiyun if (ret) {
358*4882a593Smuzhiyun pr_err("%s: Failed to dis VBus supply\n", __func__);
359*4882a593Smuzhiyun return ret;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
rockchip_usb2phy_of_xlate(struct phy * phy,struct ofnode_phandle_args * args)366*4882a593Smuzhiyun static int rockchip_usb2phy_of_xlate(struct phy *phy,
367*4882a593Smuzhiyun struct ofnode_phandle_args *args)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun const char *dev_name = phy->dev->name;
370*4882a593Smuzhiyun struct udevice *parent = phy->dev->parent;
371*4882a593Smuzhiyun struct rockchip_usb2phy *rphy = dev_get_priv(parent);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (!strcasecmp(dev_name, "host-port")) {
374*4882a593Smuzhiyun phy->id = USB2PHY_PORT_HOST;
375*4882a593Smuzhiyun device_get_supply_regulator(phy->dev, "phy-supply",
376*4882a593Smuzhiyun &rphy->vbus_supply[USB2PHY_PORT_HOST]);
377*4882a593Smuzhiyun } else if (!strcasecmp(dev_name, "otg-port")) {
378*4882a593Smuzhiyun phy->id = USB2PHY_PORT_OTG;
379*4882a593Smuzhiyun device_get_supply_regulator(phy->dev, "phy-supply",
380*4882a593Smuzhiyun &rphy->vbus_supply[USB2PHY_PORT_OTG]);
381*4882a593Smuzhiyun } else {
382*4882a593Smuzhiyun pr_err("%s: invalid dev name\n", __func__);
383*4882a593Smuzhiyun return -EINVAL;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun return 0;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
rockchip_usb2phy_bind(struct udevice * dev)389*4882a593Smuzhiyun static int rockchip_usb2phy_bind(struct udevice *dev)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun struct udevice *child;
392*4882a593Smuzhiyun ofnode subnode;
393*4882a593Smuzhiyun const char *node_name;
394*4882a593Smuzhiyun int ret;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun dev_for_each_subnode(subnode, dev) {
397*4882a593Smuzhiyun if (!ofnode_valid(subnode)) {
398*4882a593Smuzhiyun debug("%s: %s subnode not found", __func__, dev->name);
399*4882a593Smuzhiyun return -ENXIO;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun node_name = ofnode_get_name(subnode);
403*4882a593Smuzhiyun debug("%s: subnode %s\n", __func__, node_name);
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_port",
406*4882a593Smuzhiyun node_name, subnode, &child);
407*4882a593Smuzhiyun if (ret) {
408*4882a593Smuzhiyun pr_err("%s: '%s' cannot bind 'rockchip_usb2phy_port'\n",
409*4882a593Smuzhiyun __func__, node_name);
410*4882a593Smuzhiyun return ret;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
rockchip_usb2phy_probe(struct udevice * dev)417*4882a593Smuzhiyun static int rockchip_usb2phy_probe(struct udevice *dev)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun const struct rockchip_usb2phy_cfg *phy_cfgs;
420*4882a593Smuzhiyun struct rockchip_usb2phy *rphy = dev_get_priv(dev);
421*4882a593Smuzhiyun u32 reg, index;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun rphy->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun /* get phy power reset control */
426*4882a593Smuzhiyun if (reset_get_by_name(dev, "u2phy", rphy->reset)) {
427*4882a593Smuzhiyun pr_err("can't get phy power reset for %s", dev->name);
428*4882a593Smuzhiyun return -EINVAL;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (rphy->grf <= 0) {
432*4882a593Smuzhiyun dev_err(dev, "get syscon grf failed\n");
433*4882a593Smuzhiyun return -EINVAL;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (ofnode_read_u32(dev_ofnode(dev), "reg", ®)) {
437*4882a593Smuzhiyun dev_err(dev, "could not read reg\n");
438*4882a593Smuzhiyun return -EINVAL;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun phy_cfgs =
442*4882a593Smuzhiyun (const struct rockchip_usb2phy_cfg *)dev_get_driver_data(dev);
443*4882a593Smuzhiyun if (!phy_cfgs) {
444*4882a593Smuzhiyun dev_err(dev, "unable to get phy_cfgs\n");
445*4882a593Smuzhiyun return -EINVAL;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /* find out a proper config which can be matched with dt. */
449*4882a593Smuzhiyun index = 0;
450*4882a593Smuzhiyun do {
451*4882a593Smuzhiyun if (phy_cfgs[index].reg == reg) {
452*4882a593Smuzhiyun rphy->phy_cfg = &phy_cfgs[index];
453*4882a593Smuzhiyun break;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun } while (!phy_cfgs[index++].last);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun if (!rphy->phy_cfg) {
458*4882a593Smuzhiyun dev_err(dev, "no phy-config can be matched\n");
459*4882a593Smuzhiyun return -EINVAL;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun if (rphy->phy_cfg->phy_tuning)
463*4882a593Smuzhiyun rphy->phy_cfg->phy_tuning(rphy);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun return 0;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
rv1126_usb2phy_tuning(struct rockchip_usb2phy * rphy)468*4882a593Smuzhiyun static int rv1126_usb2phy_tuning(struct rockchip_usb2phy *rphy)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun return 0;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun static struct phy_ops rockchip_usb2phy_ops = {
474*4882a593Smuzhiyun .init = rockchip_usb2phy_init,
475*4882a593Smuzhiyun .exit = rockchip_usb2phy_exit,
476*4882a593Smuzhiyun .power_on = rockchip_usb2phy_power_on,
477*4882a593Smuzhiyun .power_off = rockchip_usb2phy_power_off,
478*4882a593Smuzhiyun .of_xlate = rockchip_usb2phy_of_xlate,
479*4882a593Smuzhiyun };
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun static const struct rockchip_usb2phy_cfg rv1126_phy_cfgs[] = {
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun .reg = 0xff4c0000,
484*4882a593Smuzhiyun .num_ports = 1,
485*4882a593Smuzhiyun .phy_tuning = rv1126_usb2phy_tuning,
486*4882a593Smuzhiyun .clkout_ctl = { 0x10230, 14, 14, 0, 1 },
487*4882a593Smuzhiyun .port_cfgs = {
488*4882a593Smuzhiyun [USB2PHY_PORT_OTG] = {
489*4882a593Smuzhiyun .bypass_otgsuspendm = { 0x10234, 12, 12, 0, 1 },
490*4882a593Smuzhiyun .bvalidfall_det_en = { 0x10300, 3, 3, 0, 1 },
491*4882a593Smuzhiyun .bvalidfall_det_st = { 0x10304, 3, 3, 0, 1 },
492*4882a593Smuzhiyun .bvalidfall_det_clr = { 0x10308, 3, 3, 0, 1 },
493*4882a593Smuzhiyun .bvalidrise_det_en = { 0x10300, 2, 2, 0, 1 },
494*4882a593Smuzhiyun .bvalidrise_det_st = { 0x10304, 2, 2, 0, 1 },
495*4882a593Smuzhiyun .bvalidrise_det_clr = { 0x10308, 2, 2, 0, 1 },
496*4882a593Smuzhiyun .disconfall_det_en = { 0x10300, 7, 7, 0, 1 },
497*4882a593Smuzhiyun .disconfall_det_st = { 0x10304, 7, 7, 0, 1 },
498*4882a593Smuzhiyun .disconfall_det_clr = { 0x10308, 7, 7, 0, 1 },
499*4882a593Smuzhiyun .disconrise_det_en = { 0x10300, 6, 6, 0, 1 },
500*4882a593Smuzhiyun .disconrise_det_st = { 0x10304, 6, 6, 0, 1 },
501*4882a593Smuzhiyun .disconrise_det_clr = { 0x10308, 6, 6, 0, 1 },
502*4882a593Smuzhiyun .idfall_det_en = { 0x10300, 5, 5, 0, 1 },
503*4882a593Smuzhiyun .idfall_det_st = { 0x10304, 5, 5, 0, 1 },
504*4882a593Smuzhiyun .idfall_det_clr = { 0x10308, 5, 5, 0, 1 },
505*4882a593Smuzhiyun .idpullup = { 0x10230, 11, 11, 0, 1 },
506*4882a593Smuzhiyun .idrise_det_en = { 0x10300, 4, 4, 0, 1 },
507*4882a593Smuzhiyun .idrise_det_st = { 0x10304, 4, 4, 0, 1 },
508*4882a593Smuzhiyun .idrise_det_clr = { 0x10308, 4, 4, 0, 1 },
509*4882a593Smuzhiyun .ls_det_en = { 0x10300, 0, 0, 0, 1 },
510*4882a593Smuzhiyun .ls_det_st = { 0x10304, 0, 0, 0, 1 },
511*4882a593Smuzhiyun .ls_det_clr = { 0x10308, 0, 0, 0, 1 },
512*4882a593Smuzhiyun .phy_sus = { 0x10230, 8, 0, 0x052, 0x1d9 },
513*4882a593Smuzhiyun .utmi_bvalid = { 0x10248, 9, 9, 0, 1 },
514*4882a593Smuzhiyun .utmi_iddig = { 0x10248, 6, 6, 0, 1 },
515*4882a593Smuzhiyun .utmi_hostdet = { 0x10248, 7, 7, 0, 1 },
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun },
518*4882a593Smuzhiyun .chg_det = {
519*4882a593Smuzhiyun .chg_en = { 0x10234, 14, 14, 0, 1 },
520*4882a593Smuzhiyun .chg_rst = { 0x10234, 15, 15, 0, 1 },
521*4882a593Smuzhiyun .chg_valid = { 0x10248, 12, 12, 0, 1 },
522*4882a593Smuzhiyun .phy_connect = { 0x10248, 13, 13, 0, 1 },
523*4882a593Smuzhiyun },
524*4882a593Smuzhiyun },
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun .reg = 0xff4c8000,
527*4882a593Smuzhiyun .num_ports = 1,
528*4882a593Smuzhiyun .phy_tuning = rv1126_usb2phy_tuning,
529*4882a593Smuzhiyun .clkout_ctl = { 0x10238, 9, 9, 0, 1 },
530*4882a593Smuzhiyun .port_cfgs = {
531*4882a593Smuzhiyun [USB2PHY_PORT_HOST] = {
532*4882a593Smuzhiyun .disconfall_det_en = { 0x10300, 9, 9, 0, 1 },
533*4882a593Smuzhiyun .disconfall_det_st = { 0x10304, 9, 9, 0, 1 },
534*4882a593Smuzhiyun .disconfall_det_clr = { 0x10308, 9, 9, 0, 1 },
535*4882a593Smuzhiyun .disconrise_det_en = { 0x10300, 8, 8, 0, 1 },
536*4882a593Smuzhiyun .disconrise_det_st = { 0x10304, 8, 8, 0, 1 },
537*4882a593Smuzhiyun .disconrise_det_clr = { 0x10308, 8, 8, 0, 1 },
538*4882a593Smuzhiyun .ls_det_en = { 0x10300, 1, 1, 0, 1 },
539*4882a593Smuzhiyun .ls_det_st = { 0x10304, 1, 1, 0, 1 },
540*4882a593Smuzhiyun .ls_det_clr = { 0x10308, 1, 1, 0, 1 },
541*4882a593Smuzhiyun .phy_sus = { 0x10238, 3, 0, 0x2, 0x9 },
542*4882a593Smuzhiyun .utmi_hostdet = { 0x10248, 23, 23, 0, 1 },
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun },
545*4882a593Smuzhiyun .chg_det = {
546*4882a593Smuzhiyun .chg_en = { 0x10238, 7, 7, 0, 1 },
547*4882a593Smuzhiyun .chg_rst = { 0x10238, 8, 8, 0, 1 },
548*4882a593Smuzhiyun .chg_valid = { 0x10248, 28, 28, 0, 1 },
549*4882a593Smuzhiyun .phy_connect = { 0x10248, 29, 29, 0, 1 },
550*4882a593Smuzhiyun },
551*4882a593Smuzhiyun .last = true,
552*4882a593Smuzhiyun },
553*4882a593Smuzhiyun };
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun static const struct udevice_id rockchip_usb2phy_ids[] = {
556*4882a593Smuzhiyun { .compatible = "rockchip,rv1126-usb2phy", .data = (ulong)&rv1126_phy_cfgs },
557*4882a593Smuzhiyun { }
558*4882a593Smuzhiyun };
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun U_BOOT_DRIVER(rockchip_usb2phy_port) = {
561*4882a593Smuzhiyun .name = "rockchip_usb2phy_port",
562*4882a593Smuzhiyun .id = UCLASS_PHY,
563*4882a593Smuzhiyun .ops = &rockchip_usb2phy_ops,
564*4882a593Smuzhiyun };
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun U_BOOT_DRIVER(rockchip_usb2phy) = {
567*4882a593Smuzhiyun .name = "rockchip_usb2phy",
568*4882a593Smuzhiyun .id = UCLASS_PHY,
569*4882a593Smuzhiyun .of_match = rockchip_usb2phy_ids,
570*4882a593Smuzhiyun .probe = rockchip_usb2phy_probe,
571*4882a593Smuzhiyun .bind = rockchip_usb2phy_bind,
572*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct rockchip_usb2phy),
573*4882a593Smuzhiyun };
574