Linux Audio

Check our new training course

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