1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2024 Renesas Electronics Corporation
*/
#include <asm/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/device_compat.h>
#include <dm/lists.h>
#include <renesas/rzg2l-usbphy.h>
#include <reset-uclass.h>
#include <reset.h>
#define RESET 0x000
#define RESET_SEL_PLLRESET BIT(12)
#define RESET_PLLRESET BIT(8)
#define RESET_SEL_P2RESET BIT(5)
#define RESET_SEL_P1RESET BIT(4)
#define RESET_PHYRST_2 BIT(1)
#define RESET_PHYRST_1 BIT(0)
#define PHY_RESET_MASK (RESET_PHYRST_1 | RESET_PHYRST_2)
#define NUM_PORTS 2
static int rzg2l_usbphy_ctrl_assert(struct reset_ctl *reset_ctl)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(reset_ctl->dev);
u32 val;
val = readl(priv->regs + RESET);
val |= reset_ctl->id ? RESET_PHYRST_2 : RESET_PHYRST_1;
/* If both ports are in reset, we can also place the PLL into reset. */
if ((val & PHY_RESET_MASK) == PHY_RESET_MASK)
val |= RESET_PLLRESET;
writel(val, priv->regs + RESET);
return 0;
}
static int rzg2l_usbphy_ctrl_deassert(struct reset_ctl *reset_ctl)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(reset_ctl->dev);
u32 val = reset_ctl->id ? RESET_PHYRST_2 : RESET_PHYRST_1;
/* If either port is out of reset, the PLL must also be out of reset. */
val |= RESET_PLLRESET;
clrbits_le32(priv->regs + RESET, val);
return 0;
}
static int rzg2l_usbphy_ctrl_of_xlate(struct reset_ctl *reset_ctl,
struct ofnode_phandle_args *args)
{
if (args->args[0] >= NUM_PORTS)
return -EINVAL;
reset_ctl->id = args->args[0];
return 0;
}
struct reset_ops rzg2l_usbphy_ctrl_ops = {
.rst_assert = rzg2l_usbphy_ctrl_assert,
.rst_deassert = rzg2l_usbphy_ctrl_deassert,
.of_xlate = rzg2l_usbphy_ctrl_of_xlate,
};
static int rzg2l_usbphy_ctrl_probe(struct udevice *dev)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev);
struct reset_ctl rst;
int ret;
priv->regs = dev_read_addr(dev);
ret = reset_get_by_index(dev, 0, &rst);
if (ret < 0) {
dev_err(dev, "failed to get reset line: %d\n", ret);
return ret;
}
ret = reset_deassert(&rst);
if (ret < 0) {
dev_err(dev, "failed to de-assert reset line: %d\n", ret);
return ret;
}
/* put pll and phy into reset state */
setbits_le32(priv->regs + RESET,
RESET_SEL_PLLRESET | RESET_PLLRESET |
RESET_SEL_P1RESET | RESET_PHYRST_1 |
RESET_SEL_P2RESET | RESET_PHYRST_2);
return 0;
}
static const struct udevice_id rzg2l_usbphy_ctrl_ids[] = {
{ .compatible = "renesas,rzg2l-usbphy-ctrl", },
{ /* sentinel */ }
};
static int rzg2l_usbphy_ctrl_bind(struct udevice *dev)
{
struct driver *drv;
ofnode node;
int ret;
node = ofnode_find_subnode(dev_ofnode(dev), "regulator-vbus");
if (!ofnode_valid(node)) {
dev_err(dev, "Failed to find vbus regulator devicetree node\n");
return -ENOENT;
}
drv = lists_driver_lookup_name("rzg2l_usbphy_regulator");
if (!drv) {
dev_err(dev, "Failed to find vbus regulator driver\n");
return -ENOENT;
}
ret = device_bind(dev, drv, dev->name, NULL, node, NULL);
if (ret) {
dev_err(dev, "Failed to bind vbus regulator: %d\n", ret);
return ret;
}
return 0;
}
U_BOOT_DRIVER(rzg2l_usbphy_ctrl) = {
.name = "rzg2l_usbphy_ctrl",
.id = UCLASS_RESET,
.of_match = rzg2l_usbphy_ctrl_ids,
.bind = rzg2l_usbphy_ctrl_bind,
.probe = rzg2l_usbphy_ctrl_probe,
.ops = &rzg2l_usbphy_ctrl_ops,
.priv_auto = sizeof(struct rzg2l_usbphy_ctrl_priv),
};
|