Merge https://gitlab.denx.de/u-boot/custodians/u-boot-sunxi
[oweals/u-boot.git] / drivers / phy / phy-rcar-gen2.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Renesas RCar Gen2 USB PHY driver
4  *
5  * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
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>
14 #include <reset.h>
15 #include <syscon.h>
16 #include <usb.h>
17 #include <asm/io.h>
18 #include <linux/bitops.h>
19 #include <power/regulator.h>
20
21 #define USBHS_LPSTS                     0x02
22 #define USBHS_UGCTRL                    0x80
23 #define USBHS_UGCTRL2                   0x84
24 #define USBHS_UGSTS                     0x88    /* From technical update */
25
26 /* Low Power Status register (LPSTS) */
27 #define USBHS_LPSTS_SUSPM               0x4000
28
29 /* USB General control register (UGCTRL) */
30 #define USBHS_UGCTRL_CONNECT            BIT(2)
31 #define USBHS_UGCTRL_PLLRESET           BIT(0)
32
33 /* USB General control register 2 (UGCTRL2) */
34 #define USBHS_UGCTRL2_USB2SEL           0x80000000
35 #define USBHS_UGCTRL2_USB2SEL_PCI       0x00000000
36 #define USBHS_UGCTRL2_USB2SEL_USB30     0x80000000
37 #define USBHS_UGCTRL2_USB0SEL           0x00000030
38 #define USBHS_UGCTRL2_USB0SEL_PCI       0x00000010
39 #define USBHS_UGCTRL2_USB0SEL_HS_USB    0x00000030
40
41 /* USB General status register (UGSTS) */
42 #define USBHS_UGSTS_LOCK                0x00000100 /* From technical update */
43
44 #define PHYS_PER_CHANNEL        2
45
46 struct rcar_gen2_phy {
47         fdt_addr_t      regs;
48         struct clk      clk;
49 };
50
51 static int rcar_gen2_phy_phy_init(struct phy *phy)
52 {
53         struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
54         u16 chan = phy->id & 0xffff;
55         u16 mode = (phy->id >> 16) & 0xffff;
56         u32 clrmask, setmask;
57
58         if (chan == 0) {
59                 clrmask = USBHS_UGCTRL2_USB0SEL;
60                 setmask = mode ? USBHS_UGCTRL2_USB0SEL_HS_USB :
61                                  USBHS_UGCTRL2_USB0SEL_PCI;
62         } else {
63                 clrmask = USBHS_UGCTRL2_USB2SEL;
64                 setmask = mode ? USBHS_UGCTRL2_USB2SEL_USB30 :
65                                  USBHS_UGCTRL2_USB2SEL_PCI;
66         }
67         clrsetbits_le32(priv->regs + USBHS_UGCTRL2, clrmask, setmask);
68
69         return 0;
70 }
71
72 static int rcar_gen2_phy_phy_power_on(struct phy *phy)
73 {
74         struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
75         int i;
76         u32 value;
77
78         /* Power on USBHS PHY */
79         clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
80
81         setbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
82
83         for (i = 0; i < 20; i++) {
84                 value = readl(priv->regs + USBHS_UGSTS);
85                 if ((value & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) {
86                         setbits_le32(priv->regs + USBHS_UGCTRL,
87                                      USBHS_UGCTRL_CONNECT);
88                         return 0;
89                 }
90                 udelay(1);
91         }
92
93         return -ETIMEDOUT;
94 }
95
96 static int rcar_gen2_phy_phy_power_off(struct phy *phy)
97 {
98         struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
99
100         /* Power off USBHS PHY */
101         clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_CONNECT);
102
103         clrbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
104
105         setbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
106
107         return 0;
108 }
109
110 static int rcar_gen2_phy_of_xlate(struct phy *phy,
111                                   struct ofnode_phandle_args *args)
112 {
113         if (args->args_count != 2) {
114                 dev_err(phy->dev, "Invalid DT PHY argument count: %d\n",
115                         args->args_count);
116                 return -EINVAL;
117         }
118
119         if (args->args[0] != 0 && args->args[0] != 2) {
120                 dev_err(phy->dev, "Invalid DT PHY channel: %d\n",
121                         args->args[0]);
122                 return -EINVAL;
123         }
124
125         if (args->args[1] != 0 && args->args[1] != 1) {
126                 dev_err(phy->dev, "Invalid DT PHY mode: %d\n",
127                         args->args[1]);
128                 return -EINVAL;
129         }
130
131         if (args->args_count)
132                 phy->id = args->args[0] | (args->args[1] << 16);
133         else
134                 phy->id = 0;
135
136         return 0;
137 }
138
139 static const struct phy_ops rcar_gen2_phy_phy_ops = {
140         .init           = rcar_gen2_phy_phy_init,
141         .power_on       = rcar_gen2_phy_phy_power_on,
142         .power_off      = rcar_gen2_phy_phy_power_off,
143         .of_xlate       = rcar_gen2_phy_of_xlate,
144 };
145
146 static int rcar_gen2_phy_probe(struct udevice *dev)
147 {
148         struct rcar_gen2_phy *priv = dev_get_priv(dev);
149         int ret;
150
151         priv->regs = dev_read_addr(dev);
152         if (priv->regs == FDT_ADDR_T_NONE)
153                 return -EINVAL;
154
155         /* Enable clock */
156         ret = clk_get_by_index(dev, 0, &priv->clk);
157         if (ret)
158                 return ret;
159
160         ret = clk_enable(&priv->clk);
161         if (ret)
162                 return ret;
163
164         return 0;
165 }
166
167 static int rcar_gen2_phy_remove(struct udevice *dev)
168 {
169         struct rcar_gen2_phy *priv = dev_get_priv(dev);
170
171         clk_disable(&priv->clk);
172         clk_free(&priv->clk);
173
174         return 0;
175 }
176
177 static const struct udevice_id rcar_gen2_phy_of_match[] = {
178         { .compatible = "renesas,rcar-gen2-usb-phy", },
179         { },
180 };
181
182 U_BOOT_DRIVER(rcar_gen2_phy) = {
183         .name           = "rcar-gen2-phy",
184         .id             = UCLASS_PHY,
185         .of_match       = rcar_gen2_phy_of_match,
186         .ops            = &rcar_gen2_phy_phy_ops,
187         .probe          = rcar_gen2_phy_probe,
188         .remove         = rcar_gen2_phy_remove,
189         .priv_auto_alloc_size = sizeof(struct rcar_gen2_phy),
190 };