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