blob: 59683a080cd7fa226060463a8bdedf380c9fab8e [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +02002/*
3 * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
4 * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +02005 */
6
Patrick Delaunayb953ec22021-04-27 11:02:19 +02007#define LOG_CATEGORY UCLASS_PHY
8
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +02009#include <common.h>
10#include <dm.h>
Sean Andersonbdc1fdf2020-10-04 21:39:47 -040011#include <dm/device_compat.h>
Chunfeng Yunb13307b2020-05-02 11:35:11 +020012#include <dm/devres.h>
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020013#include <generic-phy.h>
14
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020015static inline struct phy_ops *phy_dev_ops(struct udevice *dev)
16{
17 return (struct phy_ops *)dev->driver->ops;
18}
19
20static int generic_phy_xlate_offs_flags(struct phy *phy,
Simon Glass23558bb2017-05-18 20:09:47 -060021 struct ofnode_phandle_args *args)
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020022{
23 debug("%s(phy=%p)\n", __func__, phy);
24
25 if (args->args_count > 1) {
26 debug("Invaild args_count: %d\n", args->args_count);
27 return -EINVAL;
28 }
29
30 if (args->args_count)
31 phy->id = args->args[0];
32 else
33 phy->id = 0;
34
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020035 return 0;
36}
37
Jagan Teki5a2b6772020-05-01 23:44:18 +053038int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy)
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020039{
Simon Glass23558bb2017-05-18 20:09:47 -060040 struct ofnode_phandle_args args;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020041 struct phy_ops *ops;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020042 struct udevice *phydev;
Patrice Chotarda1b2fae2018-06-27 11:55:42 +020043 int i, ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020044
Neil Armstrongc2b9aa92020-03-30 11:27:23 +020045 debug("%s(node=%s, index=%d, phy=%p)\n",
46 __func__, ofnode_get_name(node), index, phy);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020047
48 assert(phy);
Patrice Chotardb9688df2017-07-18 11:38:42 +020049 phy->dev = NULL;
Neil Armstrongc2b9aa92020-03-30 11:27:23 +020050 ret = ofnode_parse_phandle_with_args(node, "phys", "#phy-cells", 0,
51 index, &args);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020052 if (ret) {
Simon Glass23558bb2017-05-18 20:09:47 -060053 debug("%s: dev_read_phandle_with_args failed: err=%d\n",
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020054 __func__, ret);
55 return ret;
56 }
57
Simon Glass23558bb2017-05-18 20:09:47 -060058 ret = uclass_get_device_by_ofnode(UCLASS_PHY, args.node, &phydev);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020059 if (ret) {
Simon Glass23558bb2017-05-18 20:09:47 -060060 debug("%s: uclass_get_device_by_ofnode failed: err=%d\n",
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020061 __func__, ret);
Patrice Chotarda1b2fae2018-06-27 11:55:42 +020062
63 /* Check if args.node's parent is a PHY provider */
64 ret = uclass_get_device_by_ofnode(UCLASS_PHY,
65 ofnode_get_parent(args.node),
66 &phydev);
67 if (ret)
68 return ret;
69
70 /* insert phy idx at first position into args array */
Marek Vasut5e50adf2018-08-07 12:24:35 +020071 for (i = args.args_count; i >= 1 ; i--)
Patrice Chotarda1b2fae2018-06-27 11:55:42 +020072 args.args[i] = args.args[i - 1];
73
74 args.args_count++;
75 args.args[0] = ofnode_read_u32_default(args.node, "reg", -1);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020076 }
77
78 phy->dev = phydev;
79
80 ops = phy_dev_ops(phydev);
81
82 if (ops->of_xlate)
83 ret = ops->of_xlate(phy, &args);
84 else
85 ret = generic_phy_xlate_offs_flags(phy, &args);
86 if (ret) {
87 debug("of_xlate() failed: %d\n", ret);
88 goto err;
89 }
90
91 return 0;
92
93err:
94 return ret;
95}
96
Neil Armstrongc2b9aa92020-03-30 11:27:23 +020097int generic_phy_get_by_index(struct udevice *dev, int index,
98 struct phy *phy)
99{
Jagan Teki5a2b6772020-05-01 23:44:18 +0530100 return generic_phy_get_by_index_nodev(dev_ofnode(dev), index, phy);
Neil Armstrongc2b9aa92020-03-30 11:27:23 +0200101}
102
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200103int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
104 struct phy *phy)
105{
106 int index;
107
108 debug("%s(dev=%p, name=%s, phy=%p)\n", __func__, dev, phy_name, phy);
109
Simon Glass23558bb2017-05-18 20:09:47 -0600110 index = dev_read_stringlist_search(dev, "phy-names", phy_name);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200111 if (index < 0) {
Simon Glass23558bb2017-05-18 20:09:47 -0600112 debug("dev_read_stringlist_search() failed: %d\n", index);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200113 return index;
114 }
115
116 return generic_phy_get_by_index(dev, index, phy);
117}
118
119int generic_phy_init(struct phy *phy)
120{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200121 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200122 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200123
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530124 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200125 return 0;
126 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200127 if (!ops->init)
128 return 0;
129 ret = ops->init(phy);
130 if (ret)
131 dev_err(phy->dev, "PHY: Failed to init %s: %d.\n",
132 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200133
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200134 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200135}
136
137int generic_phy_reset(struct phy *phy)
138{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200139 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200140 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200141
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530142 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200143 return 0;
144 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200145 if (!ops->reset)
146 return 0;
147 ret = ops->reset(phy);
148 if (ret)
149 dev_err(phy->dev, "PHY: Failed to reset %s: %d.\n",
150 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200151
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200152 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200153}
154
155int generic_phy_exit(struct phy *phy)
156{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200157 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200158 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200159
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530160 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200161 return 0;
162 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200163 if (!ops->exit)
164 return 0;
165 ret = ops->exit(phy);
166 if (ret)
167 dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n",
168 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200169
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200170 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200171}
172
173int generic_phy_power_on(struct phy *phy)
174{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200175 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200176 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200177
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530178 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200179 return 0;
180 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200181 if (!ops->power_on)
182 return 0;
183 ret = ops->power_on(phy);
184 if (ret)
185 dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n",
186 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200187
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200188 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200189}
190
191int generic_phy_power_off(struct phy *phy)
192{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200193 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200194 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200195
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530196 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200197 return 0;
198 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200199 if (!ops->power_off)
200 return 0;
201 ret = ops->power_off(phy);
202 if (ret)
203 dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n",
204 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200205
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200206 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200207}
208
Neil Armstrongf8da8a82020-12-29 14:58:59 +0100209int generic_phy_configure(struct phy *phy, void *params)
210{
211 struct phy_ops const *ops;
212
213 if (!generic_phy_valid(phy))
214 return 0;
215 ops = phy_dev_ops(phy->dev);
216
217 return ops->configure ? ops->configure(phy, params) : 0;
218}
219
Chunfeng Yunb13307b2020-05-02 11:35:11 +0200220int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
221{
222 int i, ret, count;
223
224 bulk->count = 0;
225
226 /* Return if no phy declared */
227 if (!dev_read_prop(dev, "phys", NULL))
228 return 0;
229
Patrick Delaunay89f68302020-09-25 09:41:14 +0200230 count = dev_count_phandle_with_args(dev, "phys", "#phy-cells", 0);
Chunfeng Yunb13307b2020-05-02 11:35:11 +0200231 if (count < 1)
232 return count;
233
234 bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL);
235 if (!bulk->phys)
236 return -ENOMEM;
237
238 for (i = 0; i < count; i++) {
239 ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]);
240 if (ret) {
241 pr_err("Failed to get PHY%d for %s\n", i, dev->name);
242 return ret;
243 }
244 bulk->count++;
245 }
246
247 return 0;
248}
249
250int generic_phy_init_bulk(struct phy_bulk *bulk)
251{
252 struct phy *phys = bulk->phys;
253 int i, ret;
254
255 for (i = 0; i < bulk->count; i++) {
256 ret = generic_phy_init(&phys[i]);
257 if (ret) {
258 pr_err("Can't init PHY%d\n", i);
259 goto phys_init_err;
260 }
261 }
262
263 return 0;
264
265phys_init_err:
266 for (; i > 0; i--)
267 generic_phy_exit(&phys[i - 1]);
268
269 return ret;
270}
271
272int generic_phy_exit_bulk(struct phy_bulk *bulk)
273{
274 struct phy *phys = bulk->phys;
275 int i, ret = 0;
276
277 for (i = 0; i < bulk->count; i++)
278 ret |= generic_phy_exit(&phys[i]);
279
280 return ret;
281}
282
283int generic_phy_power_on_bulk(struct phy_bulk *bulk)
284{
285 struct phy *phys = bulk->phys;
286 int i, ret;
287
288 for (i = 0; i < bulk->count; i++) {
289 ret = generic_phy_power_on(&phys[i]);
290 if (ret) {
291 pr_err("Can't power on PHY%d\n", i);
292 goto phys_poweron_err;
293 }
294 }
295
296 return 0;
297
298phys_poweron_err:
299 for (; i > 0; i--)
300 generic_phy_power_off(&phys[i - 1]);
301
302 return ret;
303}
304
305int generic_phy_power_off_bulk(struct phy_bulk *bulk)
306{
307 struct phy *phys = bulk->phys;
308 int i, ret = 0;
309
310 for (i = 0; i < bulk->count; i++)
311 ret |= generic_phy_power_off(&phys[i]);
312
313 return ret;
314}
315
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200316UCLASS_DRIVER(phy) = {
317 .id = UCLASS_PHY,
318 .name = "phy",
319};