1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/gpio/consumer.h> 4 #include <linux/mdio.h> 5 #include <linux/module.h> 6 #include <linux/pcs/pcs-mtk-lynxi.h> 7 #include <linux/of_irq.h> 8 #include <linux/of_mdio.h> 9 #include <linux/of_net.h> 10 #include <linux/of_platform.h> 11 #include <linux/regmap.h> 12 #include <linux/reset.h> 13 #include <linux/regulator/consumer.h> 14 #include <net/dsa.h> 15 16 #include "mt7530.h" 17 18 static int 19 mt7530_regmap_write(void *context, unsigned int reg, unsigned int val) 20 { 21 struct mt7530_priv *priv = context; 22 struct mii_bus *bus = priv->bus; 23 u16 page, r, lo, hi; 24 int ret; 25 26 page = (reg >> 6) & 0x3ff; 27 r = (reg >> 2) & 0xf; 28 lo = val & 0xffff; 29 hi = val >> 16; 30 31 ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page); 32 if (ret < 0) 33 return ret; 34 35 ret = bus->write(bus, priv->mdiodev->addr, r, lo); 36 if (ret < 0) 37 return ret; 38 39 ret = bus->write(bus, priv->mdiodev->addr, 0x10, hi); 40 return ret; 41 } 42 43 static int 44 mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val) 45 { 46 struct mt7530_priv *priv = context; 47 struct mii_bus *bus = priv->bus; 48 u16 page, r, lo, hi; 49 int ret; 50 51 page = (reg >> 6) & 0x3ff; 52 r = (reg >> 2) & 0xf; 53 54 ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page); 55 if (ret < 0) 56 return ret; 57 58 lo = bus->read(bus, priv->mdiodev->addr, r); 59 hi = bus->read(bus, priv->mdiodev->addr, 0x10); 60 61 *val = (hi << 16) | (lo & 0xffff); 62 63 return 0; 64 } 65 66 static void 67 mt7530_mdio_regmap_lock(void *mdio_lock) 68 { 69 mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED); 70 } 71 72 static void 73 mt7530_mdio_regmap_unlock(void *mdio_lock) 74 { 75 mutex_unlock(mdio_lock); 76 } 77 78 static const struct regmap_bus mt7530_regmap_bus = { 79 .reg_write = mt7530_regmap_write, 80 .reg_read = mt7530_regmap_read, 81 }; 82 83 static int 84 mt7531_create_sgmii(struct mt7530_priv *priv) 85 { 86 struct regmap_config *mt7531_pcs_config[2] = {}; 87 struct phylink_pcs *pcs; 88 struct regmap *regmap; 89 int i, ret = 0; 90 91 for (i = priv->p5_sgmii ? 0 : 1; i < 2; i++) { 92 mt7531_pcs_config[i] = devm_kzalloc(priv->dev, 93 sizeof(struct regmap_config), 94 GFP_KERNEL); 95 if (!mt7531_pcs_config[i]) { 96 ret = -ENOMEM; 97 break; 98 } 99 100 mt7531_pcs_config[i]->name = i ? "port6" : "port5"; 101 mt7531_pcs_config[i]->reg_bits = 16; 102 mt7531_pcs_config[i]->val_bits = 32; 103 mt7531_pcs_config[i]->reg_stride = 4; 104 mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i); 105 mt7531_pcs_config[i]->max_register = 0x17c; 106 mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock; 107 mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock; 108 mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock; 109 110 regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv, 111 mt7531_pcs_config[i]); 112 if (IS_ERR(regmap)) { 113 ret = PTR_ERR(regmap); 114 break; 115 } 116 pcs = mtk_pcs_lynxi_create(priv->dev, regmap, 117 MT7531_PHYA_CTRL_SIGNAL3, 0); 118 if (!pcs) { 119 ret = -ENXIO; 120 break; 121 } 122 priv->ports[5 + i].sgmii_pcs = pcs; 123 } 124 125 if (ret && i) 126 mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs); 127 128 return ret; 129 } 130 131 static const struct of_device_id mt7530_of_match[] = { 132 { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], }, 133 { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], }, 134 { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], }, 135 { /* sentinel */ }, 136 }; 137 MODULE_DEVICE_TABLE(of, mt7530_of_match); 138 139 static const struct regmap_config regmap_config = { 140 .reg_bits = 16, 141 .val_bits = 32, 142 .reg_stride = 4, 143 .max_register = MT7530_CREV, 144 .disable_locking = true, 145 }; 146 147 static int 148 mt7530_probe(struct mdio_device *mdiodev) 149 { 150 struct mt7530_priv *priv; 151 struct device_node *dn; 152 int ret; 153 154 dn = mdiodev->dev.of_node; 155 156 priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); 157 if (!priv) 158 return -ENOMEM; 159 160 priv->bus = mdiodev->bus; 161 priv->dev = &mdiodev->dev; 162 priv->mdiodev = mdiodev; 163 164 ret = mt7530_probe_common(priv); 165 if (ret) 166 return ret; 167 168 /* Use medatek,mcm property to distinguish hardware type that would 169 * cause a little bit differences on power-on sequence. 170 * Not MCM that indicates switch works as the remote standalone 171 * integrated circuit so the GPIO pin would be used to complete 172 * the reset, otherwise memory-mapped register accessing used 173 * through syscon provides in the case of MCM. 174 */ 175 priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); 176 if (priv->mcm) { 177 dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); 178 179 priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); 180 if (IS_ERR(priv->rstc)) { 181 dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); 182 return PTR_ERR(priv->rstc); 183 } 184 } else { 185 priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", 186 GPIOD_OUT_LOW); 187 if (IS_ERR(priv->reset)) { 188 dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); 189 return PTR_ERR(priv->reset); 190 } 191 } 192 193 if (priv->id == ID_MT7530) { 194 priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); 195 if (IS_ERR(priv->core_pwr)) 196 return PTR_ERR(priv->core_pwr); 197 198 priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); 199 if (IS_ERR(priv->io_pwr)) 200 return PTR_ERR(priv->io_pwr); 201 } 202 203 priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv, 204 ®map_config); 205 if (IS_ERR(priv->regmap)) 206 return PTR_ERR(priv->regmap); 207 208 if (priv->id == ID_MT7531) 209 priv->create_sgmii = mt7531_create_sgmii; 210 211 return dsa_register_switch(priv->ds); 212 } 213 214 static void 215 mt7530_remove(struct mdio_device *mdiodev) 216 { 217 struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); 218 int ret = 0, i; 219 220 if (!priv) 221 return; 222 223 ret = regulator_disable(priv->core_pwr); 224 if (ret < 0) 225 dev_err(priv->dev, 226 "Failed to disable core power: %d\n", ret); 227 228 ret = regulator_disable(priv->io_pwr); 229 if (ret < 0) 230 dev_err(priv->dev, "Failed to disable io pwr: %d\n", 231 ret); 232 233 mt7530_remove_common(priv); 234 235 for (i = 0; i < 2; ++i) 236 mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); 237 } 238 239 static void mt7530_shutdown(struct mdio_device *mdiodev) 240 { 241 struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); 242 243 if (!priv) 244 return; 245 246 dsa_switch_shutdown(priv->ds); 247 248 dev_set_drvdata(&mdiodev->dev, NULL); 249 } 250 251 static struct mdio_driver mt7530_mdio_driver = { 252 .probe = mt7530_probe, 253 .remove = mt7530_remove, 254 .shutdown = mt7530_shutdown, 255 .mdiodrv.driver = { 256 .name = "mt7530-mdio", 257 .of_match_table = mt7530_of_match, 258 }, 259 }; 260 261 mdio_module_driver(mt7530_mdio_driver); 262 263 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 264 MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MDIO)"); 265 MODULE_LICENSE("GPL"); 266