0001
0002
0003
0004
0005
0006 #include <linux/delay.h>
0007 #include <linux/io.h>
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/of_platform.h>
0012 #include <linux/of_mdio.h>
0013 #include <linux/phy.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/sched.h>
0016
0017 #define IPROC_GPHY_MDCDIV 0x1a
0018
0019 #define MII_CTRL_OFFSET 0x000
0020
0021 #define MII_CTRL_DIV_SHIFT 0
0022 #define MII_CTRL_PRE_SHIFT 7
0023 #define MII_CTRL_BUSY_SHIFT 8
0024
0025 #define MII_DATA_OFFSET 0x004
0026 #define MII_DATA_MASK 0xffff
0027 #define MII_DATA_TA_SHIFT 16
0028 #define MII_DATA_TA_VAL 2
0029 #define MII_DATA_RA_SHIFT 18
0030 #define MII_DATA_PA_SHIFT 23
0031 #define MII_DATA_OP_SHIFT 28
0032 #define MII_DATA_OP_WRITE 1
0033 #define MII_DATA_OP_READ 2
0034 #define MII_DATA_SB_SHIFT 30
0035
0036 struct iproc_mdio_priv {
0037 struct mii_bus *mii_bus;
0038 void __iomem *base;
0039 };
0040
0041 static inline int iproc_mdio_wait_for_idle(void __iomem *base)
0042 {
0043 u32 val;
0044 unsigned int timeout = 1000;
0045
0046 do {
0047 val = readl(base + MII_CTRL_OFFSET);
0048 if ((val & BIT(MII_CTRL_BUSY_SHIFT)) == 0)
0049 return 0;
0050
0051 usleep_range(1000, 2000);
0052 } while (timeout--);
0053
0054 return -ETIMEDOUT;
0055 }
0056
0057 static inline void iproc_mdio_config_clk(void __iomem *base)
0058 {
0059 u32 val;
0060
0061 val = (IPROC_GPHY_MDCDIV << MII_CTRL_DIV_SHIFT) |
0062 BIT(MII_CTRL_PRE_SHIFT);
0063 writel(val, base + MII_CTRL_OFFSET);
0064 }
0065
0066 static int iproc_mdio_read(struct mii_bus *bus, int phy_id, int reg)
0067 {
0068 struct iproc_mdio_priv *priv = bus->priv;
0069 u32 cmd;
0070 int rc;
0071
0072 rc = iproc_mdio_wait_for_idle(priv->base);
0073 if (rc)
0074 return rc;
0075
0076
0077 cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
0078 (reg << MII_DATA_RA_SHIFT) |
0079 (phy_id << MII_DATA_PA_SHIFT) |
0080 BIT(MII_DATA_SB_SHIFT) |
0081 (MII_DATA_OP_READ << MII_DATA_OP_SHIFT);
0082
0083 writel(cmd, priv->base + MII_DATA_OFFSET);
0084
0085 rc = iproc_mdio_wait_for_idle(priv->base);
0086 if (rc)
0087 return rc;
0088
0089 cmd = readl(priv->base + MII_DATA_OFFSET) & MII_DATA_MASK;
0090
0091 return cmd;
0092 }
0093
0094 static int iproc_mdio_write(struct mii_bus *bus, int phy_id,
0095 int reg, u16 val)
0096 {
0097 struct iproc_mdio_priv *priv = bus->priv;
0098 u32 cmd;
0099 int rc;
0100
0101 rc = iproc_mdio_wait_for_idle(priv->base);
0102 if (rc)
0103 return rc;
0104
0105
0106 cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) |
0107 (reg << MII_DATA_RA_SHIFT) |
0108 (phy_id << MII_DATA_PA_SHIFT) |
0109 BIT(MII_DATA_SB_SHIFT) |
0110 (MII_DATA_OP_WRITE << MII_DATA_OP_SHIFT) |
0111 ((u32)(val) & MII_DATA_MASK);
0112
0113 writel(cmd, priv->base + MII_DATA_OFFSET);
0114
0115 rc = iproc_mdio_wait_for_idle(priv->base);
0116 if (rc)
0117 return rc;
0118
0119 return 0;
0120 }
0121
0122 static int iproc_mdio_probe(struct platform_device *pdev)
0123 {
0124 struct iproc_mdio_priv *priv;
0125 struct mii_bus *bus;
0126 int rc;
0127
0128 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0129 if (!priv)
0130 return -ENOMEM;
0131
0132 priv->base = devm_platform_ioremap_resource(pdev, 0);
0133 if (IS_ERR(priv->base)) {
0134 dev_err(&pdev->dev, "failed to ioremap register\n");
0135 return PTR_ERR(priv->base);
0136 }
0137
0138 priv->mii_bus = mdiobus_alloc();
0139 if (!priv->mii_bus) {
0140 dev_err(&pdev->dev, "MDIO bus alloc failed\n");
0141 return -ENOMEM;
0142 }
0143
0144 bus = priv->mii_bus;
0145 bus->priv = priv;
0146 bus->name = "iProc MDIO bus";
0147 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
0148 bus->parent = &pdev->dev;
0149 bus->read = iproc_mdio_read;
0150 bus->write = iproc_mdio_write;
0151
0152 iproc_mdio_config_clk(priv->base);
0153
0154 rc = of_mdiobus_register(bus, pdev->dev.of_node);
0155 if (rc) {
0156 dev_err(&pdev->dev, "MDIO bus registration failed\n");
0157 goto err_iproc_mdio;
0158 }
0159
0160 platform_set_drvdata(pdev, priv);
0161
0162 dev_info(&pdev->dev, "Broadcom iProc MDIO bus registered\n");
0163
0164 return 0;
0165
0166 err_iproc_mdio:
0167 mdiobus_free(bus);
0168 return rc;
0169 }
0170
0171 static int iproc_mdio_remove(struct platform_device *pdev)
0172 {
0173 struct iproc_mdio_priv *priv = platform_get_drvdata(pdev);
0174
0175 mdiobus_unregister(priv->mii_bus);
0176 mdiobus_free(priv->mii_bus);
0177
0178 return 0;
0179 }
0180
0181 #ifdef CONFIG_PM_SLEEP
0182 static int iproc_mdio_resume(struct device *dev)
0183 {
0184 struct platform_device *pdev = to_platform_device(dev);
0185 struct iproc_mdio_priv *priv = platform_get_drvdata(pdev);
0186
0187
0188 iproc_mdio_config_clk(priv->base);
0189
0190 return 0;
0191 }
0192
0193 static const struct dev_pm_ops iproc_mdio_pm_ops = {
0194 .resume = iproc_mdio_resume
0195 };
0196 #endif
0197
0198 static const struct of_device_id iproc_mdio_of_match[] = {
0199 { .compatible = "brcm,iproc-mdio", },
0200 { },
0201 };
0202 MODULE_DEVICE_TABLE(of, iproc_mdio_of_match);
0203
0204 static struct platform_driver iproc_mdio_driver = {
0205 .driver = {
0206 .name = "iproc-mdio",
0207 .of_match_table = iproc_mdio_of_match,
0208 #ifdef CONFIG_PM_SLEEP
0209 .pm = &iproc_mdio_pm_ops,
0210 #endif
0211 },
0212 .probe = iproc_mdio_probe,
0213 .remove = iproc_mdio_remove,
0214 };
0215
0216 module_platform_driver(iproc_mdio_driver);
0217
0218 MODULE_AUTHOR("Broadcom Corporation");
0219 MODULE_DESCRIPTION("Broadcom iProc MDIO bus controller");
0220 MODULE_LICENSE("GPL v2");
0221 MODULE_ALIAS("platform:iproc-mdio");