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