blob: ef03e3a5025f351cad6a199b65c9728b084f53eb [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
Chunfeng Yunb13307b2020-05-02 11:35:11 +0200207int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
208{
209 int i, ret, count;
210
211 bulk->count = 0;
212
213 /* Return if no phy declared */
214 if (!dev_read_prop(dev, "phys", NULL))
215 return 0;
216
Patrick Delaunay89f68302020-09-25 09:41:14 +0200217 count = dev_count_phandle_with_args(dev, "phys", "#phy-cells", 0);
Chunfeng Yunb13307b2020-05-02 11:35:11 +0200218 if (count < 1)
219 return count;
220
221 bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL);
222 if (!bulk->phys)
223 return -ENOMEM;
224
225 for (i = 0; i < count; i++) {
226 ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]);
227 if (ret) {
228 pr_err("Failed to get PHY%d for %s\n", i, dev->name);
229 return ret;
230 }
231 bulk->count++;
232 }
233
234 return 0;
235}
236
237int generic_phy_init_bulk(struct phy_bulk *bulk)
238{
239 struct phy *phys = bulk->phys;
240 int i, ret;
241
242 for (i = 0; i < bulk->count; i++) {
243 ret = generic_phy_init(&phys[i]);
244 if (ret) {
245 pr_err("Can't init PHY%d\n", i);
246 goto phys_init_err;
247 }
248 }
249
250 return 0;
251
252phys_init_err:
253 for (; i > 0; i--)
254 generic_phy_exit(&phys[i - 1]);
255
256 return ret;
257}
258
259int generic_phy_exit_bulk(struct phy_bulk *bulk)
260{
261 struct phy *phys = bulk->phys;
262 int i, ret = 0;
263
264 for (i = 0; i < bulk->count; i++)
265 ret |= generic_phy_exit(&phys[i]);
266
267 return ret;
268}
269
270int generic_phy_power_on_bulk(struct phy_bulk *bulk)
271{
272 struct phy *phys = bulk->phys;
273 int i, ret;
274
275 for (i = 0; i < bulk->count; i++) {
276 ret = generic_phy_power_on(&phys[i]);
277 if (ret) {
278 pr_err("Can't power on PHY%d\n", i);
279 goto phys_poweron_err;
280 }
281 }
282
283 return 0;
284
285phys_poweron_err:
286 for (; i > 0; i--)
287 generic_phy_power_off(&phys[i - 1]);
288
289 return ret;
290}
291
292int generic_phy_power_off_bulk(struct phy_bulk *bulk)
293{
294 struct phy *phys = bulk->phys;
295 int i, ret = 0;
296
297 for (i = 0; i < bulk->count; i++)
298 ret |= generic_phy_power_off(&phys[i]);
299
300 return ret;
301}
302
Jean-Jacques Hiblot72e50162017-04-24 11:51:27 +0200303UCLASS_DRIVER(phy) = {
304 .id = UCLASS_PHY,
305 .name = "phy",
306};