0001
0002
0003
0004
0005
0006
0007 #include <linux/delay.h>
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/mutex.h>
0011 #include <linux/of_address.h>
0012 #include <linux/of_mdio.h>
0013 #include <linux/phy.h>
0014 #include <linux/platform_device.h>
0015
0016 #define REG_PHY_CTRL 0
0017 #define REG_PHY_WRITE_DATA 4
0018
0019
0020 #define MIIWR BIT(27)
0021 #define MIIRD BIT(26)
0022 #define REGAD_MASK 0x3e00000
0023 #define PHYAD_MASK 0x1f0000
0024 #define MIIRDATA_MASK 0xffff
0025
0026
0027 #define MIIWDATA_MASK 0xffff
0028
0029 struct moxart_mdio_data {
0030 void __iomem *base;
0031 };
0032
0033 static int moxart_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
0034 {
0035 struct moxart_mdio_data *data = bus->priv;
0036 u32 ctrl = 0;
0037 unsigned int count = 5;
0038
0039 dev_dbg(&bus->dev, "%s\n", __func__);
0040
0041 ctrl |= MIIRD | ((mii_id << 16) & PHYAD_MASK) |
0042 ((regnum << 21) & REGAD_MASK);
0043
0044 writel(ctrl, data->base + REG_PHY_CTRL);
0045
0046 do {
0047 ctrl = readl(data->base + REG_PHY_CTRL);
0048
0049 if (!(ctrl & MIIRD))
0050 return ctrl & MIIRDATA_MASK;
0051
0052 mdelay(10);
0053 count--;
0054 } while (count > 0);
0055
0056 dev_dbg(&bus->dev, "%s timed out\n", __func__);
0057
0058 return -ETIMEDOUT;
0059 }
0060
0061 static int moxart_mdio_write(struct mii_bus *bus, int mii_id,
0062 int regnum, u16 value)
0063 {
0064 struct moxart_mdio_data *data = bus->priv;
0065 u32 ctrl = 0;
0066 unsigned int count = 5;
0067
0068 dev_dbg(&bus->dev, "%s\n", __func__);
0069
0070 ctrl |= MIIWR | ((mii_id << 16) & PHYAD_MASK) |
0071 ((regnum << 21) & REGAD_MASK);
0072
0073 value &= MIIWDATA_MASK;
0074
0075 writel(value, data->base + REG_PHY_WRITE_DATA);
0076 writel(ctrl, data->base + REG_PHY_CTRL);
0077
0078 do {
0079 ctrl = readl(data->base + REG_PHY_CTRL);
0080
0081 if (!(ctrl & MIIWR))
0082 return 0;
0083
0084 mdelay(10);
0085 count--;
0086 } while (count > 0);
0087
0088 dev_dbg(&bus->dev, "%s timed out\n", __func__);
0089
0090 return -ETIMEDOUT;
0091 }
0092
0093 static int moxart_mdio_reset(struct mii_bus *bus)
0094 {
0095 int data, i;
0096
0097 for (i = 0; i < PHY_MAX_ADDR; i++) {
0098 data = moxart_mdio_read(bus, i, MII_BMCR);
0099 if (data < 0)
0100 continue;
0101
0102 data |= BMCR_RESET;
0103 if (moxart_mdio_write(bus, i, MII_BMCR, data) < 0)
0104 continue;
0105 }
0106
0107 return 0;
0108 }
0109
0110 static int moxart_mdio_probe(struct platform_device *pdev)
0111 {
0112 struct device_node *np = pdev->dev.of_node;
0113 struct mii_bus *bus;
0114 struct moxart_mdio_data *data;
0115 int ret, i;
0116
0117 bus = mdiobus_alloc_size(sizeof(*data));
0118 if (!bus)
0119 return -ENOMEM;
0120
0121 bus->name = "MOXA ART Ethernet MII";
0122 bus->read = &moxart_mdio_read;
0123 bus->write = &moxart_mdio_write;
0124 bus->reset = &moxart_mdio_reset;
0125 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d-mii", pdev->name, pdev->id);
0126 bus->parent = &pdev->dev;
0127
0128
0129
0130
0131
0132
0133
0134
0135 for (i = 0; i < PHY_MAX_ADDR; i++)
0136 bus->irq[i] = PHY_MAC_INTERRUPT;
0137
0138 data = bus->priv;
0139 data->base = devm_platform_ioremap_resource(pdev, 0);
0140 if (IS_ERR(data->base)) {
0141 ret = PTR_ERR(data->base);
0142 goto err_out_free_mdiobus;
0143 }
0144
0145 ret = of_mdiobus_register(bus, np);
0146 if (ret < 0)
0147 goto err_out_free_mdiobus;
0148
0149 platform_set_drvdata(pdev, bus);
0150
0151 return 0;
0152
0153 err_out_free_mdiobus:
0154 mdiobus_free(bus);
0155 return ret;
0156 }
0157
0158 static int moxart_mdio_remove(struct platform_device *pdev)
0159 {
0160 struct mii_bus *bus = platform_get_drvdata(pdev);
0161
0162 mdiobus_unregister(bus);
0163 mdiobus_free(bus);
0164
0165 return 0;
0166 }
0167
0168 static const struct of_device_id moxart_mdio_dt_ids[] = {
0169 { .compatible = "moxa,moxart-mdio" },
0170 { }
0171 };
0172 MODULE_DEVICE_TABLE(of, moxart_mdio_dt_ids);
0173
0174 static struct platform_driver moxart_mdio_driver = {
0175 .probe = moxart_mdio_probe,
0176 .remove = moxart_mdio_remove,
0177 .driver = {
0178 .name = "moxart-mdio",
0179 .of_match_table = moxart_mdio_dt_ids,
0180 },
0181 };
0182
0183 module_platform_driver(moxart_mdio_driver);
0184
0185 MODULE_DESCRIPTION("MOXA ART MDIO interface driver");
0186 MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
0187 MODULE_LICENSE("GPL v2");