1 /* Copyright (c) 2014 Linaro Ltd.
2 * Copyright (c) 2014 Hisilicon Limited.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
13 #include <linux/of_mdio.h>
14 #include <linux/delay.h>
16 #define MDIO_CMD_REG 0x0
17 #define MDIO_ADDR_REG 0x4
18 #define MDIO_WDATA_REG 0x8
19 #define MDIO_RDATA_REG 0xc
20 #define MDIO_STA_REG 0x10
22 #define MDIO_START BIT(14)
23 #define MDIO_R_VALID BIT(1)
24 #define MDIO_READ (BIT(12) | BIT(11) | MDIO_START)
25 #define MDIO_WRITE (BIT(12) | BIT(10) | MDIO_START)
27 struct hip04_mdio_priv {
31 #define WAIT_TIMEOUT 10
32 static int hip04_mdio_wait_ready(struct mii_bus *bus)
34 struct hip04_mdio_priv *priv = bus->priv;
37 for (i = 0; readl_relaxed(priv->base + MDIO_CMD_REG) & MDIO_START; i++) {
38 if (i == WAIT_TIMEOUT)
46 static int hip04_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
48 struct hip04_mdio_priv *priv = bus->priv;
52 ret = hip04_mdio_wait_ready(bus);
56 val = regnum | (mii_id << 5) | MDIO_READ;
57 writel_relaxed(val, priv->base + MDIO_CMD_REG);
59 ret = hip04_mdio_wait_ready(bus);
63 val = readl_relaxed(priv->base + MDIO_STA_REG);
64 if (val & MDIO_R_VALID) {
65 dev_err(bus->parent, "SMI bus read not valid\n");
70 val = readl_relaxed(priv->base + MDIO_RDATA_REG);
76 static int hip04_mdio_write(struct mii_bus *bus, int mii_id,
77 int regnum, u16 value)
79 struct hip04_mdio_priv *priv = bus->priv;
83 ret = hip04_mdio_wait_ready(bus);
87 writel_relaxed(value, priv->base + MDIO_WDATA_REG);
88 val = regnum | (mii_id << 5) | MDIO_WRITE;
89 writel_relaxed(val, priv->base + MDIO_CMD_REG);
94 static int hip04_mdio_reset(struct mii_bus *bus)
98 for (i = 0; i < PHY_MAX_ADDR; i++) {
99 hip04_mdio_write(bus, i, 22, 0);
100 temp = hip04_mdio_read(bus, i, MII_BMCR);
105 if (hip04_mdio_write(bus, i, MII_BMCR, temp) < 0)
113 static int hip04_mdio_probe(struct platform_device *pdev)
117 struct hip04_mdio_priv *priv;
120 bus = mdiobus_alloc_size(sizeof(struct hip04_mdio_priv));
122 dev_err(&pdev->dev, "Cannot allocate MDIO bus\n");
126 bus->name = "hip04_mdio_bus";
127 bus->read = hip04_mdio_read;
128 bus->write = hip04_mdio_write;
129 bus->reset = hip04_mdio_reset;
130 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
131 bus->parent = &pdev->dev;
134 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
135 priv->base = devm_ioremap_resource(&pdev->dev, r);
136 if (IS_ERR(priv->base)) {
137 ret = PTR_ERR(priv->base);
141 ret = of_mdiobus_register(bus, pdev->dev.of_node);
143 dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
147 platform_set_drvdata(pdev, bus);
156 static int hip04_mdio_remove(struct platform_device *pdev)
158 struct mii_bus *bus = platform_get_drvdata(pdev);
160 mdiobus_unregister(bus);
166 static const struct of_device_id hip04_mdio_match[] = {
167 { .compatible = "hisilicon,hip04-mdio" },
170 MODULE_DEVICE_TABLE(of, hip04_mdio_match);
172 static struct platform_driver hip04_mdio_driver = {
173 .probe = hip04_mdio_probe,
174 .remove = hip04_mdio_remove,
176 .name = "hip04-mdio",
177 .owner = THIS_MODULE,
178 .of_match_table = hip04_mdio_match,
182 module_platform_driver(hip04_mdio_driver);
184 MODULE_DESCRIPTION("HISILICON P04 MDIO interface driver");
185 MODULE_LICENSE("GPL v2");
186 MODULE_ALIAS("platform:hip04-mdio");