1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Driver for MMIO-Mapped MDIO devices. Some IPs expose internal PHYs or PCS 3 * within the MMIO-mapped area 4 * 5 * Copyright (C) 2023 Maxime Chevallier <maxime.chevallier@bootlin.com> 6 */ 7 #include <linux/bitfield.h> 8 #include <linux/delay.h> 9 #include <linux/mdio.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_mdio.h> 13 #include <linux/phy.h> 14 #include <linux/platform_device.h> 15 #include <linux/regmap.h> 16 #include <linux/mdio/mdio-regmap.h> 17 18 #define DRV_NAME "mdio-regmap" 19 20 struct mdio_regmap_priv { 21 struct regmap *regmap; 22 u8 valid_addr; 23 }; 24 25 static int mdio_regmap_read_c22(struct mii_bus *bus, int addr, int regnum) 26 { 27 struct mdio_regmap_priv *ctx = bus->priv; 28 unsigned int val; 29 int ret; 30 31 if (ctx->valid_addr != addr) 32 return -ENODEV; 33 34 ret = regmap_read(ctx->regmap, regnum, &val); 35 if (ret < 0) 36 return ret; 37 38 return val; 39 } 40 41 static int mdio_regmap_write_c22(struct mii_bus *bus, int addr, int regnum, 42 u16 val) 43 { 44 struct mdio_regmap_priv *ctx = bus->priv; 45 46 if (ctx->valid_addr != addr) 47 return -ENODEV; 48 49 return regmap_write(ctx->regmap, regnum, val); 50 } 51 52 struct mii_bus *devm_mdio_regmap_register(struct device *dev, 53 const struct mdio_regmap_config *config) 54 { 55 struct mdio_regmap_priv *mr; 56 struct mii_bus *mii; 57 int rc; 58 59 if (!config->parent) 60 return ERR_PTR(-EINVAL); 61 62 mii = devm_mdiobus_alloc_size(config->parent, sizeof(*mr)); 63 if (!mii) 64 return ERR_PTR(-ENOMEM); 65 66 mr = mii->priv; 67 mr->regmap = config->regmap; 68 mr->valid_addr = config->valid_addr; 69 70 mii->name = DRV_NAME; 71 strscpy(mii->id, config->name, MII_BUS_ID_SIZE); 72 mii->parent = config->parent; 73 mii->read = mdio_regmap_read_c22; 74 mii->write = mdio_regmap_write_c22; 75 76 if (config->autoscan) 77 mii->phy_mask = ~BIT(config->valid_addr); 78 else 79 mii->phy_mask = ~0; 80 81 rc = devm_mdiobus_register(dev, mii); 82 if (rc) { 83 dev_err(config->parent, "Cannot register MDIO bus![%s] (%d)\n", mii->id, rc); 84 return ERR_PTR(rc); 85 } 86 87 return mii; 88 } 89 EXPORT_SYMBOL_GPL(devm_mdio_regmap_register); 90 91 MODULE_DESCRIPTION("MDIO API over regmap"); 92 MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>"); 93 MODULE_LICENSE("GPL"); 94