blob: db7f39cd0b4598ad14aedb9bb6eebdd8c82c9d81 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jean-Jacques Hiblot48447782017-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 Hiblot48447782017-04-24 11:51:27 +02005 */
6
7#include <common.h>
8#include <dm.h>
developer272bde62020-05-02 11:35:11 +02009#include <dm/devres.h>
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020010#include <generic-phy.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020012
Jean-Jacques Hiblot48447782017-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 Glass81955512017-05-18 20:09:47 -060019 struct ofnode_phandle_args *args)
Jean-Jacques Hiblot48447782017-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 Hiblot48447782017-04-24 11:51:27 +020033 return 0;
34}
35
Jagan Tekia4e8eee2020-05-01 23:44:18 +053036int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy)
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020037{
Simon Glass81955512017-05-18 20:09:47 -060038 struct ofnode_phandle_args args;
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020039 struct phy_ops *ops;
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020040 struct udevice *phydev;
Patrice Chotardcf65fa42018-06-27 11:55:42 +020041 int i, ret;
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020042
Neil Armstrong8ab77e32020-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 Hiblot48447782017-04-24 11:51:27 +020045
46 assert(phy);
Patrice Chotard956b7ad2017-07-18 11:38:42 +020047 phy->dev = NULL;
Neil Armstrong8ab77e32020-03-30 11:27:23 +020048 ret = ofnode_parse_phandle_with_args(node, "phys", "#phy-cells", 0,
49 index, &args);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020050 if (ret) {
Simon Glass81955512017-05-18 20:09:47 -060051 debug("%s: dev_read_phandle_with_args failed: err=%d\n",
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020052 __func__, ret);
53 return ret;
54 }
55
Simon Glass81955512017-05-18 20:09:47 -060056 ret = uclass_get_device_by_ofnode(UCLASS_PHY, args.node, &phydev);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020057 if (ret) {
Simon Glass81955512017-05-18 20:09:47 -060058 debug("%s: uclass_get_device_by_ofnode failed: err=%d\n",
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +020059 __func__, ret);
Patrice Chotardcf65fa42018-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 Vasut61b17ed2018-08-07 12:24:35 +020069 for (i = args.args_count; i >= 1 ; i--)
Patrice Chotardcf65fa42018-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 Hiblot48447782017-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 Armstrong8ab77e32020-03-30 11:27:23 +020095int generic_phy_get_by_index(struct udevice *dev, int index,
96 struct phy *phy)
97{
Jagan Tekia4e8eee2020-05-01 23:44:18 +053098 return generic_phy_get_by_index_nodev(dev_ofnode(dev), index, phy);
Neil Armstrong8ab77e32020-03-30 11:27:23 +020099}
100
Jean-Jacques Hiblot48447782017-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 Glass81955512017-05-18 20:09:47 -0600108 index = dev_read_stringlist_search(dev, "phy-names", phy_name);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +0200109 if (index < 0) {
Simon Glass81955512017-05-18 20:09:47 -0600110 debug("dev_read_stringlist_search() failed: %d\n", index);
Jean-Jacques Hiblot48447782017-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 Hibloteae1eeb2019-10-01 14:03:26 +0200119 struct phy_ops const *ops;
120
Vignesh Raghavendra62bd5b12020-05-20 22:35:41 +0530121 if (!generic_phy_valid(phy))
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200122 return 0;
123 ops = phy_dev_ops(phy->dev);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +0200124
125 return ops->init ? ops->init(phy) : 0;
126}
127
128int generic_phy_reset(struct phy *phy)
129{
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200130 struct phy_ops const *ops;
131
Vignesh Raghavendra62bd5b12020-05-20 22:35:41 +0530132 if (!generic_phy_valid(phy))
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200133 return 0;
134 ops = phy_dev_ops(phy->dev);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +0200135
136 return ops->reset ? ops->reset(phy) : 0;
137}
138
139int generic_phy_exit(struct phy *phy)
140{
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200141 struct phy_ops const *ops;
142
Vignesh Raghavendra62bd5b12020-05-20 22:35:41 +0530143 if (!generic_phy_valid(phy))
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200144 return 0;
145 ops = phy_dev_ops(phy->dev);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +0200146
147 return ops->exit ? ops->exit(phy) : 0;
148}
149
150int generic_phy_power_on(struct phy *phy)
151{
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200152 struct phy_ops const *ops;
153
Vignesh Raghavendra62bd5b12020-05-20 22:35:41 +0530154 if (!generic_phy_valid(phy))
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200155 return 0;
156 ops = phy_dev_ops(phy->dev);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +0200157
158 return ops->power_on ? ops->power_on(phy) : 0;
159}
160
161int generic_phy_power_off(struct phy *phy)
162{
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200163 struct phy_ops const *ops;
164
Vignesh Raghavendra62bd5b12020-05-20 22:35:41 +0530165 if (!generic_phy_valid(phy))
Jean-Jacques Hibloteae1eeb2019-10-01 14:03:26 +0200166 return 0;
167 ops = phy_dev_ops(phy->dev);
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +0200168
169 return ops->power_off ? ops->power_off(phy) : 0;
170}
171
developer272bde62020-05-02 11:35:11 +0200172int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
173{
174 int i, ret, count;
175
176 bulk->count = 0;
177
178 /* Return if no phy declared */
179 if (!dev_read_prop(dev, "phys", NULL))
180 return 0;
181
182 count = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
183 if (count < 1)
184 return count;
185
186 bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL);
187 if (!bulk->phys)
188 return -ENOMEM;
189
190 for (i = 0; i < count; i++) {
191 ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]);
192 if (ret) {
193 pr_err("Failed to get PHY%d for %s\n", i, dev->name);
194 return ret;
195 }
196 bulk->count++;
197 }
198
199 return 0;
200}
201
202int generic_phy_init_bulk(struct phy_bulk *bulk)
203{
204 struct phy *phys = bulk->phys;
205 int i, ret;
206
207 for (i = 0; i < bulk->count; i++) {
208 ret = generic_phy_init(&phys[i]);
209 if (ret) {
210 pr_err("Can't init PHY%d\n", i);
211 goto phys_init_err;
212 }
213 }
214
215 return 0;
216
217phys_init_err:
218 for (; i > 0; i--)
219 generic_phy_exit(&phys[i - 1]);
220
221 return ret;
222}
223
224int generic_phy_exit_bulk(struct phy_bulk *bulk)
225{
226 struct phy *phys = bulk->phys;
227 int i, ret = 0;
228
229 for (i = 0; i < bulk->count; i++)
230 ret |= generic_phy_exit(&phys[i]);
231
232 return ret;
233}
234
235int generic_phy_power_on_bulk(struct phy_bulk *bulk)
236{
237 struct phy *phys = bulk->phys;
238 int i, ret;
239
240 for (i = 0; i < bulk->count; i++) {
241 ret = generic_phy_power_on(&phys[i]);
242 if (ret) {
243 pr_err("Can't power on PHY%d\n", i);
244 goto phys_poweron_err;
245 }
246 }
247
248 return 0;
249
250phys_poweron_err:
251 for (; i > 0; i--)
252 generic_phy_power_off(&phys[i - 1]);
253
254 return ret;
255}
256
257int generic_phy_power_off_bulk(struct phy_bulk *bulk)
258{
259 struct phy *phys = bulk->phys;
260 int i, ret = 0;
261
262 for (i = 0; i < bulk->count; i++)
263 ret |= generic_phy_power_off(&phys[i]);
264
265 return ret;
266}
267
Jean-Jacques Hiblot48447782017-04-24 11:51:27 +0200268UCLASS_DRIVER(phy) = {
269 .id = UCLASS_PHY,
270 .name = "phy",
271};