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