diff mbox series

[v2,2/2] netdev/phy: add MDIO bus multiplexer driven by a regmap

Message ID 20190204142435.21175-3-pankaj.bansal@nxp.com
State Changes Requested
Delegated to: David Miller
Headers show
Series add MDIO bus multiplexer driven by a regmap device | expand

Commit Message

Pankaj Bansal Feb. 4, 2019, 8:59 a.m. UTC
Add support for an MDIO bus multiplexer controlled by a regmap
device, like an FPGA.

Tested on a NXP LX2160AQDS board which uses the "QIXIS" FPGA
attached to the i2c bus.

Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
---

Notes:
    V2:
    - Added Kconfig entry for regmap based mdio mux
    - restrict the comment lines to 80 chars
    - use kerneldoc formatting for this function documentation.

 drivers/net/phy/Kconfig           |  14 +++
 drivers/net/phy/Makefile          |   1 +
 drivers/net/phy/mdio-mux-regmap.c | 171 ++++++++++++++++++++++++++++
 include/linux/mdio-mux.h          |  34 ++++++
 4 files changed, 220 insertions(+)

Comments

Andrew Lunn Feb. 4, 2019, 1:46 p.m. UTC | #1
On Mon, Feb 04, 2019 at 08:59:50AM +0000, Pankaj Bansal wrote:
> Add support for an MDIO bus multiplexer controlled by a regmap
> device, like an FPGA.

Hi Pankaj

Thanks for adding the binding documentation.

> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index 5805c0b7d60e..0827a700eb31 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_MDIO_BCM_IPROC)	+= mdio-bcm-iproc.o
>  obj-$(CONFIG_MDIO_BCM_UNIMAC)	+= mdio-bcm-unimac.o
>  obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
>  obj-$(CONFIG_MDIO_BUS_MUX)	+= mdio-mux.o
> +obj-$(CONFIG_MDIO_BUS_MUX_REGMAP)	+= mdio-mux-regmap.o
>  obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC)	+= mdio-mux-bcm-iproc.o
>  obj-$(CONFIG_MDIO_BUS_MUX_GPIO)	+= mdio-mux-gpio.o
>  obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o

We try to keep the Makefile sorting in alphabetical order.


> +/**
> + * mdio_mux_regmap_uninit - relinquish the control of MDIO bus muxing using
> + *			    regmap constructs.
> + * @data: address of data allocated by mdio_mux_regmap_init
> + */
> +int mdio_mux_regmap_uninit(void *data)
> +{
> +	struct mdio_mux_regmap_state *s = data;
> +
> +	mdio_mux_uninit(s->mux_handle);
> +
> +	return 0;
> +}

Please make this a void function, since there is nothing to return.

       Andrew
kernel test robot Feb. 4, 2019, 2:51 p.m. UTC | #2
Hi Pankaj,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on net/master]
[also build test ERROR on v5.0-rc4]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Pankaj-Bansal/add-MDIO-bus-multiplexer-driven-by-a-regmap-device/20190204-213429
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 8.2.0-11) 8.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=8.2.0 make.cross ARCH=sh 

All errors (new ones prefixed by >>):

>> drivers/net/phy/mdio-mux-regmap.c:72:5: error: redefinition of 'mdio_mux_regmap_init'
    int mdio_mux_regmap_init(struct device *dev,
        ^~~~~~~~~~~~~~~~~~~~
   In file included from drivers/net/phy/mdio-mux-regmap.c:18:
   include/linux/mdio-mux.h:53:19: note: previous definition of 'mdio_mux_regmap_init' was here
    static inline int mdio_mux_regmap_init(struct device *dev,
                      ^~~~~~~~~~~~~~~~~~~~
>> drivers/net/phy/mdio-mux-regmap.c:158:5: error: redefinition of 'mdio_mux_regmap_uninit'
    int mdio_mux_regmap_uninit(void *data)
        ^~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/net/phy/mdio-mux-regmap.c:18:
   include/linux/mdio-mux.h:60:19: note: previous definition of 'mdio_mux_regmap_uninit' was here
    static inline int mdio_mux_regmap_uninit(void *data)
                      ^~~~~~~~~~~~~~~~~~~~~~

vim +/mdio_mux_regmap_init +72 drivers/net/phy/mdio-mux-regmap.c

    62	
    63	/**
    64	 * mdio_mux_regmap_init - control MDIO bus muxing using regmap constructs.
    65	 * @dev: device with which regmap construct is associated.
    66	 * @mux_node: mdio bus mux node that contains parent mdio bus phandle.
    67	 *	      This node also contains sub nodes, where each subnode denotes
    68	 *	      a child mdio bus. All the child mdio buses are muxed, i.e. at a
    69	 *	      time only one of the child mdio buses can be used.
    70	 * @data: to store the address of data allocated by this function
    71	 */
  > 72	int mdio_mux_regmap_init(struct device *dev,
    73				 struct device_node *mux_node,
    74				 void **data)
    75	{
    76		struct device_node *child;
    77		struct mdio_mux_regmap_state *s;
    78		int ret;
    79		u32 val;
    80	
    81		dev_dbg(dev, "probing node %pOF\n", mux_node);
    82	
    83		s = devm_kzalloc(dev, sizeof(*s), GFP_KERNEL);
    84		if (!s)
    85			return -ENOMEM;
    86	
    87		s->regmap = dev_get_regmap(dev, NULL);
    88		if (IS_ERR(s->regmap)) {
    89			dev_err(dev, "Failed to get parent regmap\n");
    90			return PTR_ERR(s->regmap);
    91		}
    92	
    93		ret = of_property_read_u32(mux_node, "reg", &s->mux_reg);
    94		if (ret) {
    95			dev_err(dev, "missing or invalid reg property\n");
    96			return -ENODEV;
    97		}
    98	
    99		/* Test Register read write */
   100		ret = regmap_read(s->regmap, s->mux_reg, &val);
   101		if (ret) {
   102			dev_err(dev, "error while reading reg\n");
   103			return ret;
   104		}
   105	
   106		ret = regmap_write(s->regmap, s->mux_reg, val);
   107		if (ret) {
   108			dev_err(dev, "error while writing reg\n");
   109			return ret;
   110		}
   111	
   112		ret = of_property_read_u32(mux_node, "mux-mask", &s->mask);
   113		if (ret) {
   114			dev_err(dev, "missing or invalid mux-mask property\n");
   115			return -ENODEV;
   116		}
   117	
   118		/* Verify that the 'reg' property of each child MDIO bus does not
   119		 * set any bits outside of the 'mask'.
   120		 */
   121		for_each_available_child_of_node(mux_node, child) {
   122			ret = of_property_read_u32(child, "reg", &val);
   123			if (ret) {
   124				dev_err(dev, "%pOF is missing a 'reg' property\n",
   125					child);
   126				of_node_put(child);
   127				return -ENODEV;
   128			}
   129			if (val & ~s->mask) {
   130				dev_err(dev,
   131					"%pOF has a 'reg' value with unmasked bits\n",
   132					child);
   133				of_node_put(child);
   134				return -ENODEV;
   135			}
   136		}
   137	
   138		ret = mdio_mux_init(dev, mux_node, mdio_mux_regmap_switch_fn,
   139				    &s->mux_handle, s, NULL);
   140		if (ret) {
   141			if (ret != -EPROBE_DEFER)
   142				dev_err(dev, "failed to register mdio-mux bus %pOF\n",
   143					mux_node);
   144			return ret;
   145		}
   146	
   147		*data = s;
   148	
   149		return 0;
   150	}
   151	EXPORT_SYMBOL_GPL(mdio_mux_regmap_init);
   152	
   153	/**
   154	 * mdio_mux_regmap_uninit - relinquish the control of MDIO bus muxing using
   155	 *			    regmap constructs.
   156	 * @data: address of data allocated by mdio_mux_regmap_init
   157	 */
 > 158	int mdio_mux_regmap_uninit(void *data)
   159	{
   160		struct mdio_mux_regmap_state *s = data;
   161	
   162		mdio_mux_uninit(s->mux_handle);
   163	
   164		return 0;
   165	}
   166	EXPORT_SYMBOL_GPL(mdio_mux_regmap_uninit);
   167	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Pankaj Bansal Feb. 5, 2019, 3:52 a.m. UTC | #3
Hi Andrew,

I am getting this compilation error when the mdio-mux-regmap.ko is built as standalone module.
This error doesn't come when the mdio-mux-regmap is built as part of linux kernel.

I don't understand the reason for it. Inline definitions of functions are only defined if CONFIG_MDIO_BUS_MUX_REGMAP
Is NOT defined. 

BUT it is defined as " CONFIG_MDIO_BUS_MUX_REGMAP = m"

Can you please help me to solve this?

Regards,
Pankaj Bansal

> -----Original Message-----
> From: kbuild test robot [mailto:lkp@intel.com]
> Sent: Monday, 4 February, 2019 08:22 PM
> To: Pankaj Bansal <pankaj.bansal@nxp.com>
> Cc: kbuild-all@01.org; Andrew Lunn <andrew@lunn.ch>; Florian Fainelli
> <f.fainelli@gmail.com>; netdev@vger.kernel.org; Pankaj Bansal
> <pankaj.bansal@nxp.com>
> Subject: Re: [PATCH v2 2/2] netdev/phy: add MDIO bus multiplexer driven by a
> regmap
> 
> Hi Pankaj,
> 
> Thank you for the patch! Yet something to improve:
> 
> [auto build test ERROR on net/master]
> [also build test ERROR on v5.0-rc4]
> [if your patch is applied to the wrong git tree, please drop us a note to help
> improve the system]
> 
> url:
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.
> com%2F0day-ci%2Flinux%2Fcommits%2FPankaj-Bansal%2Fadd-MDIO-bus-
> multiplexer-driven-by-a-regmap-device%2F20190204-
> 213429&amp;data=02%7C01%7Cpankaj.bansal%40nxp.com%7Caabb2bdecd8a4
> 2c19f8108d68ab053d6%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7
> C636848890628820621&amp;sdata=WLP4yuLXqfoNLfrPSIWhNkfg24YdR6Ny8jb
> cUgvcrDQ%3D&amp;reserved=0
> config: sh-allmodconfig (attached as .config)
> compiler: sh4-linux-gnu-gcc (Debian 8.2.0-11) 8.2.0
> reproduce:
>         wget
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fraw.git
> hubusercontent.com%2Fintel%2Flkp-
> tests%2Fmaster%2Fsbin%2Fmake.cross&amp;data=02%7C01%7Cpankaj.bansal
> %40nxp.com%7Caabb2bdecd8a42c19f8108d68ab053d6%7C686ea1d3bc2b4c6f
> a92cd99c5c301635%7C0%7C0%7C636848890628820621&amp;sdata=pGqb5xq
> RsWH6fXd8NWLUKX86qQ0ZO8OOy8nj9rckqV8%3D&amp;reserved=0 -O
> ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         GCC_VERSION=8.2.0 make.cross ARCH=sh
> 
> All errors (new ones prefixed by >>):
> 
> >> drivers/net/phy/mdio-mux-regmap.c:72:5: error: redefinition of
> 'mdio_mux_regmap_init'
>     int mdio_mux_regmap_init(struct device *dev,
>         ^~~~~~~~~~~~~~~~~~~~
>    In file included from drivers/net/phy/mdio-mux-regmap.c:18:
>    include/linux/mdio-mux.h:53:19: note: previous definition of
> 'mdio_mux_regmap_init' was here
>     static inline int mdio_mux_regmap_init(struct device *dev,
>                       ^~~~~~~~~~~~~~~~~~~~
> >> drivers/net/phy/mdio-mux-regmap.c:158:5: error: redefinition of
> 'mdio_mux_regmap_uninit'
>     int mdio_mux_regmap_uninit(void *data)
>         ^~~~~~~~~~~~~~~~~~~~~~
>    In file included from drivers/net/phy/mdio-mux-regmap.c:18:
>    include/linux/mdio-mux.h:60:19: note: previous definition of
> 'mdio_mux_regmap_uninit' was here
>     static inline int mdio_mux_regmap_uninit(void *data)
>                       ^~~~~~~~~~~~~~~~~~~~~~
> 
> vim +/mdio_mux_regmap_init +72 drivers/net/phy/mdio-mux-regmap.c
> 
>     62
>     63	/**
>     64	 * mdio_mux_regmap_init - control MDIO bus muxing using regmap
> constructs.
>     65	 * @dev: device with which regmap construct is associated.
>     66	 * @mux_node: mdio bus mux node that contains parent mdio bus
> phandle.
>     67	 *	      This node also contains sub nodes, where each subnode
> denotes
>     68	 *	      a child mdio bus. All the child mdio buses are muxed, i.e. at a
>     69	 *	      time only one of the child mdio buses can be used.
>     70	 * @data: to store the address of data allocated by this function
>     71	 */
>   > 72	int mdio_mux_regmap_init(struct device *dev,
>     73				 struct device_node *mux_node,
>     74				 void **data)
>     75	{
>     76		struct device_node *child;
>     77		struct mdio_mux_regmap_state *s;
>     78		int ret;
>     79		u32 val;
>     80
>     81		dev_dbg(dev, "probing node %pOF\n", mux_node);
>     82
>     83		s = devm_kzalloc(dev, sizeof(*s), GFP_KERNEL);
>     84		if (!s)
>     85			return -ENOMEM;
>     86
>     87		s->regmap = dev_get_regmap(dev, NULL);
>     88		if (IS_ERR(s->regmap)) {
>     89			dev_err(dev, "Failed to get parent regmap\n");
>     90			return PTR_ERR(s->regmap);
>     91		}
>     92
>     93		ret = of_property_read_u32(mux_node, "reg", &s->mux_reg);
>     94		if (ret) {
>     95			dev_err(dev, "missing or invalid reg property\n");
>     96			return -ENODEV;
>     97		}
>     98
>     99		/* Test Register read write */
>    100		ret = regmap_read(s->regmap, s->mux_reg, &val);
>    101		if (ret) {
>    102			dev_err(dev, "error while reading reg\n");
>    103			return ret;
>    104		}
>    105
>    106		ret = regmap_write(s->regmap, s->mux_reg, val);
>    107		if (ret) {
>    108			dev_err(dev, "error while writing reg\n");
>    109			return ret;
>    110		}
>    111
>    112		ret = of_property_read_u32(mux_node, "mux-mask", &s-
> >mask);
>    113		if (ret) {
>    114			dev_err(dev, "missing or invalid mux-mask property\n");
>    115			return -ENODEV;
>    116		}
>    117
>    118		/* Verify that the 'reg' property of each child MDIO bus does
> not
>    119		 * set any bits outside of the 'mask'.
>    120		 */
>    121		for_each_available_child_of_node(mux_node, child) {
>    122			ret = of_property_read_u32(child, "reg", &val);
>    123			if (ret) {
>    124				dev_err(dev, "%pOF is missing a 'reg'
> property\n",
>    125					child);
>    126				of_node_put(child);
>    127				return -ENODEV;
>    128			}
>    129			if (val & ~s->mask) {
>    130				dev_err(dev,
>    131					"%pOF has a 'reg' value with unmasked
> bits\n",
>    132					child);
>    133				of_node_put(child);
>    134				return -ENODEV;
>    135			}
>    136		}
>    137
>    138		ret = mdio_mux_init(dev, mux_node,
> mdio_mux_regmap_switch_fn,
>    139				    &s->mux_handle, s, NULL);
>    140		if (ret) {
>    141			if (ret != -EPROBE_DEFER)
>    142				dev_err(dev, "failed to register mdio-mux
> bus %pOF\n",
>    143					mux_node);
>    144			return ret;
>    145		}
>    146
>    147		*data = s;
>    148
>    149		return 0;
>    150	}
>    151	EXPORT_SYMBOL_GPL(mdio_mux_regmap_init);
>    152
>    153	/**
>    154	 * mdio_mux_regmap_uninit - relinquish the control of MDIO bus
> muxing using
>    155	 *			    regmap constructs.
>    156	 * @data: address of data allocated by mdio_mux_regmap_init
>    157	 */
>  > 158	int mdio_mux_regmap_uninit(void *data)
>    159	{
>    160		struct mdio_mux_regmap_state *s = data;
>    161
>    162		mdio_mux_uninit(s->mux_handle);
>    163
>    164		return 0;
>    165	}
>    166	EXPORT_SYMBOL_GPL(mdio_mux_regmap_uninit);
>    167
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.01
> .org%2Fpipermail%2Fkbuild-
> all&amp;data=02%7C01%7Cpankaj.bansal%40nxp.com%7Caabb2bdecd8a42c19
> f8108d68ab053d6%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C636
> 848890628820621&amp;sdata=P7RrlnHYStMpoDpwIDMmlRiDTCemyEE3bxuUrq
> d0uxY%3D&amp;reserved=0                   Intel Corporation
diff mbox series

Patch

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3d187cd50eb0..93ef2505caba 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -87,6 +87,20 @@  config MDIO_BUS_MUX_MMIOREG
 
 	  Currently, only 8/16/32 bits registers are supported.
 
+config MDIO_BUS_MUX_REGMAP
+	tristate "regmap device controlled MDIO bus multiplexers"
+	depends on OF_MDIO && REGMAP
+	select MDIO_BUS_MUX
+	help
+	  This module provides a driver for MDIO bus multiplexers that
+	  are controlled via a regmap device, like an FPGA connected to i2c bus
+	  or spi bus or memory mapped FPGA.
+	  The multiplexer connects one of several child MDIO busses to a
+	  parent bus.  Child bus selection is under the control of one of
+	  the FPGA's registers.
+
+	  Currently, only 32 bits registers are supported.
+
 config MDIO_CAVIUM
 	tristate
 
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 5805c0b7d60e..0827a700eb31 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -26,6 +26,7 @@  obj-$(CONFIG_MDIO_BCM_IPROC)	+= mdio-bcm-iproc.o
 obj-$(CONFIG_MDIO_BCM_UNIMAC)	+= mdio-bcm-unimac.o
 obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
 obj-$(CONFIG_MDIO_BUS_MUX)	+= mdio-mux.o
+obj-$(CONFIG_MDIO_BUS_MUX_REGMAP)	+= mdio-mux-regmap.o
 obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC)	+= mdio-mux-bcm-iproc.o
 obj-$(CONFIG_MDIO_BUS_MUX_GPIO)	+= mdio-mux-gpio.o
 obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
diff --git a/drivers/net/phy/mdio-mux-regmap.c b/drivers/net/phy/mdio-mux-regmap.c
new file mode 100644
index 000000000000..f2cb3cad1d9b
--- /dev/null
+++ b/drivers/net/phy/mdio-mux-regmap.c
@@ -0,0 +1,171 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+
+/* Simple regmap based MDIO MUX driver
+ *
+ * Copyright 2018-2019 NXP
+ *
+ * Based on mdio-mux-mmioreg.c by Timur Tabi
+ *
+ * Author:
+ *     Pankaj Bansal <pankaj.bansal@nxp.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/mdio-mux.h>
+#include <linux/regmap.h>
+
+struct mdio_mux_regmap_state {
+	void		*mux_handle;
+	struct device	*dev;
+	struct regmap	*regmap;
+	u32		mux_reg;
+	u32		mask;
+};
+
+/**
+ * mdio_mux_regmap_switch_fn - This function is called by the mdio-mux layer
+ *			       when it thinks the mdio bus multiplexer needs
+ *			       to switch.
+ * @current_child:  current value of the mux register (masked via s->mask).
+ * @desired_child: value of the 'reg' property of the target child MDIO node.
+ * @data: Private data used by this switch_fn passed to mdio_mux_init function
+ *	  via mdio_mux_init(.., .., .., .., data, ..).
+ *
+ * The first time this function is called, current_child == -1.
+ * If current_child == desired_child, then the mux is already set to the
+ * correct bus.
+ */
+static int mdio_mux_regmap_switch_fn(int current_child, int desired_child,
+				     void *data)
+{
+	struct mdio_mux_regmap_state *s = data;
+	bool change;
+	int ret;
+
+	ret = regmap_update_bits_check(s->regmap,
+				       s->mux_reg,
+				       s->mask,
+				       desired_child,
+				       &change);
+
+	if (ret)
+		return ret;
+	if (change)
+		dev_dbg(s->dev, "%s %d -> %d\n", __func__, current_child,
+			desired_child);
+	return ret;
+}
+
+/**
+ * mdio_mux_regmap_init - control MDIO bus muxing using regmap constructs.
+ * @dev: device with which regmap construct is associated.
+ * @mux_node: mdio bus mux node that contains parent mdio bus phandle.
+ *	      This node also contains sub nodes, where each subnode denotes
+ *	      a child mdio bus. All the child mdio buses are muxed, i.e. at a
+ *	      time only one of the child mdio buses can be used.
+ * @data: to store the address of data allocated by this function
+ */
+int mdio_mux_regmap_init(struct device *dev,
+			 struct device_node *mux_node,
+			 void **data)
+{
+	struct device_node *child;
+	struct mdio_mux_regmap_state *s;
+	int ret;
+	u32 val;
+
+	dev_dbg(dev, "probing node %pOF\n", mux_node);
+
+	s = devm_kzalloc(dev, sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	s->regmap = dev_get_regmap(dev, NULL);
+	if (IS_ERR(s->regmap)) {
+		dev_err(dev, "Failed to get parent regmap\n");
+		return PTR_ERR(s->regmap);
+	}
+
+	ret = of_property_read_u32(mux_node, "reg", &s->mux_reg);
+	if (ret) {
+		dev_err(dev, "missing or invalid reg property\n");
+		return -ENODEV;
+	}
+
+	/* Test Register read write */
+	ret = regmap_read(s->regmap, s->mux_reg, &val);
+	if (ret) {
+		dev_err(dev, "error while reading reg\n");
+		return ret;
+	}
+
+	ret = regmap_write(s->regmap, s->mux_reg, val);
+	if (ret) {
+		dev_err(dev, "error while writing reg\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(mux_node, "mux-mask", &s->mask);
+	if (ret) {
+		dev_err(dev, "missing or invalid mux-mask property\n");
+		return -ENODEV;
+	}
+
+	/* Verify that the 'reg' property of each child MDIO bus does not
+	 * set any bits outside of the 'mask'.
+	 */
+	for_each_available_child_of_node(mux_node, child) {
+		ret = of_property_read_u32(child, "reg", &val);
+		if (ret) {
+			dev_err(dev, "%pOF is missing a 'reg' property\n",
+				child);
+			of_node_put(child);
+			return -ENODEV;
+		}
+		if (val & ~s->mask) {
+			dev_err(dev,
+				"%pOF has a 'reg' value with unmasked bits\n",
+				child);
+			of_node_put(child);
+			return -ENODEV;
+		}
+	}
+
+	ret = mdio_mux_init(dev, mux_node, mdio_mux_regmap_switch_fn,
+			    &s->mux_handle, s, NULL);
+	if (ret) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to register mdio-mux bus %pOF\n",
+				mux_node);
+		return ret;
+	}
+
+	*data = s;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mdio_mux_regmap_init);
+
+/**
+ * mdio_mux_regmap_uninit - relinquish the control of MDIO bus muxing using
+ *			    regmap constructs.
+ * @data: address of data allocated by mdio_mux_regmap_init
+ */
+int mdio_mux_regmap_uninit(void *data)
+{
+	struct mdio_mux_regmap_state *s = data;
+
+	mdio_mux_uninit(s->mux_handle);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mdio_mux_regmap_uninit);
+
+MODULE_AUTHOR("Pankaj Bansal <pankaj.bansal@nxp.com>");
+MODULE_DESCRIPTION("regmap based MDIO MUX driver");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/mdio-mux.h b/include/linux/mdio-mux.h
index a5d58f221939..fb715d56999b 100644
--- a/include/linux/mdio-mux.h
+++ b/include/linux/mdio-mux.h
@@ -29,4 +29,38 @@  int mdio_mux_init(struct device *dev,
 
 void mdio_mux_uninit(void *mux_handle);
 
+#ifdef CONFIG_MDIO_BUS_MUX_REGMAP
+/**
+ * mdio_mux_regmap_init - control MDIO bus muxing using regmap constructs.
+ * @dev: device with which regmap construct is associated.
+ * @mux_node: mdio bus mux node that contains parent mdio bus phandle.
+ *	      This node also contains sub nodes, where each subnode denotes
+ *	      a child mdio bus. All the child mdio buses are muxed, i.e. at a
+ *	      time only one of the child mdio buses can be used.
+ * @data: to store the address of data allocated by this function
+ */
+int mdio_mux_regmap_init(struct device *dev,
+			 struct device_node *mux_node,
+			 void **data);
+
+/**
+ * mdio_mux_regmap_uninit - relinquish the control of MDIO bus muxing using
+ *			    regmap constructs.
+ * @data: address of data allocated by mdio_mux_regmap_init
+ */
+int mdio_mux_regmap_uninit(void *data);
+#else /* CONFIG_MDIO_BUS_MUX_REGMAP */
+static inline int mdio_mux_regmap_init(struct device *dev,
+				       struct device_node *mux_node,
+				       void **data)
+{
+	return -ENODEV;
+}
+
+static inline int mdio_mux_regmap_uninit(void *data)
+{
+	return 0;
+}
+#endif /* CONFIG_MDIO_BUS_MUX_REGMAP */
+
 #endif /* __LINUX_MDIO_MUX_H */