0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/delay.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/of_mdio.h>
0012 #include <linux/of_address.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/regmap.h>
0015
0016
0017 #define MII_ADDR_REG_ADDR 0x10
0018 #define MII_BUSY BIT(0)
0019 #define MII_WRITE BIT(1)
0020 #define MII_CLKRANGE(x) ((x) << 2)
0021 #define MII_CLKRANGE_60_100M MII_CLKRANGE(0)
0022 #define MII_CLKRANGE_100_150M MII_CLKRANGE(1)
0023 #define MII_CLKRANGE_20_35M MII_CLKRANGE(2)
0024 #define MII_CLKRANGE_35_60M MII_CLKRANGE(3)
0025 #define MII_CLKRANGE_150_250M MII_CLKRANGE(4)
0026 #define MII_CLKRANGE_250_300M MII_CLKRANGE(5)
0027 #define MII_CLKRANGE_MASK GENMASK(4, 2)
0028 #define MII_REG_SHIFT 6
0029 #define MII_REG_MASK GENMASK(10, 6)
0030 #define MII_ADDR_SHIFT 11
0031 #define MII_ADDR_MASK GENMASK(15, 11)
0032
0033 #define MII_DATA_REG_ADDR 0x14
0034
0035 #define MII_MDIO_DELAY_USEC (1000)
0036 #define MII_MDIO_RETRY_MSEC (10)
0037
0038 struct ipq8064_mdio {
0039 struct regmap *base;
0040 };
0041
0042 static int
0043 ipq8064_mdio_wait_busy(struct ipq8064_mdio *priv)
0044 {
0045 u32 busy;
0046
0047 return regmap_read_poll_timeout(priv->base, MII_ADDR_REG_ADDR, busy,
0048 !(busy & MII_BUSY), MII_MDIO_DELAY_USEC,
0049 MII_MDIO_RETRY_MSEC * USEC_PER_MSEC);
0050 }
0051
0052 static int
0053 ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset)
0054 {
0055 u32 miiaddr = MII_BUSY | MII_CLKRANGE_250_300M;
0056 struct ipq8064_mdio *priv = bus->priv;
0057 u32 ret_val;
0058 int err;
0059
0060
0061 if (reg_offset & MII_ADDR_C45)
0062 return -EOPNOTSUPP;
0063
0064 miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) |
0065 ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
0066
0067 regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
0068 usleep_range(10, 13);
0069
0070 err = ipq8064_mdio_wait_busy(priv);
0071 if (err)
0072 return err;
0073
0074 regmap_read(priv->base, MII_DATA_REG_ADDR, &ret_val);
0075 return (int)ret_val;
0076 }
0077
0078 static int
0079 ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data)
0080 {
0081 u32 miiaddr = MII_WRITE | MII_BUSY | MII_CLKRANGE_250_300M;
0082 struct ipq8064_mdio *priv = bus->priv;
0083
0084
0085 if (reg_offset & MII_ADDR_C45)
0086 return -EOPNOTSUPP;
0087
0088 regmap_write(priv->base, MII_DATA_REG_ADDR, data);
0089
0090 miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) |
0091 ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
0092
0093 regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
0094
0095
0096
0097
0098 if (reg_offset == 31)
0099 usleep_range(30, 43);
0100 else
0101 usleep_range(10, 13);
0102
0103 return ipq8064_mdio_wait_busy(priv);
0104 }
0105
0106 static const struct regmap_config ipq8064_mdio_regmap_config = {
0107 .reg_bits = 32,
0108 .reg_stride = 4,
0109 .val_bits = 32,
0110 .can_multi_write = false,
0111
0112 .disable_locking = true,
0113
0114 .cache_type = REGCACHE_NONE,
0115 };
0116
0117 static int
0118 ipq8064_mdio_probe(struct platform_device *pdev)
0119 {
0120 struct device_node *np = pdev->dev.of_node;
0121 struct ipq8064_mdio *priv;
0122 struct resource res;
0123 struct mii_bus *bus;
0124 void __iomem *base;
0125 int ret;
0126
0127 if (of_address_to_resource(np, 0, &res))
0128 return -ENOMEM;
0129
0130 base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
0131 if (!base)
0132 return -ENOMEM;
0133
0134 bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
0135 if (!bus)
0136 return -ENOMEM;
0137
0138 bus->name = "ipq8064_mdio_bus";
0139 bus->read = ipq8064_mdio_read;
0140 bus->write = ipq8064_mdio_write;
0141 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
0142 bus->parent = &pdev->dev;
0143
0144 priv = bus->priv;
0145 priv->base = devm_regmap_init_mmio(&pdev->dev, base,
0146 &ipq8064_mdio_regmap_config);
0147 if (IS_ERR(priv->base))
0148 return PTR_ERR(priv->base);
0149
0150 ret = of_mdiobus_register(bus, np);
0151 if (ret)
0152 return ret;
0153
0154 platform_set_drvdata(pdev, bus);
0155 return 0;
0156 }
0157
0158 static int
0159 ipq8064_mdio_remove(struct platform_device *pdev)
0160 {
0161 struct mii_bus *bus = platform_get_drvdata(pdev);
0162
0163 mdiobus_unregister(bus);
0164
0165 return 0;
0166 }
0167
0168 static const struct of_device_id ipq8064_mdio_dt_ids[] = {
0169 { .compatible = "qcom,ipq8064-mdio" },
0170 { }
0171 };
0172 MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids);
0173
0174 static struct platform_driver ipq8064_mdio_driver = {
0175 .probe = ipq8064_mdio_probe,
0176 .remove = ipq8064_mdio_remove,
0177 .driver = {
0178 .name = "ipq8064-mdio",
0179 .of_match_table = ipq8064_mdio_dt_ids,
0180 },
0181 };
0182
0183 module_platform_driver(ipq8064_mdio_driver);
0184
0185 MODULE_DESCRIPTION("Qualcomm IPQ8064 MDIO interface driver");
0186 MODULE_AUTHOR("Christian Lamparter <chunkeey@gmail.com>");
0187 MODULE_AUTHOR("Ansuel Smith <ansuelsmth@gmail.com>");
0188 MODULE_LICENSE("GPL");