diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index d4a3a31..1b51b1a 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -107,6 +107,17 @@ config OMAP_OCP2SCP
 	  OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via
 	  OCP2SCP.
 
+config SHARED_MDIO
+	bool "Shared MDIO bus"
+	depends on OF
+
+	help
+	  Shared MDIO bus implementation for SoCs having common MDIO bus
+	  for different IO subsystems. All masters should be registered to
+	  this bus via a platform driver using shared framework API.
+	  Respective drivers would be called matching a compatible string
+	  provided in master node.
+
 config SIMPLE_PM_BUS
 	bool "Simple Power-Managed Bus Driver"
 	depends on OF && PM
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index ccff007..2b6d6e9 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_SUNXI_RSB)		+= sunxi-rsb.o
 obj-$(CONFIG_SIMPLE_PM_BUS)	+= simple-pm-bus.o
 obj-$(CONFIG_UNIPHIER_SYSTEM_BUS)	+= uniphier-system-bus.o
 obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o
+obj-$(CONFIG_SHARED_MDIO)	+= shared_mdio.o
diff --git a/drivers/bus/shared_mdio.c b/drivers/bus/shared_mdio.c
new file mode 100644
index 0000000..909af73
--- /dev/null
+++ b/drivers/bus/shared_mdio.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Shared MDIO Bus
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/of_device.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/shared_mdio.h>
+#include <linux/slab.h>
+
+static DEFINE_IDA(shared_mdio_ida);
+
+static void shared_mdio_release_master(struct device *dev)
+{
+	struct shared_mdio_master *master = to_shared_mdio_master(dev);
+
+	ida_simple_remove(&shared_mdio_ida, master->dev_num);
+	kfree(master);
+}
+
+struct shared_mdio_master *shared_mdio_alloc_master(struct device *parent,
+						    struct device_node *node)
+{
+	int ret = 0;
+	struct shared_mdio_master *master;
+
+	master = kzalloc(sizeof(*master), GFP_KERNEL);
+	if (!master) {
+		ret = -ENOMEM;
+		goto fail1;
+	}
+
+	master->dev.parent = parent;
+	master->dev.bus = &shared_mdio_bus;
+	master->dev.release = shared_mdio_release_master;
+
+	device_initialize(&master->dev);
+
+	ret = ida_simple_get(&shared_mdio_ida, 0, 0, GFP_KERNEL);
+	if (ret < 0)
+		goto fail2;
+	master->dev_num = ret;
+
+	dev_set_name(&master->dev, "shared-mdio-master%d", master->dev_num);
+
+	of_node_get(node);
+	master->dev.of_node = node;
+
+	return master;
+
+fail2:
+	kfree(master);
+fail1:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(shared_mdio_alloc_master);
+
+int shared_mdio_add_master(struct shared_mdio_master *master)
+{
+	if (!master)
+		return -EINVAL;
+
+	return device_add(&master->dev);
+}
+EXPORT_SYMBOL(shared_mdio_add_master);
+
+static int shared_mdio_driver_probe(struct device *dev)
+{
+	int rc;
+	struct shared_mdio_master *master = to_shared_mdio_master(dev);
+	struct shared_mdio_driver *drv = to_shared_mdio_driver(dev->driver);
+
+	if (!drv->probe)
+		return -ENODEV;
+
+	rc = drv->probe(master);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int shared_mdio_driver_remove(struct device *dev)
+{
+	struct shared_mdio_driver *drv = to_shared_mdio_driver(dev->driver);
+
+	if (drv->remove)
+		return drv->remove(to_shared_mdio_master(dev));
+
+	return 0;
+}
+
+static void shared_mdio_driver_shutdown(struct device *dev)
+{
+	struct shared_mdio_driver *drv = to_shared_mdio_driver(dev->driver);
+
+	if (drv->shutdown)
+		drv->shutdown(to_shared_mdio_master(dev));
+}
+
+int __shared_mdio_register_driver(struct shared_mdio_driver *drv,
+				  struct module *owner)
+{
+	int rc;
+
+	drv->driver.bus = &shared_mdio_bus;
+	drv->driver.owner = owner;
+	drv->driver.probe = shared_mdio_driver_probe;
+	drv->driver.remove = shared_mdio_driver_remove;
+	drv->driver.shutdown = shared_mdio_driver_shutdown;
+
+	rc = driver_register(&drv->driver);
+	if (rc) {
+		pr_err("driver_register() failed for %s, error: %d\n",
+			drv->driver.name, rc);
+		return rc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(__shared_mdio_register_driver);
+
+static int shared_mdio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	/* Attempt an OF style match */
+	if (of_driver_match_device(dev, drv))
+		return 1;
+
+	return 0;
+}
+
+struct bus_type shared_mdio_bus = {
+	.name	= "shared_mdio",
+	.match	= shared_mdio_bus_match,
+};
+EXPORT_SYMBOL(shared_mdio_bus);
+
+static int __init shared_mdio_init(void)
+{
+	int rc;
+
+	rc = bus_register(&shared_mdio_bus);
+	if (rc) {
+		pr_err("Failed to register shared_mdio bus, error: %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void __exit shared_mdio_exit(void)
+{
+	bus_unregister(&shared_mdio_bus);
+
+	ida_destroy(&shared_mdio_ida);
+}
+
+subsys_initcall(shared_mdio_init);
+module_exit(shared_mdio_exit);
+
+MODULE_DESCRIPTION("Shared MDIO Bus");
+MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>");
+MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/shared_mdio.h b/include/linux/shared_mdio.h
new file mode 100644
index 0000000..db6e442
--- /dev/null
+++ b/include/linux/shared_mdio.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SHARED_MDIO_H__
+#define __SHARED_MDIO_H__
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+extern struct bus_type shared_mdio_bus;
+
+/*
+ * This structure represets the mdio master that control the MDIO bus
+ * to access the phy attached on it.
+ * @dev Underlying device for mdio master
+ * @dev_num Unique device number of mdio master
+ * @mdio_write Write callback of mdio master
+ * @mdio_read Read callback for mdio master
+ */
+struct shared_mdio_master {
+	struct device dev;
+	int dev_num;
+	void *priv;
+
+	int (*mdio_write)(struct shared_mdio_master *master,
+				u16 phyid, u16 reg, u16 data);
+	int (*mdio_read)(struct shared_mdio_master *master, u16 phyid, u16 reg);
+};
+#define to_shared_mdio_master(d)		\
+			container_of(d, struct shared_mdio_master, dev)
+
+struct shared_mdio_driver {
+	int (*probe)(struct shared_mdio_master *master);
+	int (*remove)(struct shared_mdio_master *master);
+	void (*shutdown)(struct shared_mdio_master *master);
+
+	struct device_driver driver;
+};
+#define to_shared_mdio_driver(d)	\
+			container_of(d, struct shared_mdio_driver, driver)
+
+struct shared_mdio_master *shared_mdio_alloc_master(struct device *parent,
+						    struct device_node *node);
+
+int shared_mdio_add_master(struct shared_mdio_master *master);
+
+static inline void shared_mdio_remove_master(struct shared_mdio_master *master)
+{
+		device_unregister(&master->dev);
+}
+
+int __shared_mdio_register_driver(struct shared_mdio_driver *drv,
+				  struct module *owner);
+
+/* use a define to avoid include chaining to get THIS_MODULE & friends */
+#define shared_mdio_register_driver(drv) \
+	__shared_mdio_register_driver(drv, THIS_MODULE)
+
+static inline void shared_mdio_unregister_driver(
+					struct shared_mdio_driver *drv)
+{
+		driver_unregister(&drv->driver);
+}
+
+/**
+ * module_shared_mdio_driver() - Helper macro for registering a shared_mdio
+ * driver
+ * @__shared_mdio_driver: shared_mdio_driver struct
+ *
+ * Helper macro for shared mdio drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module
+ * may only use this macro once, and calling it replaces module_init()
+ * and module_exit().
+ */
+#define module_shared_mdio_driver(__shared_mdio_driver) \
+	module_driver(__shared_mdio_driver, shared_mdio_register_driver, \
+		       shared_mdio_unregister_driver)
+
+
+static inline int shared_mdio_write(struct shared_mdio_master *master,
+						u16 phy, u16 reg, u16 data)
+{
+	if (master->mdio_write)
+		return master->mdio_write(master, phy, reg, data);
+
+	return -ENOTSUPP;
+}
+
+static inline int shared_mdio_read(struct shared_mdio_master *master,
+							u16 phy_id, u16 reg)
+{
+	if (master->mdio_read)
+		return master->mdio_read(master, phy_id, reg);
+
+	return -ENOTSUPP;
+}
+
+/*
+ * Use the following functions to manipulate shared_mdio's per-master
+ * driver-specific data.
+ */
+static inline void *shared_mdio_get_drvdata(struct shared_mdio_master *master)
+{
+	return dev_get_drvdata(&master->dev);
+}
+
+static inline void shared_mdio_set_drvdata(struct shared_mdio_master *master,
+					   void *data)
+{
+	dev_set_drvdata(&master->dev, data);
+}
+
+#endif
