Commit 19ec5083 authored by David S. Miller's avatar David S. Miller

Merge branch 'mvmdio-updates'

Russell King says:

====================
mvmdio updates

This series of patches update mvmdio for Armada 8k CP110.  A number of
issues were found:

1. The driver fails to disable an interrupt when something goes wrong
   in the probe function.

2. The interrupt is specified in DT to be optional, but the driver
   unconditionally writes to the interrupt mask register, which may
   not exist.

3. The DT binding specifies
    "reg: address and length of the SMI register"
   however, when supporting the interrupt, the size must cover the
   interrupt register as well.  Update the binding documentation
   with this information that was previously omitted.

4. If the register size is too small, have the driver print an error
   and disable use of the interrupt.

5. Armada 8k needs three clocks for the MDIO interface, otherwise the
   SoC hangs (since it is part of one of the ethernet interfaces.)
   GOP clock, MG core clock and MG clock are needed on 8k. Augment the
   binding and driver to allow three clocks to be specified.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d92be7a4 96cb4342
...@@ -7,17 +7,20 @@ interface. ...@@ -7,17 +7,20 @@ interface.
Required properties: Required properties:
- compatible: "marvell,orion-mdio" - compatible: "marvell,orion-mdio"
- reg: address and length of the SMI register - reg: address and length of the MDIO registers. When an interrupt is
not present, the length is the size of the SMI register (4 bytes)
otherwise it must be 0x84 bytes to cover the interrupt control
registers.
Optional properties: Optional properties:
- interrupts: interrupt line number for the SMI error/done interrupt - interrupts: interrupt line number for the SMI error/done interrupt
- clocks: Phandle to the clock control device and gate bit - clocks: phandle for up to three required clocks for the MDIO instance
The child nodes of the MDIO driver are the individual PHY devices The child nodes of the MDIO driver are the individual PHY devices
connected to this MDIO bus. They must have a "reg" property given the connected to this MDIO bus. They must have a "reg" property given the
PHY address on the MDIO bus. PHY address on the MDIO bus.
Example at the SoC level: Example at the SoC level without an interrupt property:
mdio { mdio {
#address-cells = <1>; #address-cells = <1>;
...@@ -26,6 +29,16 @@ mdio { ...@@ -26,6 +29,16 @@ mdio {
reg = <0xd0072004 0x4>; reg = <0xd0072004 0x4>;
}; };
Example with an interrupt property:
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "marvell,orion-mdio";
reg = <0xd0072004 0x84>;
interrupts = <30>;
};
And at the board level: And at the board level:
mdio { mdio {
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
struct orion_mdio_dev { struct orion_mdio_dev {
struct mutex lock; struct mutex lock;
void __iomem *regs; void __iomem *regs;
struct clk *clk; struct clk *clk[3];
/* /*
* If we have access to the error interrupt pin (which is * If we have access to the error interrupt pin (which is
* somewhat misnamed as it not only reflects internal errors * somewhat misnamed as it not only reflects internal errors
...@@ -187,7 +187,7 @@ static int orion_mdio_probe(struct platform_device *pdev) ...@@ -187,7 +187,7 @@ static int orion_mdio_probe(struct platform_device *pdev)
struct resource *r; struct resource *r;
struct mii_bus *bus; struct mii_bus *bus;
struct orion_mdio_dev *dev; struct orion_mdio_dev *dev;
int ret; int i, ret;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) { if (!r) {
...@@ -216,11 +216,20 @@ static int orion_mdio_probe(struct platform_device *pdev) ...@@ -216,11 +216,20 @@ static int orion_mdio_probe(struct platform_device *pdev)
init_waitqueue_head(&dev->smi_busy_wait); init_waitqueue_head(&dev->smi_busy_wait);
dev->clk = devm_clk_get(&pdev->dev, NULL); for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
if (!IS_ERR(dev->clk)) dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
clk_prepare_enable(dev->clk); if (IS_ERR(dev->clk[i]))
break;
clk_prepare_enable(dev->clk[i]);
}
dev->err_interrupt = platform_get_irq(pdev, 0); dev->err_interrupt = platform_get_irq(pdev, 0);
if (dev->err_interrupt > 0 &&
resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
dev_err(&pdev->dev,
"disabling interrupt, resource size is too small\n");
dev->err_interrupt = 0;
}
if (dev->err_interrupt > 0) { if (dev->err_interrupt > 0) {
ret = devm_request_irq(&pdev->dev, dev->err_interrupt, ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
orion_mdio_err_irq, orion_mdio_err_irq,
...@@ -251,8 +260,16 @@ static int orion_mdio_probe(struct platform_device *pdev) ...@@ -251,8 +260,16 @@ static int orion_mdio_probe(struct platform_device *pdev)
return 0; return 0;
out_mdio: out_mdio:
if (!IS_ERR(dev->clk)) if (dev->err_interrupt > 0)
clk_disable_unprepare(dev->clk); writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
if (IS_ERR(dev->clk[i]))
break;
clk_disable_unprepare(dev->clk[i]);
clk_put(dev->clk[i]);
}
return ret; return ret;
} }
...@@ -260,11 +277,18 @@ static int orion_mdio_remove(struct platform_device *pdev) ...@@ -260,11 +277,18 @@ static int orion_mdio_remove(struct platform_device *pdev)
{ {
struct mii_bus *bus = platform_get_drvdata(pdev); struct mii_bus *bus = platform_get_drvdata(pdev);
struct orion_mdio_dev *dev = bus->priv; struct orion_mdio_dev *dev = bus->priv;
int i;
writel(0, dev->regs + MVMDIO_ERR_INT_MASK); if (dev->err_interrupt > 0)
writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
mdiobus_unregister(bus); mdiobus_unregister(bus);
if (!IS_ERR(dev->clk))
clk_disable_unprepare(dev->clk); for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
if (IS_ERR(dev->clk[i]))
break;
clk_disable_unprepare(dev->clk[i]);
clk_put(dev->clk[i]);
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment