0001
0002
0003
0004
0005 #include <linux/delay.h>
0006 #include <linux/io.h>
0007 #include <linux/iopoll.h>
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/of_address.h>
0011 #include <linux/of_mdio.h>
0012 #include <linux/phy.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/clk.h>
0015
0016 #define MDIO_MODE_REG 0x40
0017 #define MDIO_ADDR_REG 0x44
0018 #define MDIO_DATA_WRITE_REG 0x48
0019 #define MDIO_DATA_READ_REG 0x4c
0020 #define MDIO_CMD_REG 0x50
0021 #define MDIO_CMD_ACCESS_BUSY BIT(16)
0022 #define MDIO_CMD_ACCESS_START BIT(8)
0023 #define MDIO_CMD_ACCESS_CODE_READ 0
0024 #define MDIO_CMD_ACCESS_CODE_WRITE 1
0025 #define MDIO_CMD_ACCESS_CODE_C45_ADDR 0
0026 #define MDIO_CMD_ACCESS_CODE_C45_WRITE 1
0027 #define MDIO_CMD_ACCESS_CODE_C45_READ 2
0028
0029
0030 #define MDIO_MODE_C45 BIT(8)
0031
0032 #define IPQ4019_MDIO_TIMEOUT 10000
0033 #define IPQ4019_MDIO_SLEEP 10
0034
0035
0036 #define IPQ_MDIO_CLK_RATE 100000000
0037
0038 #define IPQ_PHY_SET_DELAY_US 100000
0039
0040 struct ipq4019_mdio_data {
0041 void __iomem *membase;
0042 void __iomem *eth_ldo_rdy;
0043 struct clk *mdio_clk;
0044 };
0045
0046 static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
0047 {
0048 struct ipq4019_mdio_data *priv = bus->priv;
0049 unsigned int busy;
0050
0051 return readl_poll_timeout(priv->membase + MDIO_CMD_REG, busy,
0052 (busy & MDIO_CMD_ACCESS_BUSY) == 0,
0053 IPQ4019_MDIO_SLEEP, IPQ4019_MDIO_TIMEOUT);
0054 }
0055
0056 static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
0057 {
0058 struct ipq4019_mdio_data *priv = bus->priv;
0059 unsigned int data;
0060 unsigned int cmd;
0061
0062 if (ipq4019_mdio_wait_busy(bus))
0063 return -ETIMEDOUT;
0064
0065
0066 if (regnum & MII_ADDR_C45) {
0067 unsigned int mmd = (regnum >> 16) & 0x1F;
0068 unsigned int reg = regnum & 0xFFFF;
0069
0070
0071 data = readl(priv->membase + MDIO_MODE_REG);
0072
0073 data |= MDIO_MODE_C45;
0074
0075 writel(data, priv->membase + MDIO_MODE_REG);
0076
0077
0078 writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
0079
0080
0081 writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
0082
0083 cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
0084 } else {
0085
0086 data = readl(priv->membase + MDIO_MODE_REG);
0087
0088 data &= ~MDIO_MODE_C45;
0089
0090 writel(data, priv->membase + MDIO_MODE_REG);
0091
0092
0093 writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
0094
0095 cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ;
0096 }
0097
0098
0099 writel(cmd, priv->membase + MDIO_CMD_REG);
0100
0101
0102 if (ipq4019_mdio_wait_busy(bus))
0103 return -ETIMEDOUT;
0104
0105 if (regnum & MII_ADDR_C45) {
0106 cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_READ;
0107
0108 writel(cmd, priv->membase + MDIO_CMD_REG);
0109
0110 if (ipq4019_mdio_wait_busy(bus))
0111 return -ETIMEDOUT;
0112 }
0113
0114
0115 return readl(priv->membase + MDIO_DATA_READ_REG);
0116 }
0117
0118 static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
0119 u16 value)
0120 {
0121 struct ipq4019_mdio_data *priv = bus->priv;
0122 unsigned int data;
0123 unsigned int cmd;
0124
0125 if (ipq4019_mdio_wait_busy(bus))
0126 return -ETIMEDOUT;
0127
0128
0129 if (regnum & MII_ADDR_C45) {
0130 unsigned int mmd = (regnum >> 16) & 0x1F;
0131 unsigned int reg = regnum & 0xFFFF;
0132
0133
0134 data = readl(priv->membase + MDIO_MODE_REG);
0135
0136 data |= MDIO_MODE_C45;
0137
0138 writel(data, priv->membase + MDIO_MODE_REG);
0139
0140
0141 writel((mii_id << 8) | mmd, priv->membase + MDIO_ADDR_REG);
0142
0143
0144 writel(reg, priv->membase + MDIO_DATA_WRITE_REG);
0145
0146 cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_ADDR;
0147
0148 writel(cmd, priv->membase + MDIO_CMD_REG);
0149
0150 if (ipq4019_mdio_wait_busy(bus))
0151 return -ETIMEDOUT;
0152 } else {
0153
0154 data = readl(priv->membase + MDIO_MODE_REG);
0155
0156 data &= ~MDIO_MODE_C45;
0157
0158 writel(data, priv->membase + MDIO_MODE_REG);
0159
0160
0161 writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
0162 }
0163
0164
0165 writel(value, priv->membase + MDIO_DATA_WRITE_REG);
0166
0167
0168 if (regnum & MII_ADDR_C45)
0169 cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_C45_WRITE;
0170 else
0171 cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
0172
0173 writel(cmd, priv->membase + MDIO_CMD_REG);
0174
0175
0176 if (ipq4019_mdio_wait_busy(bus))
0177 return -ETIMEDOUT;
0178
0179 return 0;
0180 }
0181
0182 static int ipq_mdio_reset(struct mii_bus *bus)
0183 {
0184 struct ipq4019_mdio_data *priv = bus->priv;
0185 u32 val;
0186 int ret;
0187
0188
0189
0190
0191 if (priv->eth_ldo_rdy) {
0192 val = readl(priv->eth_ldo_rdy);
0193 val |= BIT(0);
0194 writel(val, priv->eth_ldo_rdy);
0195 fsleep(IPQ_PHY_SET_DELAY_US);
0196 }
0197
0198
0199 ret = clk_set_rate(priv->mdio_clk, IPQ_MDIO_CLK_RATE);
0200 if (ret)
0201 return ret;
0202
0203 ret = clk_prepare_enable(priv->mdio_clk);
0204 if (ret == 0)
0205 mdelay(10);
0206
0207 return ret;
0208 }
0209
0210 static int ipq4019_mdio_probe(struct platform_device *pdev)
0211 {
0212 struct ipq4019_mdio_data *priv;
0213 struct mii_bus *bus;
0214 struct resource *res;
0215 int ret;
0216
0217 bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
0218 if (!bus)
0219 return -ENOMEM;
0220
0221 priv = bus->priv;
0222
0223 priv->membase = devm_platform_ioremap_resource(pdev, 0);
0224 if (IS_ERR(priv->membase))
0225 return PTR_ERR(priv->membase);
0226
0227 priv->mdio_clk = devm_clk_get_optional(&pdev->dev, "gcc_mdio_ahb_clk");
0228 if (IS_ERR(priv->mdio_clk))
0229 return PTR_ERR(priv->mdio_clk);
0230
0231
0232
0233 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0234 if (res)
0235 priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res);
0236
0237 bus->name = "ipq4019_mdio";
0238 bus->read = ipq4019_mdio_read;
0239 bus->write = ipq4019_mdio_write;
0240 bus->reset = ipq_mdio_reset;
0241 bus->parent = &pdev->dev;
0242 snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
0243
0244 ret = of_mdiobus_register(bus, pdev->dev.of_node);
0245 if (ret) {
0246 dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
0247 return ret;
0248 }
0249
0250 platform_set_drvdata(pdev, bus);
0251
0252 return 0;
0253 }
0254
0255 static int ipq4019_mdio_remove(struct platform_device *pdev)
0256 {
0257 struct mii_bus *bus = platform_get_drvdata(pdev);
0258
0259 mdiobus_unregister(bus);
0260
0261 return 0;
0262 }
0263
0264 static const struct of_device_id ipq4019_mdio_dt_ids[] = {
0265 { .compatible = "qcom,ipq4019-mdio" },
0266 { .compatible = "qcom,ipq5018-mdio" },
0267 { }
0268 };
0269 MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids);
0270
0271 static struct platform_driver ipq4019_mdio_driver = {
0272 .probe = ipq4019_mdio_probe,
0273 .remove = ipq4019_mdio_remove,
0274 .driver = {
0275 .name = "ipq4019-mdio",
0276 .of_match_table = ipq4019_mdio_dt_ids,
0277 },
0278 };
0279
0280 module_platform_driver(ipq4019_mdio_driver);
0281
0282 MODULE_DESCRIPTION("ipq4019 MDIO interface driver");
0283 MODULE_AUTHOR("Qualcomm Atheros");
0284 MODULE_LICENSE("Dual BSD/GPL");