linux/drivers/net/phy/mdio_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/* Framework for MDIO devices, other than PHYs.
   3 *
   4 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
   5 */
   6
   7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   8
   9#include <linux/delay.h>
  10#include <linux/errno.h>
  11#include <linux/gpio.h>
  12#include <linux/gpio/consumer.h>
  13#include <linux/init.h>
  14#include <linux/interrupt.h>
  15#include <linux/kernel.h>
  16#include <linux/mdio.h>
  17#include <linux/mii.h>
  18#include <linux/module.h>
  19#include <linux/phy.h>
  20#include <linux/reset.h>
  21#include <linux/slab.h>
  22#include <linux/string.h>
  23#include <linux/unistd.h>
  24
  25void mdio_device_free(struct mdio_device *mdiodev)
  26{
  27        put_device(&mdiodev->dev);
  28}
  29EXPORT_SYMBOL(mdio_device_free);
  30
  31static void mdio_device_release(struct device *dev)
  32{
  33        kfree(to_mdio_device(dev));
  34}
  35
  36int mdio_device_bus_match(struct device *dev, struct device_driver *drv)
  37{
  38        struct mdio_device *mdiodev = to_mdio_device(dev);
  39        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
  40
  41        if (mdiodrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)
  42                return 0;
  43
  44        return strcmp(mdiodev->modalias, drv->name) == 0;
  45}
  46
  47struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
  48{
  49        struct mdio_device *mdiodev;
  50
  51        /* We allocate the device, and initialize the default values */
  52        mdiodev = kzalloc(sizeof(*mdiodev), GFP_KERNEL);
  53        if (!mdiodev)
  54                return ERR_PTR(-ENOMEM);
  55
  56        mdiodev->dev.release = mdio_device_release;
  57        mdiodev->dev.parent = &bus->dev;
  58        mdiodev->dev.bus = &mdio_bus_type;
  59        mdiodev->device_free = mdio_device_free;
  60        mdiodev->device_remove = mdio_device_remove;
  61        mdiodev->bus = bus;
  62        mdiodev->addr = addr;
  63
  64        dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);
  65
  66        device_initialize(&mdiodev->dev);
  67
  68        return mdiodev;
  69}
  70EXPORT_SYMBOL(mdio_device_create);
  71
  72/**
  73 * mdio_device_register - Register the mdio device on the MDIO bus
  74 * @mdiodev: mdio_device structure to be added to the MDIO bus
  75 */
  76int mdio_device_register(struct mdio_device *mdiodev)
  77{
  78        int err;
  79
  80        dev_dbg(&mdiodev->dev, "%s\n", __func__);
  81
  82        err = mdiobus_register_device(mdiodev);
  83        if (err)
  84                return err;
  85
  86        err = device_add(&mdiodev->dev);
  87        if (err) {
  88                pr_err("MDIO %d failed to add\n", mdiodev->addr);
  89                goto out;
  90        }
  91
  92        return 0;
  93
  94 out:
  95        mdiobus_unregister_device(mdiodev);
  96        return err;
  97}
  98EXPORT_SYMBOL(mdio_device_register);
  99
 100/**
 101 * mdio_device_remove - Remove a previously registered mdio device from the
 102 *                      MDIO bus
 103 * @mdiodev: mdio_device structure to remove
 104 *
 105 * This doesn't free the mdio_device itself, it merely reverses the effects
 106 * of mdio_device_register(). Use mdio_device_free() to free the device
 107 * after calling this function.
 108 */
 109void mdio_device_remove(struct mdio_device *mdiodev)
 110{
 111        device_del(&mdiodev->dev);
 112        mdiobus_unregister_device(mdiodev);
 113}
 114EXPORT_SYMBOL(mdio_device_remove);
 115
 116void mdio_device_reset(struct mdio_device *mdiodev, int value)
 117{
 118        unsigned int d;
 119
 120        if (!mdiodev->reset_gpio && !mdiodev->reset_ctrl)
 121                return;
 122
 123        if (mdiodev->reset_gpio)
 124                gpiod_set_value_cansleep(mdiodev->reset_gpio, value);
 125
 126        if (mdiodev->reset_ctrl) {
 127                if (value)
 128                        reset_control_assert(mdiodev->reset_ctrl);
 129                else
 130                        reset_control_deassert(mdiodev->reset_ctrl);
 131        }
 132
 133        d = value ? mdiodev->reset_assert_delay : mdiodev->reset_deassert_delay;
 134        if (d)
 135                fsleep(d);
 136}
 137EXPORT_SYMBOL(mdio_device_reset);
 138
 139/**
 140 * mdio_probe - probe an MDIO device
 141 * @dev: device to probe
 142 *
 143 * Description: Take care of setting up the mdio_device structure
 144 * and calling the driver to probe the device.
 145 */
 146static int mdio_probe(struct device *dev)
 147{
 148        struct mdio_device *mdiodev = to_mdio_device(dev);
 149        struct device_driver *drv = mdiodev->dev.driver;
 150        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
 151        int err = 0;
 152
 153        /* Deassert the reset signal */
 154        mdio_device_reset(mdiodev, 0);
 155
 156        if (mdiodrv->probe) {
 157                err = mdiodrv->probe(mdiodev);
 158                if (err) {
 159                        /* Assert the reset signal */
 160                        mdio_device_reset(mdiodev, 1);
 161                }
 162        }
 163
 164        return err;
 165}
 166
 167static int mdio_remove(struct device *dev)
 168{
 169        struct mdio_device *mdiodev = to_mdio_device(dev);
 170        struct device_driver *drv = mdiodev->dev.driver;
 171        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
 172
 173        if (mdiodrv->remove)
 174                mdiodrv->remove(mdiodev);
 175
 176        /* Assert the reset signal */
 177        mdio_device_reset(mdiodev, 1);
 178
 179        return 0;
 180}
 181
 182static void mdio_shutdown(struct device *dev)
 183{
 184        struct mdio_device *mdiodev = to_mdio_device(dev);
 185        struct device_driver *drv = mdiodev->dev.driver;
 186        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
 187
 188        if (mdiodrv->shutdown)
 189                mdiodrv->shutdown(mdiodev);
 190}
 191
 192/**
 193 * mdio_driver_register - register an mdio_driver with the MDIO layer
 194 * @drv: new mdio_driver to register
 195 */
 196int mdio_driver_register(struct mdio_driver *drv)
 197{
 198        struct mdio_driver_common *mdiodrv = &drv->mdiodrv;
 199        int retval;
 200
 201        pr_debug("%s: %s\n", __func__, mdiodrv->driver.name);
 202
 203        mdiodrv->driver.bus = &mdio_bus_type;
 204        mdiodrv->driver.probe = mdio_probe;
 205        mdiodrv->driver.remove = mdio_remove;
 206        mdiodrv->driver.shutdown = mdio_shutdown;
 207
 208        retval = driver_register(&mdiodrv->driver);
 209        if (retval) {
 210                pr_err("%s: Error %d in registering driver\n",
 211                       mdiodrv->driver.name, retval);
 212
 213                return retval;
 214        }
 215
 216        return 0;
 217}
 218EXPORT_SYMBOL(mdio_driver_register);
 219
 220void mdio_driver_unregister(struct mdio_driver *drv)
 221{
 222        struct mdio_driver_common *mdiodrv = &drv->mdiodrv;
 223
 224        driver_unregister(&mdiodrv->driver);
 225}
 226EXPORT_SYMBOL(mdio_driver_unregister);
 227