コード例 #1
0
ファイル: mdio-gpio.c プロジェクト: 7799/linux
static int mdio_gpio_probe(struct platform_device *pdev)
{
	struct mdio_gpio_platform_data *pdata;
	struct mii_bus *new_bus;
	int ret, bus_id;

	if (pdev->dev.of_node) {
		pdata = mdio_gpio_of_get_data(pdev);
		bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio");
	} else {
		pdata = dev_get_platdata(&pdev->dev);
		bus_id = pdev->id;
	}

	if (!pdata)
		return -ENODEV;

	new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, bus_id);
	if (!new_bus)
		return -ENODEV;

	if (pdev->dev.of_node)
		ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
	else
		ret = mdiobus_register(new_bus);

	if (ret)
		mdio_gpio_bus_deinit(&pdev->dev);

	return ret;
}
コード例 #2
0
ファイル: mdio-gpio.c プロジェクト: markus-oberhumer/linux
static int mdio_gpio_probe(struct platform_device *pdev)
{
	struct mdio_gpio_info *bitbang;
	struct mii_bus *new_bus;
	int ret, bus_id;

	bitbang = devm_kzalloc(&pdev->dev, sizeof(*bitbang), GFP_KERNEL);
	if (!bitbang)
		return -ENOMEM;

	ret = mdio_gpio_get_data(&pdev->dev, bitbang);
	if (ret)
		return ret;

	if (pdev->dev.of_node) {
		bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio");
		if (bus_id < 0) {
			dev_warn(&pdev->dev, "failed to get alias id\n");
			bus_id = 0;
		}
	} else {
		bus_id = pdev->id;
	}

	new_bus = mdio_gpio_bus_init(&pdev->dev, bitbang, bus_id);
	if (!new_bus)
		return -ENODEV;

	ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
	if (ret)
		mdio_gpio_bus_deinit(&pdev->dev);

	return ret;
}
コード例 #3
0
ファイル: mdio-gpio.c プロジェクト: AllenDou/linux
static int __devinit mdio_gpio_probe(struct platform_device *pdev)
{
	struct mdio_gpio_platform_data *pdata;
	struct mii_bus *new_bus;
	int ret;

	if (pdev->dev.of_node)
		pdata = mdio_gpio_of_get_data(pdev);
	else
		pdata = pdev->dev.platform_data;

	if (!pdata)
		return -ENODEV;

	new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
	if (!new_bus)
		return -ENODEV;

	if (pdev->dev.of_node)
		ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
	else
		ret = mdiobus_register(new_bus);

	if (ret)
		mdio_gpio_bus_deinit(&pdev->dev);

	return ret;
}
コード例 #4
0
ファイル: bcmmii.c プロジェクト: Amitabha2001/linux
static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
{
	struct device_node *dn = priv->pdev->dev.of_node;
	struct device *kdev = &priv->pdev->dev;
	struct device_node *mdio_dn;
	char *compat;
	int ret;

	compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
	if (!compat)
		return -ENOMEM;

	mdio_dn = of_find_compatible_node(dn, NULL, compat);
	kfree(compat);
	if (!mdio_dn) {
		dev_err(kdev, "unable to find MDIO bus node\n");
		return -ENODEV;
	}

	ret = of_mdiobus_register(priv->mii_bus, mdio_dn);
	if (ret) {
		dev_err(kdev, "failed to register MDIO bus\n");
		return ret;
	}

	/* Fetch the PHY phandle */
	priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0);

	/* Get the link mode */
	priv->phy_interface = of_get_phy_mode(dn);

	return 0;
}
コード例 #5
0
ファイル: ep8248e.c プロジェクト: AppEngine/linux-2.6
static int __devinit ep8248e_mdio_probe(struct of_device *ofdev,
                                        const struct of_device_id *match)
{
	struct mii_bus *bus;
	struct resource res;
	struct device_node *node;
	int ret;

	node = of_get_parent(ofdev->node);
	of_node_put(node);
	if (node != ep8248e_bcsr_node)
		return -ENODEV;

	ret = of_address_to_resource(ofdev->node, 0, &res);
	if (ret)
		return ret;

	bus = alloc_mdio_bitbang(&ep8248e_mdio_ctrl);
	if (!bus)
		return -ENOMEM;

	bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);

	bus->name = "ep8248e-mdio-bitbang";
	bus->parent = &ofdev->dev;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);

	return of_mdiobus_register(bus, ofdev->node);
}
コード例 #6
0
ファイル: fec_mpc52xx_phy.c プロジェクト: 03199618/linux
static int mpc52xx_fec_mdio_probe(struct platform_device *of)
{
	struct device *dev = &of->dev;
	struct device_node *np = of->dev.of_node;
	struct mii_bus *bus;
	struct mpc52xx_fec_mdio_priv *priv;
	struct resource res;
	int err;

	bus = mdiobus_alloc();
	if (bus == NULL)
		return -ENOMEM;
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (priv == NULL) {
		err = -ENOMEM;
		goto out_free;
	}

	bus->name = "mpc52xx MII bus";
	bus->read = mpc52xx_fec_mdio_read;
	bus->write = mpc52xx_fec_mdio_write;

	/* setup irqs */
	bus->irq = priv->mdio_irqs;

	/* setup registers */
	err = of_address_to_resource(np, 0, &res);
	if (err)
		goto out_free;
	priv->regs = ioremap(res.start, resource_size(&res));
	if (priv->regs == NULL) {
		err = -ENOMEM;
		goto out_free;
	}

	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);
	bus->priv = priv;

	bus->parent = dev;
	dev_set_drvdata(dev, bus);

	/* set MII speed */
	out_be32(&priv->regs->mii_speed,
		((mpc5xxx_get_bus_frequency(of->dev.of_node) >> 20) / 5) << 1);

	err = of_mdiobus_register(bus, np);
	if (err)
		goto out_unmap;

	return 0;

 out_unmap:
	iounmap(priv->regs);
 out_free:
	kfree(priv);
	mdiobus_free(bus);

	return err;
}
コード例 #7
0
ファイル: bcm_sf2.c プロジェクト: EricTHTseng/linux
static int bcm_sf2_mdio_register(struct dsa_switch *ds)
{
	struct bcm_sf2_priv *priv = ds_to_priv(ds);
	struct device_node *dn;
	static int index;
	int err;

	/* Find our integrated MDIO bus node */
	dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
	priv->master_mii_bus = of_mdio_find_bus(dn);
	if (!priv->master_mii_bus)
		return -EPROBE_DEFER;

	get_device(&priv->master_mii_bus->dev);
	priv->master_mii_dn = dn;

	priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
	if (!priv->slave_mii_bus)
		return -ENOMEM;

	priv->slave_mii_bus->priv = priv;
	priv->slave_mii_bus->name = "sf2 slave mii";
	priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read;
	priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write;
	snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d",
		 index++);
	priv->slave_mii_bus->dev.of_node = dn;

	/* Include the pseudo-PHY address to divert reads towards our
	 * workaround. This is only required for 7445D0, since 7445E0
	 * disconnects the internal switch pseudo-PHY such that we can use the
	 * regular SWITCH_MDIO master controller instead.
	 *
	 * Here we flag the pseudo PHY as needing special treatment and would
	 * otherwise make all other PHY read/writes go to the master MDIO bus
	 * controller that comes with this switch backed by the "mdio-unimac"
	 * driver.
	 */
	if (of_machine_is_compatible("brcm,bcm7445d0"))
		priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR);
	else
		priv->indir_phy_mask = 0;

	ds->phys_mii_mask = priv->indir_phy_mask;
	ds->slave_mii_bus = priv->slave_mii_bus;
	priv->slave_mii_bus->parent = ds->dev->parent;
	priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask;

	if (dn)
		err = of_mdiobus_register(priv->slave_mii_bus, dn);
	else
		err = mdiobus_register(priv->slave_mii_bus);

	if (err)
		of_node_put(dn);

	return err;
}
コード例 #8
0
ファイル: gpio_mdio.c プロジェクト: 1703011/asuswrt-merlin
static int __devinit gpio_mdio_probe(struct platform_device *ofdev,
				     const struct of_device_id *match)
{
	struct device *dev = &ofdev->dev;
	struct device_node *np = ofdev->dev.of_node;
	struct mii_bus *new_bus;
	struct gpio_priv *priv;
	const unsigned int *prop;
	int err;

	err = -ENOMEM;
	priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
	if (!priv)
		goto out;

	new_bus = mdiobus_alloc();

	if (!new_bus)
		goto out_free_priv;

	new_bus->name = "pasemi gpio mdio bus";
	new_bus->read = &gpio_mdio_read;
	new_bus->write = &gpio_mdio_write;
	new_bus->reset = &gpio_mdio_reset;

	prop = of_get_property(np, "reg", NULL);
	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop);
	new_bus->priv = priv;

	new_bus->irq = priv->mdio_irqs;

	prop = of_get_property(np, "mdc-pin", NULL);
	priv->mdc_pin = *prop;

	prop = of_get_property(np, "mdio-pin", NULL);
	priv->mdio_pin = *prop;

	new_bus->parent = dev;
	dev_set_drvdata(dev, new_bus);

	err = of_mdiobus_register(new_bus, np);

	if (err != 0) {
		printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
				new_bus->name, err);
		goto out_free_irq;
	}

	return 0;

out_free_irq:
	kfree(new_bus);
out_free_priv:
	kfree(priv);
out:
	return err;
}
コード例 #9
0
ファイル: vsc848x.c プロジェクト: garyvan/openwrt-1.6
static int vsc848x_nexus_probe(struct platform_device *pdev)
{
	struct vsc848x_nexus_mdiobus *bus;
	const char *bus_id;
	int len;
	int err = 0;

	bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
	if (!bus)
		return -ENOMEM;

	bus->parent_mii_bus = container_of(pdev->dev.parent,
					   struct mii_bus, dev);

	/* The PHY nexux  must have a reg property in the range [0-31] */
	err = of_property_read_u32(pdev->dev.of_node, "reg", &bus->reg_offset);
	if (err) {
		dev_err(&pdev->dev, "%s has invalid PHY address\n",
			pdev->dev.of_node->full_name);
		return err;
	}

	bus->mii_bus = mdiobus_alloc();
	if (!bus->mii_bus)
		return -ENOMEM;

	bus->mii_bus->priv = bus;
	bus->mii_bus->irq = bus->phy_irq;
	bus->mii_bus->name = "vsc848x_nexus";
	bus_id = bus->parent_mii_bus->id;
	len = strlen(bus_id);
	if (len > MII_BUS_ID_SIZE - 4)
		bus_id += len - (MII_BUS_ID_SIZE - 4);
	snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s:%02x",
		 bus_id, bus->reg_offset);
	bus->mii_bus->parent = &pdev->dev;

	bus->mii_bus->read = vsc848x_nexus_read;
	bus->mii_bus->write = vsc848x_nexus_write;
	mutex_init(&bus->lock);

	dev_set_drvdata(&pdev->dev, bus);

	err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node);
	if (err) {
		dev_err(&pdev->dev, "Error registering with device tree\n");
		goto fail_register;
	}

	return 0;

fail_register:
	dev_err(&pdev->dev, "Failed to register\n");
	mdiobus_free(bus->mii_bus);
	return err;
}
コード例 #10
0
int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
{
	struct mii_bus *bus;
	u32 bus_hz;
	int clk_div;
	int rc;
	struct resource res;
	struct device_node *np1 = of_get_parent(lp->phy_node);

	/* Calculate a reasonable divisor for the clock rate */
	clk_div = 0x3f; /* worst-case default setting */
	if (of_property_read_u32(np, "clock-frequency", &bus_hz) == 0) {
		clk_div = bus_hz / (2500 * 1000 * 2) - 1;
		if (clk_div < 1)
			clk_div = 1;
		if (clk_div > 0x3f)
			clk_div = 0x3f;
	}

	/* Enable the MDIO bus by asserting the enable bit and writing
	 * in the clock config */
	mutex_lock(&lp->indirect_mutex);
	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
	mutex_unlock(&lp->indirect_mutex);

	bus = mdiobus_alloc();
	if (!bus)
		return -ENOMEM;

	of_address_to_resource(np1, 0, &res);
	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
		 (unsigned long long)res.start);
	bus->priv = lp;
	bus->name = "Xilinx TEMAC MDIO";
	bus->read = temac_mdio_read;
	bus->write = temac_mdio_write;
	bus->parent = lp->dev;

	lp->mii_bus = bus;

	rc = of_mdiobus_register(bus, np1);
	if (rc)
		goto err_register;

	mutex_lock(&lp->indirect_mutex);
	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
		temac_indirect_in32(lp, XTE_MC_OFFSET));
	mutex_unlock(&lp->indirect_mutex);
	return 0;

 err_register:
	mdiobus_free(bus);
	return rc;
}
コード例 #11
0
ファイル: mdio-sun4i.c プロジェクト: 020gzh/linux
static int sun4i_mdio_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct mii_bus *bus;
	struct sun4i_mdio_data *data;
	struct resource *res;
	int ret;

	bus = mdiobus_alloc_size(sizeof(*data));
	if (!bus)
		return -ENOMEM;

	bus->name = "sun4i_mii_bus";
	bus->read = &sun4i_mdio_read;
	bus->write = &sun4i_mdio_write;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
	bus->parent = &pdev->dev;

	data = bus->priv;
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	data->membase = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(data->membase)) {
		ret = PTR_ERR(data->membase);
		goto err_out_free_mdiobus;
	}

	data->regulator = devm_regulator_get(&pdev->dev, "phy");
	if (IS_ERR(data->regulator)) {
		if (PTR_ERR(data->regulator) == -EPROBE_DEFER)
			return -EPROBE_DEFER;

		dev_info(&pdev->dev, "no regulator found\n");
		data->regulator = NULL;
	} else {
		ret = regulator_enable(data->regulator);
		if (ret)
			goto err_out_free_mdiobus;
	}

	ret = of_mdiobus_register(bus, np);
	if (ret < 0)
		goto err_out_disable_regulator;

	platform_set_drvdata(pdev, bus);

	return 0;

err_out_disable_regulator:
	if (data->regulator)
		regulator_disable(data->regulator);
err_out_free_mdiobus:
	mdiobus_free(bus);
	return ret;
}
コード例 #12
0
int temac_mdio_setup(struct temac_local *lp, struct device_node *np)
{
	struct mii_bus *bus;
	const u32 *bus_hz;
	int clk_div;
	int rc, size;
	struct resource res;

	
	clk_div = 0x3f; 
	bus_hz = of_get_property(np, "clock-frequency", &size);
	if (bus_hz && size >= sizeof(*bus_hz)) {
		clk_div = (*bus_hz) / (2500 * 1000 * 2) - 1;
		if (clk_div < 1)
			clk_div = 1;
		if (clk_div > 0x3f)
			clk_div = 0x3f;
	}

	mutex_lock(&lp->indirect_mutex);
	temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div);
	mutex_unlock(&lp->indirect_mutex);

	bus = mdiobus_alloc();
	if (!bus)
		return -ENOMEM;

	of_address_to_resource(np, 0, &res);
	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
		 (unsigned long long)res.start);
	bus->priv = lp;
	bus->name = "Xilinx TEMAC MDIO";
	bus->read = temac_mdio_read;
	bus->write = temac_mdio_write;
	bus->parent = lp->dev;
	bus->irq = lp->mdio_irqs; 

	lp->mii_bus = bus;

	rc = of_mdiobus_register(bus, np);
	if (rc)
		goto err_register;

	mutex_lock(&lp->indirect_mutex);
	dev_dbg(lp->dev, "MDIO bus registered;  MC:%x\n",
		temac_indirect_in32(lp, XTE_MC_OFFSET));
	mutex_unlock(&lp->indirect_mutex);
	return 0;

 err_register:
	mdiobus_free(bus);
	return rc;
}
コード例 #13
0
ファイル: xgmac_mdio.c プロジェクト: 383530895/linux
static int xgmac_mdio_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct mii_bus *bus;
	struct resource res;
	int ret;

	ret = of_address_to_resource(np, 0, &res);
	if (ret) {
		dev_err(&pdev->dev, "could not obtain address\n");
		return ret;
	}

	bus = mdiobus_alloc_size(PHY_MAX_ADDR * sizeof(int));
	if (!bus)
		return -ENOMEM;

	bus->name = "Freescale XGMAC MDIO Bus";
	bus->read = xgmac_mdio_read;
	bus->write = xgmac_mdio_write;
	bus->reset = xgmac_mdio_reset;
	bus->irq = bus->priv;
	bus->parent = &pdev->dev;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start);

	/* Set the PHY base address */
	bus->priv = of_iomap(np, 0);
	if (!bus->priv) {
		ret = -ENOMEM;
		goto err_ioremap;
	}

	ret = of_mdiobus_register(bus, np);
	if (ret) {
		dev_err(&pdev->dev, "cannot register MDIO bus\n");
		goto err_registration;
	}

	platform_set_drvdata(pdev, bus);

	return 0;

err_registration:
	iounmap(bus->priv);

err_ioremap:
	mdiobus_free(bus);

	return ret;
}
コード例 #14
0
static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
{
	struct mii_bus *new_bus;
	struct bb_info *bitbang;
	int ret = -ENOMEM;

	bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
	if (!bitbang)
		goto out;

	bitbang->ctrl.ops = &bb_ops;

	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
	if (!new_bus)
		goto out_free_priv;

	new_bus->name = "CPM2 Bitbanged MII",

	ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node);
	if (ret)
		goto out_free_bus;

	new_bus->phy_mask = ~0;
	new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
	if (!new_bus->irq) {
		ret = -ENOMEM;
		goto out_unmap_regs;
	}

	new_bus->parent = &ofdev->dev;
	dev_set_drvdata(&ofdev->dev, new_bus);

	ret = of_mdiobus_register(new_bus, ofdev->dev.of_node);
	if (ret)
		goto out_free_irqs;

	return 0;

out_free_irqs:
	dev_set_drvdata(&ofdev->dev, NULL);
	kfree(new_bus->irq);
out_unmap_regs:
	iounmap(bitbang->dir);
out_free_bus:
	free_mdio_bitbang(new_bus);
out_free_priv:
	kfree(bitbang);
out:
	return ret;
}
コード例 #15
0
ファイル: mdio.c プロジェクト: Lyude/linux
int mtk_mdio_init(struct mtk_eth *eth)
{
	struct device_node *mii_np;
	int err;

	if (!eth->soc->mdio_read || !eth->soc->mdio_write)
		return 0;

	spin_lock_init(&phy_ralink.lock);
	eth->phy = &phy_ralink;

	mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
	if (!mii_np) {
		dev_err(eth->dev, "no %s child node found", "mdio-bus");
		return -ENODEV;
	}

	if (!of_device_is_available(mii_np)) {
		err = 0;
		goto err_put_node;
	}

	eth->mii_bus = mdiobus_alloc();
	if (!eth->mii_bus) {
		err = -ENOMEM;
		goto err_put_node;
	}

	eth->mii_bus->name = "mdio";
	eth->mii_bus->read = eth->soc->mdio_read;
	eth->mii_bus->write = eth->soc->mdio_write;
	eth->mii_bus->reset = mtk_mdio_reset;
	eth->mii_bus->priv = eth;
	eth->mii_bus->parent = eth->dev;

	snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name);
	err = of_mdiobus_register(eth->mii_bus, mii_np);
	if (err)
		goto err_free_bus;

	return 0;

err_free_bus:
	kfree(eth->mii_bus);
err_put_node:
	of_node_put(mii_np);
	eth->mii_bus = NULL;
	return err;
}
コード例 #16
0
ファイル: mdio-moxart.c プロジェクト: Anjali05/linux
static int moxart_mdio_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct mii_bus *bus;
	struct moxart_mdio_data *data;
	struct resource *res;
	int ret, i;

	bus = mdiobus_alloc_size(sizeof(*data));
	if (!bus)
		return -ENOMEM;

	bus->name = "MOXA ART Ethernet MII";
	bus->read = &moxart_mdio_read;
	bus->write = &moxart_mdio_write;
	bus->reset = &moxart_mdio_reset;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d-mii", pdev->name, pdev->id);
	bus->parent = &pdev->dev;

	/* Setting PHY_IGNORE_INTERRUPT here even if it has no effect,
	 * of_mdiobus_register() sets these PHY_POLL.
	 * Ideally, the interrupt from MAC controller could be used to
	 * detect link state changes, not polling, i.e. if there was
	 * a way phy_driver could set PHY_HAS_INTERRUPT but have that
	 * interrupt handled in ethernet drivercode.
	 */
	for (i = 0; i < PHY_MAX_ADDR; i++)
		bus->irq[i] = PHY_IGNORE_INTERRUPT;

	data = bus->priv;
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	data->base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(data->base)) {
		ret = PTR_ERR(data->base);
		goto err_out_free_mdiobus;
	}

	ret = of_mdiobus_register(bus, np);
	if (ret < 0)
		goto err_out_free_mdiobus;

	platform_set_drvdata(pdev, bus);

	return 0;

err_out_free_mdiobus:
	mdiobus_free(bus);
	return ret;
}
コード例 #17
0
ファイル: mdio-bcm-iproc.c プロジェクト: 020gzh/linux
static int iproc_mdio_probe(struct platform_device *pdev)
{
	struct iproc_mdio_priv *priv;
	struct mii_bus *bus;
	struct resource *res;
	int rc;

	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	priv->base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(priv->base)) {
		dev_err(&pdev->dev, "failed to ioremap register\n");
		return PTR_ERR(priv->base);
	}

	priv->mii_bus = mdiobus_alloc();
	if (!priv->mii_bus) {
		dev_err(&pdev->dev, "MDIO bus alloc failed\n");
		return -ENOMEM;
	}

	bus = priv->mii_bus;
	bus->priv = priv;
	bus->name = "iProc MDIO bus";
	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
	bus->parent = &pdev->dev;
	bus->read = iproc_mdio_read;
	bus->write = iproc_mdio_write;

	rc = of_mdiobus_register(bus, pdev->dev.of_node);
	if (rc) {
		dev_err(&pdev->dev, "MDIO bus registration failed\n");
		goto err_iproc_mdio;
	}

	platform_set_drvdata(pdev, priv);

	dev_info(&pdev->dev, "Broadcom iProc MDIO bus at 0x%p\n", priv->base);

	return 0;

err_iproc_mdio:
	mdiobus_free(bus);
	return rc;
}
コード例 #18
0
ファイル: emac_mdio.c プロジェクト: AshishNamdev/linux
/**
 * arc_mdio_probe - MDIO probe function.
 * @priv:	Pointer to ARC EMAC private data structure.
 *
 * returns:	0 on success, -ENOMEM when mdiobus_alloc
 * (to allocate memory for MII bus structure) fails.
 *
 * Sets up and registers the MDIO interface.
 */
int arc_mdio_probe(struct arc_emac_priv *priv)
{
	struct arc_emac_mdio_bus_data *data = &priv->bus_data;
	struct device_node *np = priv->dev->of_node;
	struct mii_bus *bus;
	int error;

	bus = mdiobus_alloc();
	if (!bus)
		return -ENOMEM;

	priv->bus = bus;
	bus->priv = priv;
	bus->parent = priv->dev;
	bus->name = "Synopsys MII Bus";
	bus->read = &arc_mdio_read;
	bus->write = &arc_mdio_write;
	bus->reset = &arc_mdio_reset;

	/* optional reset-related properties */
	data->reset_gpio = devm_gpiod_get_optional(priv->dev, "phy-reset",
						   GPIOD_OUT_LOW);
	if (IS_ERR(data->reset_gpio)) {
		error = PTR_ERR(data->reset_gpio);
		dev_err(priv->dev, "Failed to request gpio: %d\n", error);
		return error;
	}

	of_property_read_u32(np, "phy-reset-duration", &data->msec);
	/* A sane reset duration should not be longer than 1s */
	if (data->msec > 1000)
		data->msec = 1;

	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);

	error = of_mdiobus_register(bus, priv->dev->of_node);
	if (error) {
		dev_err(priv->dev, "cannot register MDIO bus %s\n", bus->name);
		mdiobus_free(bus);
		return error;
	}

	return 0;
}
コード例 #19
0
ファイル: lantiq_gswip.c プロジェクト: Anjali05/linux
static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
{
	struct dsa_switch *ds = priv->ds;

	ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
	if (!ds->slave_mii_bus)
		return -ENOMEM;

	ds->slave_mii_bus->priv = priv;
	ds->slave_mii_bus->read = gswip_mdio_rd;
	ds->slave_mii_bus->write = gswip_mdio_wr;
	ds->slave_mii_bus->name = "lantiq,xrx200-mdio";
	snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii",
		 dev_name(priv->dev));
	ds->slave_mii_bus->parent = priv->dev;
	ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;

	return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
}
コード例 #20
0
ファイル: hip04_mdio.c プロジェクト: DenisLug/mptcp
static int hip04_mdio_probe(struct platform_device *pdev)
{
	struct resource *r;
	struct mii_bus *bus;
	struct hip04_mdio_priv *priv;
	int ret;

	bus = mdiobus_alloc_size(sizeof(struct hip04_mdio_priv));
	if (!bus) {
		dev_err(&pdev->dev, "Cannot allocate MDIO bus\n");
		return -ENOMEM;
	}

	bus->name = "hip04_mdio_bus";
	bus->read = hip04_mdio_read;
	bus->write = hip04_mdio_write;
	bus->reset = hip04_mdio_reset;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
	bus->parent = &pdev->dev;
	priv = bus->priv;

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	priv->base = devm_ioremap_resource(&pdev->dev, r);
	if (IS_ERR(priv->base)) {
		ret = PTR_ERR(priv->base);
		goto out_mdio;
	}

	ret = of_mdiobus_register(bus, pdev->dev.of_node);
	if (ret < 0) {
		dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
		goto out_mdio;
	}

	platform_set_drvdata(pdev, bus);

	return 0;

out_mdio:
	mdiobus_free(bus);
	return ret;
}
コード例 #21
0
static int __devinit ep8248e_mdio_probe(struct platform_device *ofdev)
{
	struct mii_bus *bus;
	struct resource res;
	struct device_node *node;
	int ret;

	node = of_get_parent(ofdev->dev.of_node);
	of_node_put(node);
	if (node != ep8248e_bcsr_node)
		return -ENODEV;

	ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
	if (ret)
		return ret;

	bus = alloc_mdio_bitbang(&ep8248e_mdio_ctrl);
	if (!bus)
		return -ENOMEM;

	bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
	if (bus->irq == NULL) {
		ret = -ENOMEM;
		goto err_free_bus;
	}

	bus->name = "ep8248e-mdio-bitbang";
	bus->parent = &ofdev->dev;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);

	ret = of_mdiobus_register(bus, ofdev->dev.of_node);
	if (ret)
		goto err_free_irq;

	return 0;
err_free_irq:
	kfree(bus->irq);
err_free_bus:
	free_mdio_bitbang(bus);
	return ret;
}
コード例 #22
0
ファイル: xilinx_axienet_mdio.c プロジェクト: 03199618/linux
/**
 * axienet_mdio_setup - MDIO setup function
 * @lp:		Pointer to axienet local data structure.
 * @np:		Pointer to device node
 *
 * returns:	0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
 *		mdiobus_alloc (to allocate memory for mii bus structure) fails.
 *
 * Sets up the MDIO interface by initializing the MDIO clock and enabling the
 * MDIO interface in hardware. Register the MDIO interface.
 **/
int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
{
	int ret;
	u32 clk_div, host_clock;
	u32 *property_p;
	struct mii_bus *bus;
	struct resource res;
	struct device_node *np1;

	/* clk_div can be calculated by deriving it from the equation:
	 * fMDIO = fHOST / ((1 + clk_div) * 2)
	 *
	 * Where fMDIO <= 2500000, so we get:
	 * fHOST / ((1 + clk_div) * 2) <= 2500000
	 *
	 * Then we get:
	 * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST)
	 *
	 * Then we get:
	 * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST)
	 *
	 * Then we get:
	 * 1 / (1 + clk_div) <= (5000000 / fHOST)
	 *
	 * So:
	 * (1 + clk_div) >= (fHOST / 5000000)
	 *
	 * And finally:
	 * clk_div >= (fHOST / 5000000) - 1
	 *
	 * fHOST can be read from the flattened device tree as property
	 * "clock-frequency" from the CPU
	 */

	np1 = of_find_node_by_name(NULL, "cpu");
	if (!np1) {
		printk(KERN_WARNING "%s(): Could not find CPU device node.",
		       __func__);
		printk(KERN_WARNING "Setting MDIO clock divisor to "
		       "default %d\n", DEFAULT_CLOCK_DIVISOR);
		clk_div = DEFAULT_CLOCK_DIVISOR;
		goto issue;
	}
	property_p = (u32 *) of_get_property(np1, "clock-frequency", NULL);
	if (!property_p) {
		printk(KERN_WARNING "%s(): Could not find CPU property: "
		       "clock-frequency.", __func__);
		printk(KERN_WARNING "Setting MDIO clock divisor to "
		       "default %d\n", DEFAULT_CLOCK_DIVISOR);
		clk_div = DEFAULT_CLOCK_DIVISOR;
		of_node_put(np1);
		goto issue;
	}

	host_clock = be32_to_cpup(property_p);
	clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
	/* If there is any remainder from the division of
	 * fHOST / (MAX_MDIO_FREQ * 2), then we need to add
	 * 1 to the clock divisor or we will surely be above 2.5 MHz */
	if (host_clock % (MAX_MDIO_FREQ * 2))
		clk_div++;

	printk(KERN_DEBUG "%s(): Setting MDIO clock divisor to %u based "
	       "on %u Hz host clock.\n", __func__, clk_div, host_clock);

	of_node_put(np1);
issue:
	axienet_iow(lp, XAE_MDIO_MC_OFFSET,
		    (((u32) clk_div) | XAE_MDIO_MC_MDIOEN_MASK));

	ret = axienet_mdio_wait_until_ready(lp);
	if (ret < 0)
		return ret;

	bus = mdiobus_alloc();
	if (!bus)
		return -ENOMEM;

	np1 = of_get_parent(lp->phy_node);
	of_address_to_resource(np1, 0, &res);
	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
		 (unsigned long long) res.start);

	bus->priv = lp;
	bus->name = "Xilinx Axi Ethernet MDIO";
	bus->read = axienet_mdio_read;
	bus->write = axienet_mdio_write;
	bus->parent = lp->dev;
	bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
	lp->mii_bus = bus;

	ret = of_mdiobus_register(bus, np1);
	if (ret) {
		mdiobus_free(bus);
		return ret;
	}
	return 0;
}
コード例 #23
0
ファイル: mdio-sun4i.c プロジェクト: 32bitmicro/xvisor
static int sun4i_mdio_probe(struct vmm_device *pdev,
			    const struct vmm_devtree_nodeid *devid)
{
	struct device_node *np = pdev->node;
	struct mii_bus *bus;
	struct sun4i_mdio_data *data;
	int ret, i;
	virtual_addr_t  reg_addr;

	bus = mdiobus_alloc_size(sizeof(*data));
	if (!bus)
		return -ENOMEM;

	bus->name = "sun4i_mii_bus";
	bus->read = &sun4i_mdio_read;
	bus->write = &sun4i_mdio_write;
	bus->reset = &sun4i_mdio_reset;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(pdev));
	bus->parent = pdev;

#if 0
	bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
			GFP_KERNEL);
#endif
	bus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);

	if (!bus->irq) {
		ret = -ENOMEM;
		goto err_out_free_mdiobus;
	}

	for (i = 0; i < PHY_MAX_ADDR; i++)
		bus->irq[i] = PHY_POLL;

	data = bus->priv;
#if 0
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	data->membase = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(data->membase)) {
		ret = PTR_ERR(data->membase);
		goto err_out_free_mdiobus;
	}
#endif
	if ((ret = vmm_devtree_request_regmap(np, &reg_addr, 0,
						"Sun4i MDIO"))) {
		vmm_printf("%s: Failed to ioremap\n", __func__);
		return -ENOMEM;
	}

	data->membase = (void *) reg_addr;

#if 0
	data->regulator = devm_regulator_get(&pdev->dev, "phy");
#endif
	data->regulator = devm_regulator_get(pdev, "phy");

	if (IS_ERR(data->regulator)) {
		if (PTR_ERR(data->regulator) == -EPROBE_DEFER)
			return -EPROBE_DEFER;

		dev_info(pdev, "no regulator found\n");
	} else {
		ret = regulator_enable(data->regulator);
		if (ret)
			goto err_out_free_mdiobus;
	}

	ret = of_mdiobus_register(bus, np);
	if (ret < 0)
		goto err_out_disable_regulator;

	platform_set_drvdata(pdev, bus);

	return 0;

err_out_disable_regulator:
	regulator_disable(data->regulator);
err_out_free_mdiobus:
	mdiobus_free(bus);
	return ret;
}
コード例 #24
0
ファイル: mii-fec.c プロジェクト: 020gzh/linux
static int fs_enet_mdio_probe(struct platform_device *ofdev)
{
	const struct of_device_id *match;
	struct resource res;
	struct mii_bus *new_bus;
	struct fec_info *fec;
	int (*get_bus_freq)(struct device_node *);
	int ret = -ENOMEM, clock, speed;

	match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev);
	if (!match)
		return -EINVAL;
	get_bus_freq = match->data;

	new_bus = mdiobus_alloc();
	if (!new_bus)
		goto out;

	fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
	if (!fec)
		goto out_mii;

	new_bus->priv = fec;
	new_bus->name = "FEC MII Bus";
	new_bus->read = &fs_enet_fec_mii_read;
	new_bus->write = &fs_enet_fec_mii_write;

	ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
	if (ret)
		goto out_res;

	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start);

	fec->fecp = ioremap(res.start, resource_size(&res));
	if (!fec->fecp) {
		ret = -ENOMEM;
		goto out_fec;
	}

	if (get_bus_freq) {
		clock = get_bus_freq(ofdev->dev.of_node);
		if (!clock) {
			/* Use maximum divider if clock is unknown */
			dev_warn(&ofdev->dev, "could not determine IPS clock\n");
			clock = 0x3F * 5000000;
		}
	} else
		clock = ppc_proc_freq;

	/*
	 * Scale for a MII clock <= 2.5 MHz
	 * Note that only 6 bits (25:30) are available for MII speed.
	 */
	speed = (clock + 4999999) / 5000000;
	if (speed > 0x3F) {
		speed = 0x3F;
		dev_err(&ofdev->dev,
			"MII clock (%d Hz) exceeds max (2.5 MHz)\n",
			clock / speed);
	}

	fec->mii_speed = speed << 1;

	setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
	setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
	                                  FEC_ECNTRL_ETHER_EN);
	out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
	clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed);

	new_bus->phy_mask = ~0;

	new_bus->parent = &ofdev->dev;
	platform_set_drvdata(ofdev, new_bus);

	ret = of_mdiobus_register(new_bus, ofdev->dev.of_node);
	if (ret)
		goto out_unmap_regs;

	return 0;

out_unmap_regs:
	iounmap(fec->fecp);
out_res:
out_fec:
	kfree(fec);
out_mii:
	mdiobus_free(new_bus);
out:
	return ret;
}
コード例 #25
0
ファイル: emac-phy.c プロジェクト: AlexShiLucky/linux
/* Configure the MDIO bus and connect the external PHY */
int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
{
	struct device_node *np = pdev->dev.of_node;
	struct mii_bus *mii_bus;
	int ret;

	/* Create the mii_bus object for talking to the MDIO bus */
	adpt->mii_bus = mii_bus = devm_mdiobus_alloc(&pdev->dev);
	if (!mii_bus)
		return -ENOMEM;

	mii_bus->name = "emac-mdio";
	snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
	mii_bus->read = emac_mdio_read;
	mii_bus->write = emac_mdio_write;
	mii_bus->parent = &pdev->dev;
	mii_bus->priv = adpt;

	if (has_acpi_companion(&pdev->dev)) {
		u32 phy_addr;

		ret = mdiobus_register(mii_bus);
		if (ret) {
			dev_err(&pdev->dev, "could not register mdio bus\n");
			return ret;
		}
		ret = device_property_read_u32(&pdev->dev, "phy-channel",
					       &phy_addr);
		if (ret)
			/* If we can't read a valid phy address, then assume
			 * that there is only one phy on this mdio bus.
			 */
			adpt->phydev = phy_find_first(mii_bus);
		else
			adpt->phydev = mdiobus_get_phy(mii_bus, phy_addr);

		/* of_phy_find_device() claims a reference to the phydev,
		 * so we do that here manually as well. When the driver
		 * later unloads, it can unilaterally drop the reference
		 * without worrying about ACPI vs DT.
		 */
		if (adpt->phydev)
			get_device(&adpt->phydev->mdio.dev);
	} else {
		struct device_node *phy_np;

		ret = of_mdiobus_register(mii_bus, np);
		if (ret) {
			dev_err(&pdev->dev, "could not register mdio bus\n");
			return ret;
		}

		phy_np = of_parse_phandle(np, "phy-handle", 0);
		adpt->phydev = of_phy_find_device(phy_np);
		of_node_put(phy_np);
	}

	if (!adpt->phydev) {
		dev_err(&pdev->dev, "could not find external phy\n");
		mdiobus_unregister(mii_bus);
		return -ENODEV;
	}

	return 0;
}
コード例 #26
0
ファイル: mdio-mux.c プロジェクト: AlexShiLucky/linux
int mdio_mux_init(struct device *dev,
		  struct device_node *mux_node,
		  int (*switch_fn)(int cur, int desired, void *data),
		  void **mux_handle,
		  void *data,
		  struct mii_bus *mux_bus)
{
	struct device_node *parent_bus_node;
	struct device_node *child_bus_node;
	int r, ret_val;
	struct mii_bus *parent_bus;
	struct mdio_mux_parent_bus *pb;
	struct mdio_mux_child_bus *cb;

	if (!mux_node)
		return -ENODEV;

	if (!mux_bus) {
		parent_bus_node = of_parse_phandle(mux_node,
						   "mdio-parent-bus", 0);

		if (!parent_bus_node)
			return -ENODEV;

		parent_bus = of_mdio_find_bus(parent_bus_node);
		if (!parent_bus) {
			ret_val = -EPROBE_DEFER;
			goto err_parent_bus;
		}
	} else {
		parent_bus_node = NULL;
		parent_bus = mux_bus;
		get_device(&parent_bus->dev);
	}

	pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL);
	if (!pb) {
		ret_val = -ENOMEM;
		goto err_pb_kz;
	}

	pb->switch_data = data;
	pb->switch_fn = switch_fn;
	pb->current_child = -1;
	pb->parent_id = parent_count++;
	pb->mii_bus = parent_bus;

	ret_val = -ENODEV;
	for_each_available_child_of_node(mux_node, child_bus_node) {
		int v;

		r = of_property_read_u32(child_bus_node, "reg", &v);
		if (r) {
			dev_err(dev,
				"Error: Failed to find reg for child %pOF\n",
				child_bus_node);
			continue;
		}

		cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
		if (!cb) {
			ret_val = -ENOMEM;
			continue;
		}
		cb->bus_number = v;
		cb->parent = pb;

		cb->mii_bus = mdiobus_alloc();
		if (!cb->mii_bus) {
			ret_val = -ENOMEM;
			devm_kfree(dev, cb);
			continue;
		}
		cb->mii_bus->priv = cb;

		cb->mii_bus->name = "mdio_mux";
		snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%x.%x",
			 pb->parent_id, v);
		cb->mii_bus->parent = dev;
		cb->mii_bus->read = mdio_mux_read;
		cb->mii_bus->write = mdio_mux_write;
		r = of_mdiobus_register(cb->mii_bus, child_bus_node);
		if (r) {
			dev_err(dev,
				"Error: Failed to register MDIO bus for child %pOF\n",
				child_bus_node);
			mdiobus_free(cb->mii_bus);
			devm_kfree(dev, cb);
		} else {
			cb->next = pb->children;
			pb->children = cb;
		}
	}
コード例 #27
0
ファイル: mvmdio.c プロジェクト: 020gzh/linux
static int orion_mdio_probe(struct platform_device *pdev)
{
	struct resource *r;
	struct mii_bus *bus;
	struct orion_mdio_dev *dev;
	int ret;

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!r) {
		dev_err(&pdev->dev, "No SMI register address given\n");
		return -ENODEV;
	}

	bus = devm_mdiobus_alloc_size(&pdev->dev,
				      sizeof(struct orion_mdio_dev));
	if (!bus)
		return -ENOMEM;

	bus->name = "orion_mdio_bus";
	bus->read = orion_mdio_read;
	bus->write = orion_mdio_write;
	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
		 dev_name(&pdev->dev));
	bus->parent = &pdev->dev;

	dev = bus->priv;
	dev->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
	if (!dev->regs) {
		dev_err(&pdev->dev, "Unable to remap SMI register\n");
		ret = -ENODEV;
		goto out_mdio;
	}

	init_waitqueue_head(&dev->smi_busy_wait);

	dev->clk = devm_clk_get(&pdev->dev, NULL);
	if (!IS_ERR(dev->clk))
		clk_prepare_enable(dev->clk);

	dev->err_interrupt = platform_get_irq(pdev, 0);
	if (dev->err_interrupt > 0) {
		ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
					orion_mdio_err_irq,
					IRQF_SHARED, pdev->name, dev);
		if (ret)
			goto out_mdio;

		writel(MVMDIO_ERR_INT_SMI_DONE,
			dev->regs + MVMDIO_ERR_INT_MASK);

	} else if (dev->err_interrupt == -EPROBE_DEFER) {
		return -EPROBE_DEFER;
	}

	mutex_init(&dev->lock);

	if (pdev->dev.of_node)
		ret = of_mdiobus_register(bus, pdev->dev.of_node);
	else
		ret = mdiobus_register(bus);
	if (ret < 0) {
		dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
		goto out_mdio;
	}

	platform_set_drvdata(pdev, bus);

	return 0;

out_mdio:
	if (!IS_ERR(dev->clk))
		clk_disable_unprepare(dev->clk);
	return ret;
}
コード例 #28
0
ファイル: mdio-xgene.c プロジェクト: AlexShiLucky/linux
static int xgene_mdio_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct mii_bus *mdio_bus;
	const struct of_device_id *of_id;
	struct resource *res;
	struct xgene_mdio_pdata *pdata;
	void __iomem *csr_base;
	int mdio_id = 0, ret = 0;

	of_id = of_match_device(xgene_mdio_of_match, &pdev->dev);
	if (of_id) {
		mdio_id = (enum xgene_mdio_id)of_id->data;
	} else {
#ifdef CONFIG_ACPI
		const struct acpi_device_id *acpi_id;

		acpi_id = acpi_match_device(xgene_mdio_acpi_match, &pdev->dev);
		if (acpi_id)
			mdio_id = (enum xgene_mdio_id)acpi_id->driver_data;
#endif
	}

	if (!mdio_id)
		return -ENODEV;

	pdata = devm_kzalloc(dev, sizeof(struct xgene_mdio_pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;
	pdata->mdio_id = mdio_id;
	pdata->dev = dev;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	csr_base = devm_ioremap_resource(dev, res);
	if (IS_ERR(csr_base))
		return PTR_ERR(csr_base);
	pdata->mac_csr_addr = csr_base;
	pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET;
	pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET;

	if (mdio_id == XGENE_MDIO_RGMII)
		spin_lock_init(&pdata->mac_lock);

	if (dev->of_node) {
		pdata->clk = devm_clk_get(dev, NULL);
		if (IS_ERR(pdata->clk)) {
			dev_err(dev, "Unable to retrieve clk\n");
			return PTR_ERR(pdata->clk);
		}
	}

	ret = xgene_mdio_reset(pdata);
	if (ret)
		return ret;

	mdio_bus = mdiobus_alloc();
	if (!mdio_bus) {
		ret = -ENOMEM;
		goto out_clk;
	}

	mdio_bus->name = "APM X-Gene MDIO bus";

	if (mdio_id == XGENE_MDIO_RGMII) {
		mdio_bus->read = xgene_mdio_rgmii_read;
		mdio_bus->write = xgene_mdio_rgmii_write;
		mdio_bus->priv = (void __force *)pdata;
		snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s",
			 "xgene-mii-rgmii");
	} else {
		mdio_bus->read = xgene_xfi_mdio_read;
		mdio_bus->write = xgene_xfi_mdio_write;
		mdio_bus->priv = (void __force *)pdata->mdio_csr_addr;
		snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s",
			 "xgene-mii-xfi");
	}

	mdio_bus->parent = dev;
	platform_set_drvdata(pdev, pdata);

	if (dev->of_node) {
		ret = of_mdiobus_register(mdio_bus, dev->of_node);
	} else {
#ifdef CONFIG_ACPI
		/* Mask out all PHYs from auto probing. */
		mdio_bus->phy_mask = ~0;
		ret = mdiobus_register(mdio_bus);
		if (ret)
			goto out_mdiobus;

		acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(dev), 1,
				    acpi_register_phy, NULL, mdio_bus, NULL);
#endif
	}

	if (ret)
		goto out_mdiobus;

	pdata->mdio_bus = mdio_bus;
	xgene_mdio_status = true;

	return 0;

out_mdiobus:
	mdiobus_free(mdio_bus);

out_clk:
	if (dev->of_node)
		clk_disable_unprepare(pdata->clk);

	return ret;
}
コード例 #29
0
/**
 * axienet_mdio_setup - MDIO setup function
 * @lp:		Pointer to axienet local data structure.
 * @np:		Pointer to device node
 *
 * returns:	0 on success, -ETIMEDOUT on a timeout, -ENOMEM when
 *		mdiobus_alloc (to allocate memory for mii bus structure) fails.
 *
 * Sets up the MDIO interface by initializing the MDIO clock and enabling the
 * MDIO interface in hardware. Register the MDIO interface.
 **/
int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
{
	int ret;
	u32 clk_div;
	struct mii_bus *bus;
	struct resource res;
	struct device_node *np1;
	struct device_node *npp = 0; /* the ethernet controller device node */

	/* clk_div can be calculated by deriving it from the equation:
	 * fMDIO = fHOST / ((1 + clk_div) * 2)
	 *
	 * Where fMDIO <= 2500000, so we get:
	 * fHOST / ((1 + clk_div) * 2) <= 2500000
	 *
	 * Then we get:
	 * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST)
	 *
	 * Then we get:
	 * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST)
	 *
	 * Then we get:
	 * 1 / (1 + clk_div) <= (5000000 / fHOST)
	 *
	 * So:
	 * (1 + clk_div) >= (fHOST / 5000000)
	 *
	 * And finally:
	 * clk_div >= (fHOST / 5000000) - 1
	 *
	 * fHOST can be read from the flattened device tree as property
	 * "clock-frequency" from the CPU
	 */
	np1 = of_get_parent(lp->phy_node);
	if (np1)
		npp = of_get_parent(np1);
	if (!npp) {
		dev_warn(lp->dev,
			"Could not find ethernet controller device node.");
		dev_warn(lp->dev, "Setting MDIO clock divisor to default %d\n",
		       DEFAULT_CLOCK_DIVISOR);
		clk_div = DEFAULT_CLOCK_DIVISOR;
	} else {
		u32 *property_p;

		property_p = (uint32_t *)of_get_property(npp,
						"clock-frequency", NULL);
		if (!property_p) {
			dev_warn(lp->dev, "Could not find clock ethernet " \
						      "controller property.");
			dev_warn(lp->dev,
				 "Setting MDIO clock divisor to default %d\n",
							DEFAULT_CLOCK_DIVISOR);
			clk_div = DEFAULT_CLOCK_DIVISOR;
		} else {
			u32 host_clock = be32_to_cpup(property_p);

			clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;

			/* If there is any remainder from the division of
			 * fHOST / (MAX_MDIO_FREQ * 2), then we need to add 1
			 * to the clock divisor or we will surely be
			 * above 2.5 MHz */
			if (host_clock % (MAX_MDIO_FREQ * 2))
				clk_div++;
			dev_dbg(lp->dev, "Setting MDIO clock divisor to %u " \
						"based on %u Hz host clock.\n",
						clk_div, host_clock);
		}
	}

	axienet_iow(lp, XAE_MDIO_MC_OFFSET, (((u32)clk_div) |
						XAE_MDIO_MC_MDIOEN_MASK));

	ret = axienet_mdio_wait_until_ready(lp);
	if (ret < 0)
		return ret;

	bus = mdiobus_alloc();
	if (!bus)
		return -ENOMEM;

	of_address_to_resource(npp, 0, &res);
	snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
		 (unsigned long long) res.start);

	bus->priv = lp;
	bus->name = "Xilinx Axi Ethernet MDIO";
	bus->read = axienet_mdio_read;
	bus->write = axienet_mdio_write;
	bus->parent = lp->dev;
	bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
	lp->mii_bus = bus;

	ret = of_mdiobus_register(bus, np1);
	if (ret) {
		mdiobus_free(bus);
		return ret;
	}
	return 0;
}
コード例 #30
0
/**
 * stmmac_mdio_register
 * @ndev: net device structure
 * Description: it registers the MII bus
 */
int stmmac_mdio_register(struct net_device *ndev)
{
    int err = 0;
    struct mii_bus *new_bus;
    struct stmmac_priv *priv = netdev_priv(ndev);
    struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
    struct device_node *mdio_node = priv->plat->mdio_node;
    int addr, found;

    if (!mdio_bus_data)
        return 0;

    new_bus = mdiobus_alloc();
    if (new_bus == NULL)
        return -ENOMEM;

    if (mdio_bus_data->irqs)
        memcpy(new_bus->irq, mdio_bus_data, sizeof(new_bus->irq));

#ifdef CONFIG_OF
    if (priv->device->of_node)
        mdio_bus_data->reset_gpio = -1;
#endif

    new_bus->name = "stmmac";
    new_bus->read = &stmmac_mdio_read;
    new_bus->write = &stmmac_mdio_write;
    new_bus->reset = &stmmac_mdio_reset;
    snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
             new_bus->name, priv->plat->bus_id);
    new_bus->priv = ndev;
    new_bus->phy_mask = mdio_bus_data->phy_mask;
    new_bus->parent = priv->device;

    if (mdio_node)
        err = of_mdiobus_register(new_bus, mdio_node);
    else
        err = mdiobus_register(new_bus);
    if (err != 0) {
        pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);
        goto bus_register_fail;
    }

    if (priv->plat->phy_node || mdio_node)
        goto bus_register_done;

    found = 0;
    for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
        struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
        if (phydev) {
            int act = 0;
            char irq_num[4];
            char *irq_str;

            /*
             * If an IRQ was provided to be assigned after
             * the bus probe, do it here.
             */
            if ((mdio_bus_data->irqs == NULL) &&
                    (mdio_bus_data->probed_phy_irq > 0)) {
                new_bus->irq[addr] =
                    mdio_bus_data->probed_phy_irq;
                phydev->irq = mdio_bus_data->probed_phy_irq;
            }

            /*
             * If we're going to bind the MAC to this PHY bus,
             * and no PHY number was provided to the MAC,
             * use the one probed here.
             */
            if (priv->plat->phy_addr == -1)
                priv->plat->phy_addr = addr;

            act = (priv->plat->phy_addr == addr);
            switch (phydev->irq) {
            case PHY_POLL:
                irq_str = "POLL";
                break;
            case PHY_IGNORE_INTERRUPT:
                irq_str = "IGNORE";
                break;
            default:
                sprintf(irq_num, "%d", phydev->irq);
                irq_str = irq_num;
                break;
            }
            pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
                    ndev->name, phydev->phy_id, addr,
                    irq_str, phydev_name(phydev),
                    act ? " active" : "");
            found = 1;
        }
    }

    if (!found && !mdio_node) {
        pr_warn("%s: No PHY found\n", ndev->name);
        mdiobus_unregister(new_bus);
        mdiobus_free(new_bus);
        return -ENODEV;
    }

bus_register_done:
    priv->mii = new_bus;

    return 0;

bus_register_fail:
    mdiobus_free(new_bus);
    return err;
}