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                pr_err("error getting GPIO for fixed link %pOF, proceed without\n",
 220                       fixed_link_node);
 221                gpiod = NULL;
 222        }
 223
 224        return gpiod;
 225}
 226#else
 227static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np)
 228{
 229        return NULL;
 230}
 231#endif
 232
 233static struct phy_device *__fixed_phy_register(unsigned int irq,
 234                                               struct fixed_phy_status *status,
 235                                               struct device_node *np,
 236                                               struct gpio_desc *gpiod)
 237{
 238        struct fixed_mdio_bus *fmb = &platform_fmb;
 239        struct phy_device *phy;
 240        int phy_addr;
 241        int ret;
 242
 243        if (!fmb->mii_bus || fmb->mii_bus->state != MDIOBUS_REGISTERED)
 244                return ERR_PTR(-EPROBE_DEFER);
 245
 246        /* Check if we have a GPIO associated with this fixed phy */
 247        if (!gpiod) {
 248                gpiod = fixed_phy_get_gpiod(np);
 249                if (IS_ERR(gpiod))
 250                        return ERR_CAST(gpiod);
 251        }
 252
 253        /* Get the next available PHY address, up to PHY_MAX_ADDR */
 254        phy_addr = ida_simple_get(&phy_fixed_ida, 0, PHY_MAX_ADDR, GFP_KERNEL);
 255        if (phy_addr < 0)
 256                return ERR_PTR(phy_addr);
 257
 258        ret = fixed_phy_add_gpiod(irq, phy_addr, status, gpiod);
 259        if (ret < 0) {
 260                ida_simple_remove(&phy_fixed_ida, phy_addr);
 261                return ERR_PTR(ret);
 262        }
 263
 264        phy = get_phy_device(fmb->mii_bus, phy_addr, false);
 265        if (IS_ERR(phy)) {
 266                fixed_phy_del(phy_addr);
 267                return ERR_PTR(-EINVAL);
 268        }
 269
 270        /* propagate the fixed link values to struct phy_device */
 271        phy->link = status->link;
 272        if (status->link) {
 273                phy->speed = status->speed;
 274                phy->duplex = status->duplex;
 275                phy->pause = status->pause;
 276                phy->asym_pause = status->asym_pause;
 277        }
 278
 279        of_node_get(np);
 280        phy->mdio.dev.of_node = np;
 281        phy->is_pseudo_fixed_link = true;
 282
 283        switch (status->speed) {
 284        case SPEED_1000:
 285                linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
 286                                 phy->supported);
 287                linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
 288                                 phy->supported);
 289                /* fall through */
 290        case SPEED_100:
 291                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
 292                                 phy->supported);
 293                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
 294                                 phy->supported);
 295                /* fall through */
 296        case SPEED_10:
 297        default:
 298                linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
 299                                 phy->supported);
 300                linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
 301                                 phy->supported);
 302        }
 303
 304        phy_advertise_supported(phy);
 305
 306        ret = phy_device_register(phy);
 307        if (ret) {
 308                phy_device_free(phy);
 309                of_node_put(np);
 310                fixed_phy_del(phy_addr);
 311                return ERR_PTR(ret);
 312        }
 313
 314        return phy;
 315}
 316
 317struct phy_device *fixed_phy_register(unsigned int irq,
 318                                      struct fixed_phy_status *status,
 319                                      struct device_node *np)
 320{
 321        return __fixed_phy_register(irq, status, np, NULL);
 322}
 323EXPORT_SYMBOL_GPL(fixed_phy_register);
 324
 325struct phy_device *
 326fixed_phy_register_with_gpiod(unsigned int irq,
 327                              struct fixed_phy_status *status,
 328                              struct gpio_desc *gpiod)
 329{
 330        return __fixed_phy_register(irq, status, NULL, gpiod);
 331}
 332EXPORT_SYMBOL_GPL(fixed_phy_register_with_gpiod);
 333
 334void fixed_phy_unregister(struct phy_device *phy)
 335{
 336        phy_device_remove(phy);
 337        of_node_put(phy->mdio.dev.of_node);
 338        fixed_phy_del(phy->mdio.addr);
 339}
 340EXPORT_SYMBOL_GPL(fixed_phy_unregister);
 341
 342static int __init fixed_mdio_bus_init(void)
 343{
 344        struct fixed_mdio_bus *fmb = &platform_fmb;
 345        int ret;
 346
 347        pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
 348        if (IS_ERR(pdev))
 349                return PTR_ERR(pdev);
 350
 351        fmb->mii_bus = mdiobus_alloc();
 352        if (fmb->mii_bus == NULL) {
 353                ret = -ENOMEM;
 354                goto err_mdiobus_reg;
 355        }
 356
 357        snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
 358        fmb->mii_bus->name = "Fixed MDIO Bus";
 359        fmb->mii_bus->priv = fmb;
 360        fmb->mii_bus->parent = &pdev->dev;
 361        fmb->mii_bus->read = &fixed_mdio_read;
 362        fmb->mii_bus->write = &fixed_mdio_write;
 363
 364        ret = mdiobus_register(fmb->mii_bus);
 365        if (ret)
 366                goto err_mdiobus_alloc;
 367
 368        return 0;
 369
 370err_mdiobus_alloc:
 371        mdiobus_free(fmb->mii_bus);
 372err_mdiobus_reg:
 373        platform_device_unregister(pdev);
 374        return ret;
 375}
 376module_init(fixed_mdio_bus_init);
 377
 378static void __exit fixed_mdio_bus_exit(void)
 379{
 380        struct fixed_mdio_bus *fmb = &platform_fmb;
 381        struct fixed_phy *fp, *tmp;
 382
 383        mdiobus_unregister(fmb->mii_bus);
 384        mdiobus_free(fmb->mii_bus);
 385        platform_device_unregister(pdev);
 386
 387        list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
 388                list_del(&fp->node);
 389                kfree(fp);
 390        }
 391        ida_destroy(&phy_fixed_ida);
 392}
 393module_exit(fixed_mdio_bus_exit);
 394
 395MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
 396MODULE_AUTHOR("Vitaly Bordug");
 397MODULE_LICENSE("GPL");
 398