Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0+ 2 : : /* 3 : : * Fixed MDIO bus (MDIO bus emulation with fixed PHYs) 4 : : * 5 : : * Author: Vitaly Bordug <vbordug@ru.mvista.com> 6 : : * Anton Vorontsov <avorontsov@ru.mvista.com> 7 : : * 8 : : * Copyright (c) 2006-2007 MontaVista Software, Inc. 9 : : */ 10 : : 11 : : #include <linux/kernel.h> 12 : : #include <linux/module.h> 13 : : #include <linux/platform_device.h> 14 : : #include <linux/list.h> 15 : : #include <linux/mii.h> 16 : : #include <linux/phy.h> 17 : : #include <linux/phy_fixed.h> 18 : : #include <linux/err.h> 19 : : #include <linux/slab.h> 20 : : #include <linux/of.h> 21 : : #include <linux/gpio/consumer.h> 22 : : #include <linux/seqlock.h> 23 : : #include <linux/idr.h> 24 : : #include <linux/netdevice.h> 25 : : #include <linux/linkmode.h> 26 : : 27 : : #include "swphy.h" 28 : : 29 : : struct fixed_mdio_bus { 30 : : struct mii_bus *mii_bus; 31 : : struct list_head phys; 32 : : }; 33 : : 34 : : struct fixed_phy { 35 : : int addr; 36 : : struct phy_device *phydev; 37 : : seqcount_t seqcount; 38 : : struct fixed_phy_status status; 39 : : bool no_carrier; 40 : : int (*link_update)(struct net_device *, struct fixed_phy_status *); 41 : : struct list_head node; 42 : : struct gpio_desc *link_gpiod; 43 : : }; 44 : : 45 : : static struct platform_device *pdev; 46 : : static struct fixed_mdio_bus platform_fmb = { 47 : : .phys = LIST_HEAD_INIT(platform_fmb.phys), 48 : : }; 49 : : 50 : 0 : int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier) 51 : : { 52 : : struct fixed_mdio_bus *fmb = &platform_fmb; 53 : 0 : struct phy_device *phydev = dev->phydev; 54 : : struct fixed_phy *fp; 55 : : 56 : 0 : if (!phydev || !phydev->mdio.bus) 57 : : return -EINVAL; 58 : : 59 : 0 : list_for_each_entry(fp, &fmb->phys, node) { 60 : 0 : if (fp->addr == phydev->mdio.addr) { 61 : 0 : fp->no_carrier = !new_carrier; 62 : 0 : return 0; 63 : : } 64 : : } 65 : : return -EINVAL; 66 : : } 67 : : EXPORT_SYMBOL_GPL(fixed_phy_change_carrier); 68 : : 69 : 0 : static void fixed_phy_update(struct fixed_phy *fp) 70 : : { 71 : 0 : if (!fp->no_carrier && fp->link_gpiod) 72 : 0 : fp->status.link = !!gpiod_get_value_cansleep(fp->link_gpiod); 73 : 0 : } 74 : : 75 : 3 : static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num) 76 : : { 77 : 3 : struct fixed_mdio_bus *fmb = bus->priv; 78 : : struct fixed_phy *fp; 79 : : 80 : 3 : list_for_each_entry(fp, &fmb->phys, node) { 81 : 0 : if (fp->addr == phy_addr) { 82 : : struct fixed_phy_status state; 83 : : int s; 84 : : 85 : : do { 86 : : s = read_seqcount_begin(&fp->seqcount); 87 : 0 : fp->status.link = !fp->no_carrier; 88 : : /* Issue callback if user registered it. */ 89 : 0 : if (fp->link_update) 90 : 0 : fp->link_update(fp->phydev->attached_dev, 91 : : &fp->status); 92 : : /* Check the GPIO for change in status */ 93 : 0 : fixed_phy_update(fp); 94 : 0 : state = fp->status; 95 : 0 : } while (read_seqcount_retry(&fp->seqcount, s)); 96 : : 97 : 0 : return swphy_read_reg(reg_num, &state); 98 : : } 99 : : } 100 : : 101 : : return 0xFFFF; 102 : : } 103 : : 104 : 0 : static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num, 105 : : u16 val) 106 : : { 107 : 0 : return 0; 108 : : } 109 : : 110 : : /* 111 : : * If something weird is required to be done with link/speed, 112 : : * network driver is able to assign a function to implement this. 113 : : * May be useful for PHY's that need to be software-driven. 114 : : */ 115 : 0 : int fixed_phy_set_link_update(struct phy_device *phydev, 116 : : int (*link_update)(struct net_device *, 117 : : struct fixed_phy_status *)) 118 : : { 119 : : struct fixed_mdio_bus *fmb = &platform_fmb; 120 : : struct fixed_phy *fp; 121 : : 122 : 0 : if (!phydev || !phydev->mdio.bus) 123 : : return -EINVAL; 124 : : 125 : 0 : list_for_each_entry(fp, &fmb->phys, node) { 126 : 0 : if (fp->addr == phydev->mdio.addr) { 127 : 0 : fp->link_update = link_update; 128 : 0 : fp->phydev = phydev; 129 : 0 : return 0; 130 : : } 131 : : } 132 : : 133 : : return -ENOENT; 134 : : } 135 : : EXPORT_SYMBOL_GPL(fixed_phy_set_link_update); 136 : : 137 : 0 : static int fixed_phy_add_gpiod(unsigned int irq, int phy_addr, 138 : : struct fixed_phy_status *status, 139 : : struct gpio_desc *gpiod) 140 : : { 141 : : int ret; 142 : : struct fixed_mdio_bus *fmb = &platform_fmb; 143 : : struct fixed_phy *fp; 144 : : 145 : 0 : ret = swphy_validate_state(status); 146 : 0 : if (ret < 0) 147 : : return ret; 148 : : 149 : 0 : fp = kzalloc(sizeof(*fp), GFP_KERNEL); 150 : 0 : if (!fp) 151 : : return -ENOMEM; 152 : : 153 : : seqcount_init(&fp->seqcount); 154 : : 155 : 0 : if (irq != PHY_POLL) 156 : 0 : fmb->mii_bus->irq[phy_addr] = irq; 157 : : 158 : 0 : fp->addr = phy_addr; 159 : 0 : fp->status = *status; 160 : 0 : fp->link_gpiod = gpiod; 161 : : 162 : 0 : fixed_phy_update(fp); 163 : : 164 : 0 : list_add_tail(&fp->node, &fmb->phys); 165 : : 166 : 0 : return 0; 167 : : } 168 : : 169 : 0 : int fixed_phy_add(unsigned int irq, int phy_addr, 170 : : struct fixed_phy_status *status) { 171 : : 172 : 0 : return fixed_phy_add_gpiod(irq, phy_addr, status, NULL); 173 : : } 174 : : EXPORT_SYMBOL_GPL(fixed_phy_add); 175 : : 176 : : static DEFINE_IDA(phy_fixed_ida); 177 : : 178 : 0 : static void fixed_phy_del(int phy_addr) 179 : : { 180 : : struct fixed_mdio_bus *fmb = &platform_fmb; 181 : : struct fixed_phy *fp, *tmp; 182 : : 183 : 0 : list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { 184 : 0 : if (fp->addr == phy_addr) { 185 : : list_del(&fp->node); 186 : 0 : if (fp->link_gpiod) 187 : 0 : gpiod_put(fp->link_gpiod); 188 : 0 : kfree(fp); 189 : 0 : ida_simple_remove(&phy_fixed_ida, phy_addr); 190 : 0 : return; 191 : : } 192 : : } 193 : : } 194 : : 195 : : #ifdef CONFIG_OF_GPIO 196 : 0 : static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np) 197 : : { 198 : : struct device_node *fixed_link_node; 199 : : struct gpio_desc *gpiod; 200 : : 201 : 0 : if (!np) 202 : : return NULL; 203 : : 204 : 0 : fixed_link_node = of_get_child_by_name(np, "fixed-link"); 205 : 0 : if (!fixed_link_node) 206 : : return NULL; 207 : : 208 : : /* 209 : : * As the fixed link is just a device tree node without any 210 : : * Linux device associated with it, we simply have obtain 211 : : * the GPIO descriptor from the device tree like this. 212 : : */ 213 : 0 : gpiod = gpiod_get_from_of_node(fixed_link_node, "link-gpios", 0, 214 : : GPIOD_IN, "mdio"); 215 : 0 : if (IS_ERR(gpiod) && PTR_ERR(gpiod) != -EPROBE_DEFER) { 216 : 0 : if (PTR_ERR(gpiod) != -ENOENT) 217 : 0 : pr_err("error getting GPIO for fixed link %pOF, proceed without\n", 218 : : fixed_link_node); 219 : : gpiod = NULL; 220 : : } 221 : 0 : of_node_put(fixed_link_node); 222 : : 223 : 0 : return gpiod; 224 : : } 225 : : #else 226 : : static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np) 227 : : { 228 : : return NULL; 229 : : } 230 : : #endif 231 : : 232 : 0 : static struct phy_device *__fixed_phy_register(unsigned int irq, 233 : : struct fixed_phy_status *status, 234 : : struct device_node *np, 235 : : struct gpio_desc *gpiod) 236 : : { 237 : : struct fixed_mdio_bus *fmb = &platform_fmb; 238 : : struct phy_device *phy; 239 : : int phy_addr; 240 : : int ret; 241 : : 242 : 0 : if (!fmb->mii_bus || fmb->mii_bus->state != MDIOBUS_REGISTERED) 243 : : return ERR_PTR(-EPROBE_DEFER); 244 : : 245 : : /* Check if we have a GPIO associated with this fixed phy */ 246 : 0 : if (!gpiod) { 247 : 0 : gpiod = fixed_phy_get_gpiod(np); 248 : 0 : if (IS_ERR(gpiod)) 249 : : return ERR_CAST(gpiod); 250 : : } 251 : : 252 : : /* Get the next available PHY address, up to PHY_MAX_ADDR */ 253 : 0 : phy_addr = ida_simple_get(&phy_fixed_ida, 0, PHY_MAX_ADDR, GFP_KERNEL); 254 : 0 : if (phy_addr < 0) 255 : 0 : return ERR_PTR(phy_addr); 256 : : 257 : 0 : ret = fixed_phy_add_gpiod(irq, phy_addr, status, gpiod); 258 : 0 : if (ret < 0) { 259 : 0 : ida_simple_remove(&phy_fixed_ida, phy_addr); 260 : 0 : return ERR_PTR(ret); 261 : : } 262 : : 263 : 0 : phy = get_phy_device(fmb->mii_bus, phy_addr, false); 264 : 0 : if (IS_ERR(phy)) { 265 : 0 : fixed_phy_del(phy_addr); 266 : 0 : return ERR_PTR(-EINVAL); 267 : : } 268 : : 269 : : /* propagate the fixed link values to struct phy_device */ 270 : 0 : phy->link = status->link; 271 : 0 : if (status->link) { 272 : 0 : phy->speed = status->speed; 273 : 0 : phy->duplex = status->duplex; 274 : 0 : phy->pause = status->pause; 275 : 0 : phy->asym_pause = status->asym_pause; 276 : : } 277 : : 278 : 0 : of_node_get(np); 279 : 0 : phy->mdio.dev.of_node = np; 280 : 0 : phy->is_pseudo_fixed_link = true; 281 : : 282 : 0 : switch (status->speed) { 283 : : case SPEED_1000: 284 : : linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 285 : : phy->supported); 286 : : linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 287 : : phy->supported); 288 : : /* fall through */ 289 : : case SPEED_100: 290 : : linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, 291 : : phy->supported); 292 : : linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, 293 : : phy->supported); 294 : : /* fall through */ 295 : : case SPEED_10: 296 : : default: 297 : : linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, 298 : : phy->supported); 299 : : linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, 300 : : phy->supported); 301 : : } 302 : : 303 : 0 : phy_advertise_supported(phy); 304 : : 305 : 0 : ret = phy_device_register(phy); 306 : 0 : if (ret) { 307 : 0 : phy_device_free(phy); 308 : 0 : of_node_put(np); 309 : 0 : fixed_phy_del(phy_addr); 310 : 0 : return ERR_PTR(ret); 311 : : } 312 : : 313 : : return phy; 314 : : } 315 : : 316 : 0 : struct phy_device *fixed_phy_register(unsigned int irq, 317 : : struct fixed_phy_status *status, 318 : : struct device_node *np) 319 : : { 320 : 0 : return __fixed_phy_register(irq, status, np, NULL); 321 : : } 322 : : EXPORT_SYMBOL_GPL(fixed_phy_register); 323 : : 324 : : struct phy_device * 325 : 0 : fixed_phy_register_with_gpiod(unsigned int irq, 326 : : struct fixed_phy_status *status, 327 : : struct gpio_desc *gpiod) 328 : : { 329 : 0 : return __fixed_phy_register(irq, status, NULL, gpiod); 330 : : } 331 : : EXPORT_SYMBOL_GPL(fixed_phy_register_with_gpiod); 332 : : 333 : 0 : void fixed_phy_unregister(struct phy_device *phy) 334 : : { 335 : 0 : phy_device_remove(phy); 336 : 0 : of_node_put(phy->mdio.dev.of_node); 337 : 0 : fixed_phy_del(phy->mdio.addr); 338 : 0 : } 339 : : EXPORT_SYMBOL_GPL(fixed_phy_unregister); 340 : : 341 : 3 : static int __init fixed_mdio_bus_init(void) 342 : : { 343 : : struct fixed_mdio_bus *fmb = &platform_fmb; 344 : : int ret; 345 : : 346 : 3 : pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0); 347 : 3 : if (IS_ERR(pdev)) 348 : 0 : return PTR_ERR(pdev); 349 : : 350 : 3 : fmb->mii_bus = mdiobus_alloc(); 351 : 3 : if (fmb->mii_bus == NULL) { 352 : : ret = -ENOMEM; 353 : : goto err_mdiobus_reg; 354 : : } 355 : : 356 : 3 : snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0"); 357 : 3 : fmb->mii_bus->name = "Fixed MDIO Bus"; 358 : 3 : fmb->mii_bus->priv = fmb; 359 : 3 : fmb->mii_bus->parent = &pdev->dev; 360 : 3 : fmb->mii_bus->read = &fixed_mdio_read; 361 : 3 : fmb->mii_bus->write = &fixed_mdio_write; 362 : : 363 : 3 : ret = mdiobus_register(fmb->mii_bus); 364 : 3 : if (ret) 365 : : goto err_mdiobus_alloc; 366 : : 367 : : return 0; 368 : : 369 : : err_mdiobus_alloc: 370 : 0 : mdiobus_free(fmb->mii_bus); 371 : : err_mdiobus_reg: 372 : 0 : platform_device_unregister(pdev); 373 : 0 : return ret; 374 : : } 375 : : module_init(fixed_mdio_bus_init); 376 : : 377 : 0 : static void __exit fixed_mdio_bus_exit(void) 378 : : { 379 : : struct fixed_mdio_bus *fmb = &platform_fmb; 380 : : struct fixed_phy *fp, *tmp; 381 : : 382 : 0 : mdiobus_unregister(fmb->mii_bus); 383 : 0 : mdiobus_free(fmb->mii_bus); 384 : 0 : platform_device_unregister(pdev); 385 : : 386 : 0 : list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { 387 : : list_del(&fp->node); 388 : 0 : kfree(fp); 389 : : } 390 : 0 : ida_destroy(&phy_fixed_ida); 391 : 0 : } 392 : : module_exit(fixed_mdio_bus_exit); 393 : : 394 : : MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)"); 395 : : MODULE_AUTHOR("Vitaly Bordug"); 396 : : MODULE_LICENSE("GPL");