1 /* 2 * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ 3 * Written by Jean-Jacques Hiblot <jjhiblot@ti.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <generic-phy.h> 11 #include <linux/list.h> 12 13 /** 14 * struct phy_counts - Init and power-on counts of a single PHY port 15 * 16 * This structure is used to keep track of PHY initialization and power 17 * state change requests, so that we don't power off and deinitialize a 18 * PHY instance until all of its users want it done. Otherwise, multiple 19 * consumers using the same PHY port can cause problems (e.g. one might 20 * call power_off() after another's exit() and hang indefinitely). 21 * 22 * @id: The PHY ID within a PHY provider 23 * @power_on_count: Times generic_phy_power_on() was called for this ID 24 * without a matching generic_phy_power_off() afterwards 25 * @init_count: Times generic_phy_init() was called for this ID 26 * without a matching generic_phy_exit() afterwards 27 * @list: Handle for a linked list of these structures corresponding to 28 * ports of the same PHY provider 29 */ 30 struct phy_counts { 31 unsigned long id; 32 int power_on_count; 33 int init_count; 34 struct list_head list; 35 }; 36 37 DECLARE_GLOBAL_DATA_PTR; 38 39 static inline struct phy_ops *phy_dev_ops(struct udevice *dev) 40 { 41 return (struct phy_ops *)dev->driver->ops; 42 } 43 44 static struct phy_counts *phy_get_counts(struct phy *phy) 45 { 46 struct list_head *uc_priv; 47 struct phy_counts *counts; 48 49 if (!generic_phy_valid(phy)) 50 return NULL; 51 52 uc_priv = dev_get_uclass_priv(phy->dev); 53 list_for_each_entry(counts, uc_priv, list) 54 if (counts->id == phy->id) 55 return counts; 56 57 return NULL; 58 } 59 60 static int phy_alloc_counts(struct phy *phy) 61 { 62 struct list_head *uc_priv; 63 struct phy_counts *counts; 64 65 if (!generic_phy_valid(phy)) 66 return 0; 67 if (phy_get_counts(phy)) 68 return 0; 69 70 uc_priv = dev_get_uclass_priv(phy->dev); 71 counts = kzalloc(sizeof(*counts), GFP_KERNEL); 72 if (!counts) 73 return -ENOMEM; 74 75 counts->id = phy->id; 76 counts->power_on_count = 0; 77 counts->init_count = 0; 78 list_add(&counts->list, uc_priv); 79 80 return 0; 81 } 82 83 static int phy_uclass_pre_probe(struct udevice *dev) 84 { 85 struct list_head *uc_priv = dev_get_uclass_priv(dev); 86 87 INIT_LIST_HEAD(uc_priv); 88 89 return 0; 90 } 91 92 static int phy_uclass_pre_remove(struct udevice *dev) 93 { 94 struct list_head *uc_priv = dev_get_uclass_priv(dev); 95 struct phy_counts *counts, *next; 96 97 list_for_each_entry_safe(counts, next, uc_priv, list) 98 kfree(counts); 99 100 return 0; 101 } 102 103 static int generic_phy_xlate_offs_flags(struct phy *phy, 104 struct ofnode_phandle_args *args) 105 { 106 debug("%s(phy=%p)\n", __func__, phy); 107 108 if (args->args_count > 1) { 109 debug("Invaild args_count: %d\n", args->args_count); 110 return -EINVAL; 111 } 112 113 if (args->args_count) 114 phy->id = args->args[0]; 115 else 116 phy->id = 0; 117 118 return 0; 119 } 120 121 int generic_phy_get_by_index(struct udevice *dev, int index, 122 struct phy *phy) 123 { 124 struct ofnode_phandle_args args; 125 struct phy_ops *ops; 126 int ret; 127 struct udevice *phydev; 128 129 debug("%s(dev=%p, index=%d, phy=%p)\n", __func__, dev, index, phy); 130 131 assert(phy); 132 phy->dev = NULL; 133 ret = dev_read_phandle_with_args(dev, "phys", "#phy-cells", 0, index, 134 &args); 135 if (ret) { 136 debug("%s: dev_read_phandle_with_args failed: err=%d\n", 137 __func__, ret); 138 return ret; 139 } 140 141 ret = uclass_get_device_by_ofnode(UCLASS_PHY, args.node, &phydev); 142 if (ret) { 143 debug("%s: uclass_get_device_by_ofnode failed: err=%d\n", 144 __func__, ret); 145 return ret; 146 } 147 148 phy->dev = phydev; 149 150 ops = phy_dev_ops(phydev); 151 152 if (ops->of_xlate) 153 ret = ops->of_xlate(phy, &args); 154 else 155 ret = generic_phy_xlate_offs_flags(phy, &args); 156 if (ret) { 157 debug("of_xlate() failed: %d\n", ret); 158 goto err; 159 } 160 161 ret = phy_alloc_counts(phy); 162 if (ret) { 163 debug("phy_alloc_counts() failed: %d\n", ret); 164 goto err; 165 } 166 167 return 0; 168 169 err: 170 return ret; 171 } 172 173 int generic_phy_get_by_name(struct udevice *dev, const char *phy_name, 174 struct phy *phy) 175 { 176 int index; 177 178 debug("%s(dev=%p, name=%s, phy=%p)\n", __func__, dev, phy_name, phy); 179 180 index = dev_read_stringlist_search(dev, "phy-names", phy_name); 181 if (index < 0) { 182 debug("dev_read_stringlist_search() failed: %d\n", index); 183 return index; 184 } 185 186 return generic_phy_get_by_index(dev, index, phy); 187 } 188 189 int generic_phy_init(struct phy *phy) 190 { 191 struct phy_counts *counts; 192 struct phy_ops const *ops; 193 int ret; 194 195 if (!generic_phy_valid(phy)) 196 return 0; 197 ops = phy_dev_ops(phy->dev); 198 if (!ops->init) 199 return 0; 200 201 counts = phy_get_counts(phy); 202 if (counts->init_count > 0) { 203 counts->init_count++; 204 return 0; 205 } 206 207 ret = ops->init(phy); 208 if (ret) 209 dev_err(phy->dev, "PHY: Failed to init %s: %d.\n", 210 phy->dev->name, ret); 211 else 212 counts->init_count = 1; 213 214 return 0; 215 } 216 217 int generic_phy_reset(struct phy *phy) 218 { 219 struct phy_ops const *ops; 220 221 if (!generic_phy_valid(phy)) 222 return 0; 223 ops = phy_dev_ops(phy->dev); 224 225 return ops->reset ? ops->reset(phy) : 0; 226 } 227 228 int generic_phy_exit(struct phy *phy) 229 { 230 struct phy_counts *counts; 231 struct phy_ops const *ops; 232 int ret; 233 234 if (!generic_phy_valid(phy)) 235 return 0; 236 ops = phy_dev_ops(phy->dev); 237 if (!ops->exit) 238 return 0; 239 240 counts = phy_get_counts(phy); 241 if (counts->init_count == 0) 242 return 0; 243 if (counts->init_count > 1) { 244 counts->init_count--; 245 return 0; 246 } 247 248 ret = ops->exit(phy); 249 if (ret) 250 dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n", 251 phy->dev->name, ret); 252 else 253 counts->init_count = 0; 254 255 return 0; 256 } 257 258 int generic_phy_power_on(struct phy *phy) 259 { 260 struct phy_counts *counts; 261 struct phy_ops const *ops; 262 int ret; 263 264 if (!generic_phy_valid(phy)) 265 return 0; 266 ops = phy_dev_ops(phy->dev); 267 if (!ops->power_on) 268 return 0; 269 270 counts = phy_get_counts(phy); 271 if (counts->power_on_count > 0) { 272 counts->power_on_count++; 273 return 0; 274 } 275 276 ret = ops->power_on(phy); 277 if (ret) 278 dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n", 279 phy->dev->name, ret); 280 else 281 counts->power_on_count = 1; 282 283 return 0; 284 } 285 286 int generic_phy_power_off(struct phy *phy) 287 { 288 struct phy_counts *counts; 289 struct phy_ops const *ops; 290 int ret; 291 292 if (!generic_phy_valid(phy)) 293 return 0; 294 ops = phy_dev_ops(phy->dev); 295 if (!ops->power_off) 296 return 0; 297 298 counts = phy_get_counts(phy); 299 if (counts->power_on_count == 0) 300 return 0; 301 if (counts->power_on_count > 1) { 302 counts->power_on_count--; 303 return 0; 304 } 305 306 ret = ops->power_off(phy); 307 if (ret) 308 dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n", 309 phy->dev->name, ret); 310 else 311 counts->power_on_count = 0; 312 313 return 0; 314 } 315 316 int generic_phy_configure(struct phy *phy, union phy_configure_opts *opts) 317 { 318 struct phy_ops const *ops; 319 320 if (!generic_phy_valid(phy)) 321 return 0; 322 ops = phy_dev_ops(phy->dev); 323 324 return ops->configure ? ops->configure(phy, opts) : 0; 325 } 326 327 int generic_phy_validate(struct phy *phy, enum phy_mode mode, int submode, 328 union phy_configure_opts *opts) 329 { 330 struct phy_ops const *ops; 331 332 if (!generic_phy_valid(phy)) 333 return 0; 334 ops = phy_dev_ops(phy->dev); 335 336 return ops->validate ? ops->validate(phy, mode, submode, opts) : 0; 337 } 338 339 int generic_phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode) 340 { 341 struct phy_ops const *ops; 342 int ret; 343 344 if (!generic_phy_valid(phy)) 345 return 0; 346 ops = phy_dev_ops(phy->dev); 347 348 if (!ops->set_mode) 349 return 0; 350 351 ret = ops->set_mode(phy, mode, submode); 352 if (!ret) 353 phy->attrs.mode = mode; 354 355 return ret; 356 } 357 358 UCLASS_DRIVER(phy) = { 359 .id = UCLASS_PHY, 360 .name = "phy", 361 .pre_probe = phy_uclass_pre_probe, 362 .pre_remove = phy_uclass_pre_remove, 363 .per_device_auto_alloc_size = sizeof(struct list_head), 364 }; 365