Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
0004  *
0005  * Author: Vitaly Bordug <vbordug@ru.mvista.com>
0006  *         Anton Vorontsov <avorontsov@ru.mvista.com>
0007  *
0008  * Copyright (c) 2006-2007 MontaVista Software, Inc.
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/list.h>
0015 #include <linux/mii.h>
0016 #include <linux/phy.h>
0017 #include <linux/phy_fixed.h>
0018 #include <linux/err.h>
0019 #include <linux/slab.h>
0020 #include <linux/of.h>
0021 #include <linux/gpio/consumer.h>
0022 #include <linux/idr.h>
0023 #include <linux/netdevice.h>
0024 #include <linux/linkmode.h>
0025 
0026 #include "swphy.h"
0027 
0028 struct fixed_mdio_bus {
0029     struct mii_bus *mii_bus;
0030     struct list_head phys;
0031 };
0032 
0033 struct fixed_phy {
0034     int addr;
0035     struct phy_device *phydev;
0036     struct fixed_phy_status status;
0037     bool no_carrier;
0038     int (*link_update)(struct net_device *, struct fixed_phy_status *);
0039     struct list_head node;
0040     struct gpio_desc *link_gpiod;
0041 };
0042 
0043 static struct platform_device *pdev;
0044 static struct fixed_mdio_bus platform_fmb = {
0045     .phys = LIST_HEAD_INIT(platform_fmb.phys),
0046 };
0047 
0048 int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier)
0049 {
0050     struct fixed_mdio_bus *fmb = &platform_fmb;
0051     struct phy_device *phydev = dev->phydev;
0052     struct fixed_phy *fp;
0053 
0054     if (!phydev || !phydev->mdio.bus)
0055         return -EINVAL;
0056 
0057     list_for_each_entry(fp, &fmb->phys, node) {
0058         if (fp->addr == phydev->mdio.addr) {
0059             fp->no_carrier = !new_carrier;
0060             return 0;
0061         }
0062     }
0063     return -EINVAL;
0064 }
0065 EXPORT_SYMBOL_GPL(fixed_phy_change_carrier);
0066 
0067 static void fixed_phy_update(struct fixed_phy *fp)
0068 {
0069     if (!fp->no_carrier && fp->link_gpiod)
0070         fp->status.link = !!gpiod_get_value_cansleep(fp->link_gpiod);
0071 }
0072 
0073 static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
0074 {
0075     struct fixed_mdio_bus *fmb = bus->priv;
0076     struct fixed_phy *fp;
0077 
0078     list_for_each_entry(fp, &fmb->phys, node) {
0079         if (fp->addr == phy_addr) {
0080             struct fixed_phy_status state;
0081 
0082             fp->status.link = !fp->no_carrier;
0083 
0084             /* Issue callback if user registered it. */
0085             if (fp->link_update)
0086                 fp->link_update(fp->phydev->attached_dev,
0087                         &fp->status);
0088 
0089             /* Check the GPIO for change in status */
0090             fixed_phy_update(fp);
0091             state = fp->status;
0092 
0093             return swphy_read_reg(reg_num, &state);
0094         }
0095     }
0096 
0097     return 0xFFFF;
0098 }
0099 
0100 static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
0101                 u16 val)
0102 {
0103     return 0;
0104 }
0105 
0106 /*
0107  * If something weird is required to be done with link/speed,
0108  * network driver is able to assign a function to implement this.
0109  * May be useful for PHY's that need to be software-driven.
0110  */
0111 int fixed_phy_set_link_update(struct phy_device *phydev,
0112                   int (*link_update)(struct net_device *,
0113                          struct fixed_phy_status *))
0114 {
0115     struct fixed_mdio_bus *fmb = &platform_fmb;
0116     struct fixed_phy *fp;
0117 
0118     if (!phydev || !phydev->mdio.bus)
0119         return -EINVAL;
0120 
0121     list_for_each_entry(fp, &fmb->phys, node) {
0122         if (fp->addr == phydev->mdio.addr) {
0123             fp->link_update = link_update;
0124             fp->phydev = phydev;
0125             return 0;
0126         }
0127     }
0128 
0129     return -ENOENT;
0130 }
0131 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
0132 
0133 static int fixed_phy_add_gpiod(unsigned int irq, int phy_addr,
0134                    struct fixed_phy_status *status,
0135                    struct gpio_desc *gpiod)
0136 {
0137     int ret;
0138     struct fixed_mdio_bus *fmb = &platform_fmb;
0139     struct fixed_phy *fp;
0140 
0141     ret = swphy_validate_state(status);
0142     if (ret < 0)
0143         return ret;
0144 
0145     fp = kzalloc(sizeof(*fp), GFP_KERNEL);
0146     if (!fp)
0147         return -ENOMEM;
0148 
0149     if (irq != PHY_POLL)
0150         fmb->mii_bus->irq[phy_addr] = irq;
0151 
0152     fp->addr = phy_addr;
0153     fp->status = *status;
0154     fp->link_gpiod = gpiod;
0155 
0156     fixed_phy_update(fp);
0157 
0158     list_add_tail(&fp->node, &fmb->phys);
0159 
0160     return 0;
0161 }
0162 
0163 int fixed_phy_add(unsigned int irq, int phy_addr,
0164           struct fixed_phy_status *status)
0165 {
0166     return fixed_phy_add_gpiod(irq, phy_addr, status, NULL);
0167 }
0168 EXPORT_SYMBOL_GPL(fixed_phy_add);
0169 
0170 static DEFINE_IDA(phy_fixed_ida);
0171 
0172 static void fixed_phy_del(int phy_addr)
0173 {
0174     struct fixed_mdio_bus *fmb = &platform_fmb;
0175     struct fixed_phy *fp, *tmp;
0176 
0177     list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
0178         if (fp->addr == phy_addr) {
0179             list_del(&fp->node);
0180             if (fp->link_gpiod)
0181                 gpiod_put(fp->link_gpiod);
0182             kfree(fp);
0183             ida_free(&phy_fixed_ida, phy_addr);
0184             return;
0185         }
0186     }
0187 }
0188 
0189 #ifdef CONFIG_OF_GPIO
0190 static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np)
0191 {
0192     struct device_node *fixed_link_node;
0193     struct gpio_desc *gpiod;
0194 
0195     if (!np)
0196         return NULL;
0197 
0198     fixed_link_node = of_get_child_by_name(np, "fixed-link");
0199     if (!fixed_link_node)
0200         return NULL;
0201 
0202     /*
0203      * As the fixed link is just a device tree node without any
0204      * Linux device associated with it, we simply have obtain
0205      * the GPIO descriptor from the device tree like this.
0206      */
0207     gpiod = fwnode_gpiod_get_index(of_fwnode_handle(fixed_link_node),
0208                        "link", 0, GPIOD_IN, "mdio");
0209     if (IS_ERR(gpiod) && PTR_ERR(gpiod) != -EPROBE_DEFER) {
0210         if (PTR_ERR(gpiod) != -ENOENT)
0211             pr_err("error getting GPIO for fixed link %pOF, proceed without\n",
0212                    fixed_link_node);
0213         gpiod = NULL;
0214     }
0215     of_node_put(fixed_link_node);
0216 
0217     return gpiod;
0218 }
0219 #else
0220 static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np)
0221 {
0222     return NULL;
0223 }
0224 #endif
0225 
0226 static struct phy_device *__fixed_phy_register(unsigned int irq,
0227                            struct fixed_phy_status *status,
0228                            struct device_node *np,
0229                            struct gpio_desc *gpiod)
0230 {
0231     struct fixed_mdio_bus *fmb = &platform_fmb;
0232     struct phy_device *phy;
0233     int phy_addr;
0234     int ret;
0235 
0236     if (!fmb->mii_bus || fmb->mii_bus->state != MDIOBUS_REGISTERED)
0237         return ERR_PTR(-EPROBE_DEFER);
0238 
0239     /* Check if we have a GPIO associated with this fixed phy */
0240     if (!gpiod) {
0241         gpiod = fixed_phy_get_gpiod(np);
0242         if (IS_ERR(gpiod))
0243             return ERR_CAST(gpiod);
0244     }
0245 
0246     /* Get the next available PHY address, up to PHY_MAX_ADDR */
0247     phy_addr = ida_alloc_max(&phy_fixed_ida, PHY_MAX_ADDR - 1, GFP_KERNEL);
0248     if (phy_addr < 0)
0249         return ERR_PTR(phy_addr);
0250 
0251     ret = fixed_phy_add_gpiod(irq, phy_addr, status, gpiod);
0252     if (ret < 0) {
0253         ida_free(&phy_fixed_ida, phy_addr);
0254         return ERR_PTR(ret);
0255     }
0256 
0257     phy = get_phy_device(fmb->mii_bus, phy_addr, false);
0258     if (IS_ERR(phy)) {
0259         fixed_phy_del(phy_addr);
0260         return ERR_PTR(-EINVAL);
0261     }
0262 
0263     /* propagate the fixed link values to struct phy_device */
0264     phy->link = status->link;
0265     if (status->link) {
0266         phy->speed = status->speed;
0267         phy->duplex = status->duplex;
0268         phy->pause = status->pause;
0269         phy->asym_pause = status->asym_pause;
0270     }
0271 
0272     of_node_get(np);
0273     phy->mdio.dev.of_node = np;
0274     phy->is_pseudo_fixed_link = true;
0275 
0276     switch (status->speed) {
0277     case SPEED_1000:
0278         linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
0279                  phy->supported);
0280         linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
0281                  phy->supported);
0282         fallthrough;
0283     case SPEED_100:
0284         linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
0285                  phy->supported);
0286         linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
0287                  phy->supported);
0288         fallthrough;
0289     case SPEED_10:
0290     default:
0291         linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
0292                  phy->supported);
0293         linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
0294                  phy->supported);
0295     }
0296 
0297     phy_advertise_supported(phy);
0298 
0299     ret = phy_device_register(phy);
0300     if (ret) {
0301         phy_device_free(phy);
0302         of_node_put(np);
0303         fixed_phy_del(phy_addr);
0304         return ERR_PTR(ret);
0305     }
0306 
0307     return phy;
0308 }
0309 
0310 struct phy_device *fixed_phy_register(unsigned int irq,
0311                       struct fixed_phy_status *status,
0312                       struct device_node *np)
0313 {
0314     return __fixed_phy_register(irq, status, np, NULL);
0315 }
0316 EXPORT_SYMBOL_GPL(fixed_phy_register);
0317 
0318 struct phy_device *
0319 fixed_phy_register_with_gpiod(unsigned int irq,
0320                   struct fixed_phy_status *status,
0321                   struct gpio_desc *gpiod)
0322 {
0323     return __fixed_phy_register(irq, status, NULL, gpiod);
0324 }
0325 EXPORT_SYMBOL_GPL(fixed_phy_register_with_gpiod);
0326 
0327 void fixed_phy_unregister(struct phy_device *phy)
0328 {
0329     phy_device_remove(phy);
0330     of_node_put(phy->mdio.dev.of_node);
0331     fixed_phy_del(phy->mdio.addr);
0332 }
0333 EXPORT_SYMBOL_GPL(fixed_phy_unregister);
0334 
0335 static int __init fixed_mdio_bus_init(void)
0336 {
0337     struct fixed_mdio_bus *fmb = &platform_fmb;
0338     int ret;
0339 
0340     pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
0341     if (IS_ERR(pdev))
0342         return PTR_ERR(pdev);
0343 
0344     fmb->mii_bus = mdiobus_alloc();
0345     if (fmb->mii_bus == NULL) {
0346         ret = -ENOMEM;
0347         goto err_mdiobus_reg;
0348     }
0349 
0350     snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
0351     fmb->mii_bus->name = "Fixed MDIO Bus";
0352     fmb->mii_bus->priv = fmb;
0353     fmb->mii_bus->parent = &pdev->dev;
0354     fmb->mii_bus->read = &fixed_mdio_read;
0355     fmb->mii_bus->write = &fixed_mdio_write;
0356     fmb->mii_bus->phy_mask = ~0;
0357 
0358     ret = mdiobus_register(fmb->mii_bus);
0359     if (ret)
0360         goto err_mdiobus_alloc;
0361 
0362     return 0;
0363 
0364 err_mdiobus_alloc:
0365     mdiobus_free(fmb->mii_bus);
0366 err_mdiobus_reg:
0367     platform_device_unregister(pdev);
0368     return ret;
0369 }
0370 module_init(fixed_mdio_bus_init);
0371 
0372 static void __exit fixed_mdio_bus_exit(void)
0373 {
0374     struct fixed_mdio_bus *fmb = &platform_fmb;
0375     struct fixed_phy *fp, *tmp;
0376 
0377     mdiobus_unregister(fmb->mii_bus);
0378     mdiobus_free(fmb->mii_bus);
0379     platform_device_unregister(pdev);
0380 
0381     list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
0382         list_del(&fp->node);
0383         kfree(fp);
0384     }
0385     ida_destroy(&phy_fixed_ida);
0386 }
0387 module_exit(fixed_mdio_bus_exit);
0388 
0389 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
0390 MODULE_AUTHOR("Vitaly Bordug");
0391 MODULE_LICENSE("GPL");