diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-28 21:02:06 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-28 21:02:06 +0300 |
commit | 52f8cf8b0b540a8e4ebba52fe5ee3f57c2682f92 (patch) | |
tree | a73a7eed36ad7895e150012e29835aa8d83b96d7 /drivers/base/regmap/regmap-mdio.c | |
parent | ef60eb0eb6e0aaf0aae302cb6362a81b2491e997 (diff) | |
parent | d17032f2befaceef2c8c6b761ae657bc700b0be3 (diff) | |
download | linux-52f8cf8b0b540a8e4ebba52fe5ee3f57c2682f92.tar.xz |
Merge tag 'regmap-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown:
"The big thing this release is support for accessing the register maps
of MDIO devices via the framework. We've also added support for 7/17
register formats on bytestream transports and inverted status
registers in regmap-irq"
* tag 'regmap-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
regmap: mdio: Reject invalid addresses
regmap: mdio: Fix regmap_bus pointer constness
regmap: mdio: Add clause-45 support
regmap: mdio: Clean up invalid clause-22 addresses
regmap-irq: Introduce inverted status registers support
regmap: add support for 7/17 register formating
regmap: mdio: Don't modify output if error happened
regmap: Add MDIO bus support
regmap-i2c: Set regmap max raw r/w from quirks
Diffstat (limited to 'drivers/base/regmap/regmap-mdio.c')
-rw-r--r-- | drivers/base/regmap/regmap-mdio.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/base/regmap/regmap-mdio.c b/drivers/base/regmap/regmap-mdio.c new file mode 100644 index 000000000000..6a20201299f5 --- /dev/null +++ b/drivers/base/regmap/regmap-mdio.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/errno.h> +#include <linux/mdio.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#define REGVAL_MASK GENMASK(15, 0) +#define REGNUM_C22_MASK GENMASK(4, 0) +/* Clause-45 mask includes the device type (5 bit) and actual register number (16 bit) */ +#define REGNUM_C45_MASK GENMASK(20, 0) + +static int regmap_mdio_read(struct mdio_device *mdio_dev, u32 reg, unsigned int *val) +{ + int ret; + + ret = mdiobus_read(mdio_dev->bus, mdio_dev->addr, reg); + if (ret < 0) + return ret; + + *val = ret & REGVAL_MASK; + return 0; +} + +static int regmap_mdio_write(struct mdio_device *mdio_dev, u32 reg, unsigned int val) +{ + return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val); +} + +static int regmap_mdio_c22_read(void *context, unsigned int reg, unsigned int *val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C22_MASK)) + return -ENXIO; + + return regmap_mdio_read(mdio_dev, reg, val); +} + +static int regmap_mdio_c22_write(void *context, unsigned int reg, unsigned int val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C22_MASK)) + return -ENXIO; + + return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val); +} + +static const struct regmap_bus regmap_mdio_c22_bus = { + .reg_write = regmap_mdio_c22_write, + .reg_read = regmap_mdio_c22_read, +}; + +static int regmap_mdio_c45_read(void *context, unsigned int reg, unsigned int *val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C45_MASK)) + return -ENXIO; + + return regmap_mdio_read(mdio_dev, MII_ADDR_C45 | reg, val); +} + +static int regmap_mdio_c45_write(void *context, unsigned int reg, unsigned int val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C45_MASK)) + return -ENXIO; + + return regmap_mdio_write(mdio_dev, MII_ADDR_C45 | reg, val); +} + +static const struct regmap_bus regmap_mdio_c45_bus = { + .reg_write = regmap_mdio_c45_write, + .reg_read = regmap_mdio_c45_read, +}; + +struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev, + const struct regmap_config *config, struct lock_class_key *lock_key, + const char *lock_name) +{ + const struct regmap_bus *bus; + + if (config->reg_bits == 5 && config->val_bits == 16) + bus = ®map_mdio_c22_bus; + else if (config->reg_bits == 21 && config->val_bits == 16) + bus = ®map_mdio_c45_bus; + else + return ERR_PTR(-EOPNOTSUPP); + + return __regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__regmap_init_mdio); + +struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev, + const struct regmap_config *config, struct lock_class_key *lock_key, + const char *lock_name) +{ + const struct regmap_bus *bus; + + if (config->reg_bits == 5 && config->val_bits == 16) + bus = ®map_mdio_c22_bus; + else if (config->reg_bits == 21 && config->val_bits == 16) + bus = ®map_mdio_c45_bus; + else + return ERR_PTR(-EOPNOTSUPP); + + return __devm_regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_mdio); + +MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>"); +MODULE_DESCRIPTION("Regmap MDIO Module"); +MODULE_LICENSE("GPL v2"); |