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 26 void mdio_device_free(struct mdio_device *mdiodev) 27 { 28 put_device(&mdiodev->dev); 29 } 30 EXPORT_SYMBOL(mdio_device_free); 31 32 static void mdio_device_release(struct device *dev) 33 { 34 kfree(to_mdio_device(dev)); 35 } 36 37 struct 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 } 60 EXPORT_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 */ 66 int 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 } 88 EXPORT_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 */ 99 void mdio_device_remove(struct mdio_device *mdiodev) 100 { 101 device_del(&mdiodev->dev); 102 mdiobus_unregister_device(mdiodev); 103 } 104 EXPORT_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 */ 113 static 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 126 static 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 */ 142 int 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 } 163 EXPORT_SYMBOL(mdio_driver_register); 164 165 void mdio_driver_unregister(struct mdio_driver *drv) 166 { 167 struct mdio_driver_common *mdiodrv = &drv->mdiodrv; 168 169 driver_unregister(&mdiodrv->driver); 170 } 171 EXPORT_SYMBOL(mdio_driver_unregister); 172