示例#1
0
/* mdio_bus_match
 *
 * description: Given a PHY device, and a PHY driver, return 1 if
 *   the driver supports the device.  Otherwise, return 0
 */
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
	struct phy_device *phydev = to_phy_device(dev);
	struct phy_driver *phydrv = to_phy_driver(drv);

	return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask));
}
示例#2
0
/**
 * phy_attach - attach a network device to a particular PHY device
 * @dev: network device to attach
 * @phy_id: PHY device to attach
 * @flags: PHY device's dev_flags
 * @interface: PHY device's interface
 *
 * Description: Called by drivers to attach to a particular PHY
 *     device. The phy_device is found, and properly hooked up
 *     to the phy_driver.  If no driver is attached, then the
 *     genphy_driver is used.  The phy_device is given a ptr to
 *     the attaching device, and given a callback for link status
 *     change.  The phy_device is returned to the attaching driver.
 */
struct phy_device *phy_attach(struct net_device *dev,
		const char *phy_id, u32 flags, phy_interface_t interface)
{
	struct bus_type *bus = &mdio_bus_type;
	struct phy_device *phydev;
	struct device *d;

	/* Search the list of PHY devices on the mdio bus for the
	 * PHY with the requested name */
	d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id);

	if (d) {
		phydev = to_phy_device(d);
	} else {
		printk(KERN_ERR "%s not found\n", phy_id);
		return ERR_PTR(-ENODEV);
	}

	/* Assume that if there is no driver, that it doesn't
	 * exist, and we should use the genphy driver. */
	if (NULL == d->driver) {
		int err;
		d->driver = &genphy_driver.driver;

		err = d->driver->probe(d);
		if (err >= 0)
			err = device_bind_driver(d);

		if (err)
			return ERR_PTR(err);
	}

	if (phydev->attached_dev) {
		printk(KERN_ERR "%s: %s already attached\n",
				dev->name, phy_id);
		return ERR_PTR(-EBUSY);
	}

	phydev->attached_dev = dev;

	phydev->dev_flags = flags;

	phydev->interface = interface;

	/* Do initial configuration here, now that
	 * we have certain key parameters
	 * (dev_flags and interface) */
	if (phydev->drv->config_init) {
		int err;

		err = phydev->drv->config_init(phydev);

		if (err < 0)
			return ERR_PTR(err);
	}

	return phydev;
}
struct phy_device *of_phy_find_device(struct device_node *phy_np)
{
	struct device *d;
	if (!phy_np)
		return NULL;

	d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);
	return d ? to_phy_device(d) : NULL;
}
示例#4
0
static void mdio_bus_remove(struct device_d *_dev)
{
	struct phy_device *dev = to_phy_device(_dev);
	struct phy_driver *drv = to_phy_driver(_dev->driver);

	if (drv->remove)
		drv->remove(dev);

	free(dev->cdev.name);
	devfs_remove(&dev->cdev);
}
示例#5
0
static int mdio_bus_probe(struct device_d *_dev)
{
	struct phy_device *dev = to_phy_device(_dev);
	struct phy_driver *drv = to_phy_driver(_dev->driver);

	int ret;

	if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto err;
	}

	if (dev->dev_flags) {
		if (dev->dev_flags & PHYLIB_FORCE_10) {
			dev->speed = SPEED_10;
			dev->duplex = DUPLEX_FULL;
			dev->autoneg = !AUTONEG_ENABLE;
			dev->force = 1;
			dev->link = 1;
		} else if (dev->dev_flags & PHYLIB_FORCE_100) {
			dev->speed = SPEED_100;
			dev->duplex = DUPLEX_FULL;
			dev->autoneg = !AUTONEG_ENABLE;
			dev->force = 1;
			dev->link = 1;
		}
	}

	/* Start out supporting everything. Eventually,
	 * a controller will attach, and may modify one
	 * or both of these values */
	dev->supported = drv->features;
	dev->advertising = drv->features;

	dev_add_param_int_ro(&dev->dev, "phy_addr", dev->addr, "%d");
	dev_add_param_int_ro(&dev->dev, "phy_id", dev->phy_id, "0x%08x");

	dev->cdev.name = asprintf("phy%d", _dev->id);
	dev->cdev.size = 64;
	dev->cdev.ops = &phydev_ops;
	dev->cdev.priv = dev;
	dev->cdev.dev = _dev;
	devfs_create(&dev->cdev);

	return 0;

err:
	return ret;
}
示例#6
0
struct phy_device *phy_attach(struct net_device *dev,
		const char *phy_id, u32 flags)
{
	struct bus_type *bus = &mdio_bus_type;
	struct phy_device *phydev;
	struct device *d;

	/* Search the list of PHY devices on the mdio bus for the
	 * PHY with the requested name */
	d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id);

	if (d) {
		phydev = to_phy_device(d);
	} else {
		printk(KERN_ERR "%s not found\n", phy_id);
		return ERR_PTR(-ENODEV);
	}

	/* Assume that if there is no driver, that it doesn't
	 * exist, and we should use the genphy driver. */
	if (NULL == d->driver) {
		int err;
		down_write(&d->bus->subsys.rwsem);
		d->driver = &genphy_driver.driver;

		err = d->driver->probe(d);

		if (err < 0)
			return ERR_PTR(err);

		device_bind_driver(d);
		up_write(&d->bus->subsys.rwsem);
	}

	if (phydev->attached_dev) {
		printk(KERN_ERR "%s: %s already attached\n",
				dev->name, phy_id);
		return ERR_PTR(-EBUSY);
	}

	phydev->attached_dev = dev;

	phydev->dev_flags = flags;

	return phydev;
}
示例#7
0
static int phy_remove(struct device *dev)
{
	struct phy_device *phydev;

	phydev = to_phy_device(dev);

	mutex_lock(&phydev->lock);
	phydev->state = PHY_DOWN;
	mutex_unlock(&phydev->lock);

	if (phydev->drv->remove)
		phydev->drv->remove(phydev);

	put_driver(dev->driver);
	phydev->drv = NULL;

	return 0;
}
示例#8
0
/* phy_probe
 *
 * description: Take care of setting up the phy_device structure,
 *   set the state to READY (the driver's init function should
 *   set it to STARTING if needed).
 */
static int phy_probe(struct device *dev)
{
	struct phy_device *phydev;
	struct phy_driver *phydrv;
	struct device_driver *drv;
	int err = 0;

	phydev = to_phy_device(dev);

	/* Make sure the driver is held.
	 * XXX -- Is this correct? */
	drv = get_driver(phydev->dev.driver);
	phydrv = to_phy_driver(drv);
	phydev->drv = phydrv;

	/* Disable the interrupt if the PHY doesn't support it */
	if (!(phydrv->flags & PHY_HAS_INTERRUPT))
		phydev->irq = PHY_POLL;

	spin_lock(&phydev->lock);

	/* Start out supporting everything. Eventually,
	 * a controller will attach, and may modify one
	 * or both of these values */
	phydev->supported = phydrv->features;
	phydev->advertising = phydrv->features;

	/* Set the state to READY by default */
	phydev->state = PHY_READY;

	if (phydev->drv->probe)
		err = phydev->drv->probe(phydev);

	spin_unlock(&phydev->lock);

	if (err < 0)
		return err;

	if (phydev->drv->config_init)
		err = phydev->drv->config_init(phydev);

	return err;
}
static void phy_device_release(struct device *dev)
{
	phy_device_free(to_phy_device(dev));
}
示例#10
0
static int mdio_bus_probe(struct device_d *_dev)
{
	struct phy_device *dev = to_phy_device(_dev);
	struct phy_driver *drv = to_phy_driver(_dev->driver);

	int ret;
	char str[16];

	dev->attached_dev->phydev = dev;

	if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto err;
	}

	if (dev->dev_flags) {
		if (dev->dev_flags & PHYLIB_FORCE_10) {
			dev->speed = SPEED_10;
			dev->duplex = DUPLEX_FULL;
			dev->autoneg = !AUTONEG_ENABLE;
			dev->force = 1;
			dev->link = 1;
		} else if (dev->dev_flags & PHYLIB_FORCE_100) {
			dev->speed = SPEED_100;
			dev->duplex = DUPLEX_FULL;
			dev->autoneg = !AUTONEG_ENABLE;
			dev->force = 1;
			dev->link = 1;
		}
	}

	/* Start out supporting everything. Eventually,
	 * a controller will attach, and may modify one
	 * or both of these values */
	dev->supported = drv->features;
	dev->advertising = drv->features;

	ret = phy_init_hw(dev);
	if (ret)
		goto err;

	/* Sanitize settings based on PHY capabilities */
	if ((dev->supported & SUPPORTED_Autoneg) == 0)
		dev->autoneg = AUTONEG_DISABLE;

	sprintf(str, "%d", dev->addr);
	dev_add_param_fixed(&dev->dev, "phy_addr", str);

	sprintf(str, "0x%08x", dev->phy_id);
	dev_add_param_fixed(&dev->dev, "phy_id", str);

	dev->cdev.name = asprintf("phy%d", _dev->id);
	dev->cdev.size = 64;
	dev->cdev.ops = &phydev_ops;
	dev->cdev.priv = dev;
	dev->cdev.dev = _dev;
	devfs_create(&dev->cdev);

	return 0;

err:
	dev->attached_dev->phydev = NULL;
	dev->attached_dev = NULL;
	return ret;
}