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