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