blob: 43ffbcee0f01af6adfba9276f4e0ab5a847100ad [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
7#include <common.h>
8#include <dm.h>
Sean Andersonbdc1fdf2020-10-04 21:39:47 -04009#include <dm/device_compat.h>
Chunfeng Yunb13307b2020-05-02 11:35:11 +020010#include <dm/devres.h>
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020011#include <generic-phy.h>
12
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020013static inline struct phy_ops *phy_dev_ops(struct udevice *dev)
14{
15 return (struct phy_ops *)dev->driver->ops;
16}
17
18static int generic_phy_xlate_offs_flags(struct phy *phy,
Simon Glass23558bb2017-05-18 20:09:47 -060019 struct ofnode_phandle_args *args)
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020020{
21 debug("%s(phy=%p)\n", __func__, phy);
22
23 if (args->args_count > 1) {
24 debug("Invaild args_count: %d\n", args->args_count);
25 return -EINVAL;
26 }
27
28 if (args->args_count)
29 phy->id = args->args[0];
30 else
31 phy->id = 0;
32
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020033 return 0;
34}
35
Jagan Teki5a2b6772020-05-01 23:44:18 +053036int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy)
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020037{
Simon Glass23558bb2017-05-18 20:09:47 -060038 struct ofnode_phandle_args args;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020039 struct phy_ops *ops;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020040 struct udevice *phydev;
Patrice Chotarda1b2fae2018-06-27 11:55:42 +020041 int i, ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020042
Neil Armstrongc2b9aa92020-03-30 11:27:23 +020043 debug("%s(node=%s, index=%d, phy=%p)\n",
44 __func__, ofnode_get_name(node), index, phy);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020045
46 assert(phy);
Patrice Chotardb9688df2017-07-18 11:38:42 +020047 phy->dev = NULL;
Neil Armstrongc2b9aa92020-03-30 11:27:23 +020048 ret = ofnode_parse_phandle_with_args(node, "phys", "#phy-cells", 0,
49 index, &args);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020050 if (ret) {
Simon Glass23558bb2017-05-18 20:09:47 -060051 debug("%s: dev_read_phandle_with_args failed: err=%d\n",
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020052 __func__, ret);
53 return ret;
54 }
55
Simon Glass23558bb2017-05-18 20:09:47 -060056 ret = uclass_get_device_by_ofnode(UCLASS_PHY, args.node, &phydev);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020057 if (ret) {
Simon Glass23558bb2017-05-18 20:09:47 -060058 debug("%s: uclass_get_device_by_ofnode failed: err=%d\n",
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020059 __func__, ret);
Patrice Chotarda1b2fae2018-06-27 11:55:42 +020060
61 /* Check if args.node's parent is a PHY provider */
62 ret = uclass_get_device_by_ofnode(UCLASS_PHY,
63 ofnode_get_parent(args.node),
64 &phydev);
65 if (ret)
66 return ret;
67
68 /* insert phy idx at first position into args array */
Marek Vasut5e50adf2018-08-07 12:24:35 +020069 for (i = args.args_count; i >= 1 ; i--)
Patrice Chotarda1b2fae2018-06-27 11:55:42 +020070 args.args[i] = args.args[i - 1];
71
72 args.args_count++;
73 args.args[0] = ofnode_read_u32_default(args.node, "reg", -1);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +020074 }
75
76 phy->dev = phydev;
77
78 ops = phy_dev_ops(phydev);
79
80 if (ops->of_xlate)
81 ret = ops->of_xlate(phy, &args);
82 else
83 ret = generic_phy_xlate_offs_flags(phy, &args);
84 if (ret) {
85 debug("of_xlate() failed: %d\n", ret);
86 goto err;
87 }
88
89 return 0;
90
91err:
92 return ret;
93}
94
Neil Armstrongc2b9aa92020-03-30 11:27:23 +020095int generic_phy_get_by_index(struct udevice *dev, int index,
96 struct phy *phy)
97{
Jagan Teki5a2b6772020-05-01 23:44:18 +053098 return generic_phy_get_by_index_nodev(dev_ofnode(dev), index, phy);
Neil Armstrongc2b9aa92020-03-30 11:27:23 +020099}
100
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200101int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
102 struct phy *phy)
103{
104 int index;
105
106 debug("%s(dev=%p, name=%s, phy=%p)\n", __func__, dev, phy_name, phy);
107
Simon Glass23558bb2017-05-18 20:09:47 -0600108 index = dev_read_stringlist_search(dev, "phy-names", phy_name);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200109 if (index < 0) {
Simon Glass23558bb2017-05-18 20:09:47 -0600110 debug("dev_read_stringlist_search() failed: %d\n", index);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200111 return index;
112 }
113
114 return generic_phy_get_by_index(dev, index, phy);
115}
116
117int generic_phy_init(struct phy *phy)
118{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200119 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200120 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200121
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530122 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200123 return 0;
124 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200125 if (!ops->init)
126 return 0;
127 ret = ops->init(phy);
128 if (ret)
129 dev_err(phy->dev, "PHY: Failed to init %s: %d.\n",
130 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200131
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200132 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200133}
134
135int generic_phy_reset(struct phy *phy)
136{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200137 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200138 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200139
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530140 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200141 return 0;
142 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200143 if (!ops->reset)
144 return 0;
145 ret = ops->reset(phy);
146 if (ret)
147 dev_err(phy->dev, "PHY: Failed to reset %s: %d.\n",
148 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200149
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200150 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200151}
152
153int generic_phy_exit(struct phy *phy)
154{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200155 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200156 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200157
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530158 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200159 return 0;
160 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200161 if (!ops->exit)
162 return 0;
163 ret = ops->exit(phy);
164 if (ret)
165 dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n",
166 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200167
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200168 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200169}
170
171int generic_phy_power_on(struct phy *phy)
172{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200173 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200174 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200175
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530176 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200177 return 0;
178 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200179 if (!ops->power_on)
180 return 0;
181 ret = ops->power_on(phy);
182 if (ret)
183 dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n",
184 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200185
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200186 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200187}
188
189int generic_phy_power_off(struct phy *phy)
190{
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200191 struct phy_ops const *ops;
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200192 int ret;
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200193
Vignesh Raghavendra64b69f82020-05-20 22:35:41 +0530194 if (!generic_phy_valid(phy))
Jean-Jacques Hiblot4e184292019-10-01 14:03:26 +0200195 return 0;
196 ops = phy_dev_ops(phy->dev);
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200197 if (!ops->power_off)
198 return 0;
199 ret = ops->power_off(phy);
200 if (ret)
201 dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n",
202 phy->dev->name, ret);
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200203
Patrick Delaunay2041ae52020-07-03 17:36:40 +0200204 return ret;
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200205}
206
Neil Armstrongf8da8a82020-12-29 14:58:59 +0100207int generic_phy_configure(struct phy *phy, void *params)
208{
209 struct phy_ops const *ops;
210
211 if (!generic_phy_valid(phy))
212 return 0;
213 ops = phy_dev_ops(phy->dev);
214
215 return ops->configure ? ops->configure(phy, params) : 0;
216}
217
Chunfeng Yunb13307b2020-05-02 11:35:11 +0200218int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
219{
220 int i, ret, count;
221
222 bulk->count = 0;
223
224 /* Return if no phy declared */
225 if (!dev_read_prop(dev, "phys", NULL))
226 return 0;
227
Patrick Delaunay89f68302020-09-25 09:41:14 +0200228 count = dev_count_phandle_with_args(dev, "phys", "#phy-cells", 0);
Chunfeng Yunb13307b2020-05-02 11:35:11 +0200229 if (count < 1)
230 return count;
231
232 bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL);
233 if (!bulk->phys)
234 return -ENOMEM;
235
236 for (i = 0; i < count; i++) {
237 ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]);
238 if (ret) {
239 pr_err("Failed to get PHY%d for %s\n", i, dev->name);
240 return ret;
241 }
242 bulk->count++;
243 }
244
245 return 0;
246}
247
248int generic_phy_init_bulk(struct phy_bulk *bulk)
249{
250 struct phy *phys = bulk->phys;
251 int i, ret;
252
253 for (i = 0; i < bulk->count; i++) {
254 ret = generic_phy_init(&phys[i]);
255 if (ret) {
256 pr_err("Can't init PHY%d\n", i);
257 goto phys_init_err;
258 }
259 }
260
261 return 0;
262
263phys_init_err:
264 for (; i > 0; i--)
265 generic_phy_exit(&phys[i - 1]);
266
267 return ret;
268}
269
270int generic_phy_exit_bulk(struct phy_bulk *bulk)
271{
272 struct phy *phys = bulk->phys;
273 int i, ret = 0;
274
275 for (i = 0; i < bulk->count; i++)
276 ret |= generic_phy_exit(&phys[i]);
277
278 return ret;
279}
280
281int generic_phy_power_on_bulk(struct phy_bulk *bulk)
282{
283 struct phy *phys = bulk->phys;
284 int i, ret;
285
286 for (i = 0; i < bulk->count; i++) {
287 ret = generic_phy_power_on(&phys[i]);
288 if (ret) {
289 pr_err("Can't power on PHY%d\n", i);
290 goto phys_poweron_err;
291 }
292 }
293
294 return 0;
295
296phys_poweron_err:
297 for (; i > 0; i--)
298 generic_phy_power_off(&phys[i - 1]);
299
300 return ret;
301}
302
303int generic_phy_power_off_bulk(struct phy_bulk *bulk)
304{
305 struct phy *phys = bulk->phys;
306 int i, ret = 0;
307
308 for (i = 0; i < bulk->count; i++)
309 ret |= generic_phy_power_off(&phys[i]);
310
311 return ret;
312}
313
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200314UCLASS_DRIVER(phy) = {
315 .id = UCLASS_PHY,
316 .name = "phy",
317};