blob: 1d65b0b08f760778f7513aaa3588d001c48e3a75 [file] [log] [blame]
Kunihiko Hayashid6104332023-02-20 14:50:32 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * phy_uniphier_usb3.c - Socionext UniPhier Usb3 PHY driver
4 * Copyright 2019-2023 Socionext, Inc.
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <generic-phy.h>
10
11#include <clk.h>
12#include <reset.h>
13
14struct uniphier_usb3phy_priv {
15 struct clk *clk_link, *clk_phy, *clk_parent, *clk_phyext;
16 struct reset_ctl *rst_link, *rst_phy, *rst_parent;
17};
18
19static int uniphier_usb3phy_init(struct phy *phy)
20{
21 struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev);
22 int ret;
23
24 ret = clk_enable(priv->clk_phy);
25 if (ret)
26 return ret;
27
28 ret = reset_deassert(priv->rst_phy);
29 if (ret)
30 goto out_clk;
31
32 if (priv->clk_phyext) {
33 ret = clk_enable(priv->clk_phyext);
34 if (ret)
35 goto out_rst;
36 }
37
38 return 0;
39
40out_rst:
41 reset_assert(priv->rst_phy);
42out_clk:
43 clk_disable(priv->clk_phy);
44
45 return ret;
46}
47
48static int uniphier_usb3phy_exit(struct phy *phy)
49{
50 struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev);
51
52 if (priv->clk_phyext)
53 clk_disable(priv->clk_phyext);
54
55 reset_assert(priv->rst_phy);
56 clk_disable(priv->clk_phy);
57
58 return 0;
59}
60
61static int uniphier_usb3phy_probe(struct udevice *dev)
62{
63 struct uniphier_usb3phy_priv *priv = dev_get_priv(dev);
64 int ret;
65
66 priv->clk_link = devm_clk_get(dev, "link");
67 if (IS_ERR(priv->clk_link)) {
68 printf("Failed to get link clock\n");
69 return PTR_ERR(priv->clk_link);
70 }
71
72 priv->clk_phy = devm_clk_get(dev, "phy");
73 if (IS_ERR(priv->clk_link)) {
74 printf("Failed to get phy clock\n");
75 return PTR_ERR(priv->clk_link);
76 }
77
78 priv->clk_parent = devm_clk_get_optional(dev, "gio");
79 if (IS_ERR(priv->clk_parent)) {
80 printf("Failed to get parent clock\n");
81 return PTR_ERR(priv->clk_parent);
82 }
83
84 priv->clk_phyext = devm_clk_get_optional(dev, "phy-ext");
85 if (IS_ERR(priv->clk_phyext)) {
86 printf("Failed to get external phy clock\n");
87 return PTR_ERR(priv->clk_phyext);
88 }
89
90 priv->rst_link = devm_reset_control_get(dev, "link");
91 if (IS_ERR(priv->rst_link)) {
92 printf("Failed to get link reset\n");
93 return PTR_ERR(priv->rst_link);
94 }
95
96 priv->rst_phy = devm_reset_control_get(dev, "phy");
97 if (IS_ERR(priv->rst_phy)) {
98 printf("Failed to get phy reset\n");
99 return PTR_ERR(priv->rst_phy);
100 }
101
102 priv->rst_parent = devm_reset_control_get_optional(dev, "gio");
103 if (IS_ERR(priv->rst_parent)) {
104 printf("Failed to get parent reset\n");
105 return PTR_ERR(priv->rst_parent);
106 }
107
108 if (priv->clk_parent) {
109 ret = clk_enable(priv->clk_parent);
110 if (ret)
111 return ret;
112 }
113 if (priv->rst_parent) {
114 ret = reset_deassert(priv->rst_parent);
115 if (ret)
116 goto out_clk_parent;
117 }
118
119 ret = clk_enable(priv->clk_link);
120 if (ret)
121 goto out_rst_parent;
122
123 ret = reset_deassert(priv->rst_link);
124 if (ret)
125 goto out_clk;
126
127 return 0;
128
129out_clk:
130 clk_disable(priv->clk_link);
131out_rst_parent:
132 if (priv->rst_parent)
133 reset_assert(priv->rst_parent);
134out_clk_parent:
135 if (priv->clk_parent)
136 clk_disable(priv->clk_parent);
137
138 return ret;
139}
140
141static struct phy_ops uniphier_usb3phy_ops = {
142 .init = uniphier_usb3phy_init,
143 .exit = uniphier_usb3phy_exit,
144};
145
146static const struct udevice_id uniphier_usb3phy_ids[] = {
147 { .compatible = "socionext,uniphier-pro4-usb3-ssphy" },
148 { .compatible = "socionext,uniphier-pro5-usb3-hsphy" },
149 { .compatible = "socionext,uniphier-pro5-usb3-ssphy" },
150 { .compatible = "socionext,uniphier-pxs2-usb3-hsphy" },
151 { .compatible = "socionext,uniphier-pxs2-usb3-ssphy" },
152 { .compatible = "socionext,uniphier-ld20-usb3-hsphy" },
153 { .compatible = "socionext,uniphier-ld20-usb3-ssphy" },
154 { .compatible = "socionext,uniphier-pxs3-usb3-hsphy" },
155 { .compatible = "socionext,uniphier-pxs3-usb3-ssphy" },
156 { .compatible = "socionext,uniphier-nx1-usb3-hsphy" },
157 { .compatible = "socionext,uniphier-nx1-usb3-ssphy" },
158 { }
159};
160
161U_BOOT_DRIVER(uniphier_usb3_phy) = {
162 .name = "uniphier-usb3-phy",
163 .id = UCLASS_PHY,
164 .of_match = uniphier_usb3phy_ids,
165 .ops = &uniphier_usb3phy_ops,
166 .probe = uniphier_usb3phy_probe,
167 .priv_auto = sizeof(struct uniphier_usb3phy_priv),
168};