linux/drivers/net/phy/mdio_device.c
<<
>>
Prefs
   1/* Framework for MDIO devices, other than PHYs.
   2 *
   3 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
   4 *
   5 * This program is free software; you can redistribute  it and/or modify it
   6 * under  the terms of  the GNU General  Public License as published by the
   7 * Free Software Foundation;  either version 2 of the  License, or (at your
   8 * option) any later version.
   9 *
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13
  14#include <linux/errno.h>
  15#include <linux/init.h>
  16#include <linux/interrupt.h>
  17#include <linux/kernel.h>
  18#include <linux/mdio.h>
  19#include <linux/mii.h>
  20#include <linux/module.h>
  21#include <linux/phy.h>
  22#include <linux/slab.h>
  23#include <linux/string.h>
  24#include <linux/unistd.h>
  25
  26void mdio_device_free(struct mdio_device *mdiodev)
  27{
  28        put_device(&mdiodev->dev);
  29}
  30EXPORT_SYMBOL(mdio_device_free);
  31
  32static void mdio_device_release(struct device *dev)
  33{
  34        kfree(to_mdio_device(dev));
  35}
  36
  37struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
  38{
  39        struct mdio_device *mdiodev;
  40
  41        /* We allocate the device, and initialize the default values */
  42        mdiodev = kzalloc(sizeof(*mdiodev), GFP_KERNEL);
  43        if (!mdiodev)
  44                return ERR_PTR(-ENOMEM);
  45
  46        mdiodev->dev.release = mdio_device_release;
  47        mdiodev->dev.parent = &bus->dev;
  48        mdiodev->dev.bus = &mdio_bus_type;
  49        mdiodev->device_free = mdio_device_free;
  50        mdiodev->device_remove = mdio_device_remove;
  51        mdiodev->bus = bus;
  52        mdiodev->addr = addr;
  53
  54        dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);
  55
  56        device_initialize(&mdiodev->dev);
  57
  58        return mdiodev;
  59}
  60EXPORT_SYMBOL(mdio_device_create);
  61
  62/**
  63 * mdio_device_register - Register the mdio device on the MDIO bus
  64 * @mdiodev: mdio_device structure to be added to the MDIO bus
  65 */
  66int mdio_device_register(struct mdio_device *mdiodev)
  67{
  68        int err;
  69
  70        dev_info(&mdiodev->dev, "mdio_device_register\n");
  71
  72        err = mdiobus_register_device(mdiodev);
  73        if (err)
  74                return err;
  75
  76        err = device_add(&mdiodev->dev);
  77        if (err) {
  78                pr_err("MDIO %d failed to add\n", mdiodev->addr);
  79                goto out;
  80        }
  81
  82        return 0;
  83
  84 out:
  85        mdiobus_unregister_device(mdiodev);
  86        return err;
  87}
  88EXPORT_SYMBOL(mdio_device_register);
  89
  90/**
  91 * mdio_device_remove - Remove a previously registered mdio device from the
  92 *                      MDIO bus
  93 * @mdiodev: mdio_device structure to remove
  94 *
  95 * This doesn't free the mdio_device itself, it merely reverses the effects
  96 * of mdio_device_register(). Use mdio_device_free() to free the device
  97 * after calling this function.
  98 */
  99void mdio_device_remove(struct mdio_device *mdiodev)
 100{
 101        device_del(&mdiodev->dev);
 102        mdiobus_unregister_device(mdiodev);
 103}
 104EXPORT_SYMBOL(mdio_device_remove);
 105
 106/**
 107 * mdio_probe - probe an MDIO device
 108 * @dev: device to probe
 109 *
 110 * Description: Take care of setting up the mdio_device structure
 111 * and calling the driver to probe the device.
 112 */
 113static int mdio_probe(struct device *dev)
 114{
 115        struct mdio_device *mdiodev = to_mdio_device(dev);
 116        struct device_driver *drv = mdiodev->dev.driver;
 117        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
 118        int err = 0;
 119
 120        if (mdiodrv->probe)
 121                err = mdiodrv->probe(mdiodev);
 122
 123        return err;
 124}
 125
 126static int mdio_remove(struct device *dev)
 127{
 128        struct mdio_device *mdiodev = to_mdio_device(dev);
 129        struct device_driver *drv = mdiodev->dev.driver;
 130        struct mdio_driver *mdiodrv = to_mdio_driver(drv);
 131
 132        if (mdiodrv->remove)
 133                mdiodrv->remove(mdiodev);
 134
 135        return 0;
 136}
 137
 138/**
 139 * mdio_driver_register - register an mdio_driver with the MDIO layer
 140 * @new_driver: new mdio_driver to register
 141 */
 142int mdio_driver_register(struct mdio_driver *drv)
 143{
 144        struct mdio_driver_common *mdiodrv = &drv->mdiodrv;
 145        int retval;
 146
 147        pr_info("mdio_driver_register: %s\n", mdiodrv->driver.name);
 148
 149        mdiodrv->driver.bus = &mdio_bus_type;
 150        mdiodrv->driver.probe = mdio_probe;
 151        mdiodrv->driver.remove = mdio_remove;
 152
 153        retval = driver_register(&mdiodrv->driver);
 154        if (retval) {
 155                pr_err("%s: Error %d in registering driver\n",
 156                       mdiodrv->driver.name, retval);
 157
 158                return retval;
 159        }
 160
 161        return 0;
 162}
 163EXPORT_SYMBOL(mdio_driver_register);
 164
 165void mdio_driver_unregister(struct mdio_driver *drv)
 166{
 167        struct mdio_driver_common *mdiodrv = &drv->mdiodrv;
 168
 169        driver_unregister(&mdiodrv->driver);
 170}
 171EXPORT_SYMBOL(mdio_driver_unregister);
 172