diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c
index 29fcc73..55eb13b 100644
--- a/drivers/remoteproc/rproc_srm_core.c
+++ b/drivers/remoteproc/rproc_srm_core.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
- * Author: Fabien Dessenne <fabien.dessenne@st.com>.
- *
- * License type: GPLv2
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
  */
 
 #include <linux/component.h>
@@ -22,6 +9,9 @@
 #include <linux/module.h>
 #include <linux/of_platform.h>
 #include <linux/remoteproc.h>
+#include <linux/rpmsg.h>
+
+#include "rproc_srm_core.h"
 
 #define BIND_TIMEOUT 10000
 
@@ -31,10 +21,98 @@ struct rproc_srm_core {
 	int bind_status;
 	atomic_t prepared;
 	struct rproc_subdev subdev;
+	struct rpmsg_driver rpdrv;
+	struct blocking_notifier_head notifier;
 };
 
 #define to_rproc_srm_core(s) container_of(s, struct rproc_srm_core, subdev)
 
+static struct rproc_srm_core *rpmsg_srm_to_core(struct rpmsg_device *rpdev)
+{
+	struct rpmsg_driver *rpdrv;
+	struct rproc_srm_core *core;
+
+	rpdrv = container_of(rpdev->dev.driver, struct rpmsg_driver, drv);
+	core = container_of(rpdrv, struct rproc_srm_core, rpdrv);
+
+	return core;
+}
+
+int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg)
+{
+	int ret;
+
+	ret = rpmsg_send(ept, (void *)msg, sizeof(*msg));
+	if (ret)
+		dev_err(&ept->rpdev->dev, "rpmsg_send failed: %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(rpmsg_srm_send);
+
+static int rpmsg_srm_cb(struct rpmsg_device *rpdev, void *data, int len,
+			void *priv, u32 src)
+{
+	struct rproc_srm_core *core = rpmsg_srm_to_core(rpdev);
+	struct rpmsg_srm_msg_desc desc;
+	int ret;
+
+	desc.ept = rpdev->ept;
+	desc.msg = data;
+
+	ret = blocking_notifier_call_chain(&core->notifier, 0, &desc);
+
+	if (!(ret & NOTIFY_STOP_MASK)) {
+		dev_warn(&rpdev->dev, "unknown device\n");
+		desc.msg->message_type = RPROC_SRM_MSG_ERROR;
+		rpmsg_srm_send(desc.ept, desc.msg);
+	}
+
+	return 0;
+}
+
+static int rpmsg_srm_probe(struct rpmsg_device *rpdev)
+{
+	/* Note : the probe ops is mandatory */
+	dev_dbg(&rpdev->dev, "%s\n", __func__);
+
+	return 0;
+}
+
+static void rpmsg_srm_remove(struct rpmsg_device *rpdev)
+{
+	/* Note : the remove ops is mandatory */
+	dev_dbg(&rpdev->dev, "%s\n", __func__);
+}
+
+static struct rpmsg_device_id rpmsg_srm_id_table[] = {
+	{ .name	= "rproc-srm" },
+	{ },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_srm_id_table);
+
+static struct rpmsg_driver rpmsg_srm_drv = {
+	.drv.name	= "rpmsg_srm",
+	.id_table	= rpmsg_srm_id_table,
+	.probe		= rpmsg_srm_probe,
+	.callback	= rpmsg_srm_cb,
+	.remove		= rpmsg_srm_remove,
+};
+
+int rproc_srm_core_register_notifier(struct rproc_srm_core *core,
+				     struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&core->notifier, nb);
+}
+EXPORT_SYMBOL(rproc_srm_core_register_notifier);
+
+int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core,
+				       struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&core->notifier, nb);
+}
+EXPORT_SYMBOL(rproc_srm_core_unregister_notifier);
+
 static int compare_of(struct device *dev, void *data)
 {
 	return dev->of_node == data;
@@ -115,6 +193,15 @@ static int rproc_srm_core_prepare(struct rproc_subdev *subdev)
 		dev_err(dev, "failed to bind\n");
 		goto master;
 	}
+
+	/* Register rpmsg driver for dynamic management */
+	rproc_srm_core->rpdrv = rpmsg_srm_drv;
+	ret = register_rpmsg_driver(&rproc_srm_core->rpdrv);
+	if (ret) {
+		dev_err(dev, "failed to register rpmsg drv\n");
+		goto master;
+	}
+
 done:
 	atomic_inc(&rproc_srm_core->prepared);
 
@@ -127,7 +214,7 @@ static int rproc_srm_core_prepare(struct rproc_subdev *subdev)
 	return ret;
 }
 
-static void rproc_srm_core_do_unprepare(struct rproc_subdev *subdev)
+static void rproc_srm_core_unprepare(struct rproc_subdev *subdev)
 {
 	struct rproc_srm_core *rproc_srm_core = to_rproc_srm_core(subdev);
 	struct device *dev = rproc_srm_core->dev;
@@ -136,6 +223,8 @@ static void rproc_srm_core_do_unprepare(struct rproc_subdev *subdev)
 
 	atomic_dec(&rproc_srm_core->prepared);
 
+	unregister_rpmsg_driver(&rproc_srm_core->rpdrv);
+
 	component_master_del(dev, &srm_comp_ops);
 	devm_of_platform_depopulate(dev);
 }
@@ -154,6 +243,7 @@ static int rproc_srm_core_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	rproc_srm_core->dev = dev;
+	BLOCKING_INIT_NOTIFIER_HEAD(&rproc_srm_core->notifier);
 
 	/* Register rproc subdevice with (un)prepare ops */
 	rproc_srm_core->subdev.prepare = rproc_srm_core_prepare;
diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h
new file mode 100644
index 0000000..7fe8a23
--- /dev/null
+++ b/drivers/remoteproc/rproc_srm_core.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
+ */
+
+#ifndef _RPROC_SRM_CORE_H_
+#define _RPROC_SRM_CORE_H_
+
+/**
+ * Message type used in resource manager rpmsg:
+ *  RPROC_SRM_MSG_GETCONFIG:    Request to get the configuration of a resource
+ *  RPROC_SRM_MSG_SETCONFIG:    Request to set the configuration of a resource
+ *  RPROC_SRM_MSG_ERROR:        Error when processing a request
+ */
+#define RPROC_SRM_MSG_GETCONFIG 0x00
+#define RPROC_SRM_MSG_SETCONFIG 0x01
+#define RPROC_SRM_MSG_ERROR     0xFF
+
+/**
+ * Resource type used in resource manager rpmsg:
+ *  RPROC_SRM_RSC_CLOCK:        clock resource
+ *  RPROC_SRM_RSC_PIN:          pin resource
+ *  RPROC_SRM_RSC_REGU:         regulator resource
+ */
+#define RPROC_SRM_RSC_CLOCK     0x00
+#define RPROC_SRM_RSC_PIN       0x01
+#define RPROC_SRM_RSC_REGU      0x02
+
+/**
+ * struct clock_cfg - clock configuration used in resource manager rpmsg
+ * @index:      clock index
+ * @name:       clock name
+ * @enable:     clock enable/disable request (in SetConfig message) or current
+ *              status (in GetConfig message)
+ * @rate:       clock rate request (in SetConfig message) or current status (in
+ *              GetConfig message)
+ */
+struct clock_cfg {
+	u32 index;
+	u8 name[16];
+	u32 enable;
+	u32 rate;
+};
+
+/**
+ * struct regu_cfg - regu configuration used in resource manager rpmsg
+ * @index:      regulator index
+ * @name:       regulator name
+ * @enable:     regulator enable/disable request (in SetConfig message) or
+ *              current status (in GetConfig message)
+ * @curr_voltage_mv: current regulator voltage in mV (meaningful in
+ *                   SetConfig message)
+ * @min_voltage_mv:  regulator min voltage request in mV (meaningful in
+ *                   SetConfig message)
+ * @max_voltage_mv:  regulator max voltage request in mV (meaningful in
+ *                   SetConfig message)
+ */
+struct regu_cfg {
+	u32 index;
+	u8 name[16];
+	u32 enable;
+	u32 curr_voltage_mv;
+	u32 min_voltage_mv;
+	u32 max_voltage_mv;
+};
+
+/**
+ * struct pin_cfg - pin configuration used in resource manager rpmsg
+ * @name:       current pin configuration name (meaningful in GetConfig message)
+ */
+struct pin_cfg {
+	u8 name[16];
+};
+
+/**
+ * struct rpmsg_srm_msg - message structure used between processors to
+ *                        dynamically update resources configuration
+ * @message_type: type of the message: see RPROC_SRM_MSG*
+ * @device_id:  an identifier specifying the device owning the resources.
+ *              This is implementation dependent. As example it may be the
+ *              device name or the device address.
+ * @rsc_type:   the type of the resource for which the configuration applies:
+ *              see RPROC_SRM_RSC*
+ * @clock_cfg:  clock config - relevant if &rsc_type is RPROC_SRM_RSC_CLOCK
+ * @regu_cfg:   regulator config - relevant if &rsc_type is RPROC_SRM_RSC_REGU
+ * @pin_cfg:    pin config - relevant if &rsc_type is RPROC_SRM_RSC_PIN
+ */
+struct rpmsg_srm_msg {
+	u32 message_type;
+	u8 device_id[32];
+	u32 rsc_type;
+	union {
+		struct clock_cfg clock_cfg;
+		struct regu_cfg regu_cfg;
+		struct pin_cfg pin_cfg;
+	};
+};
+
+struct rpmsg_srm_msg_desc {
+	struct rpmsg_endpoint *ept;
+	struct rpmsg_srm_msg *msg;
+};
+
+struct rproc_srm_core;
+
+int rproc_srm_core_register_notifier(struct rproc_srm_core *core,
+				     struct notifier_block *nb);
+int rproc_srm_core_unregister_notifier(struct rproc_srm_core *core,
+				       struct notifier_block *nb);
+int rpmsg_srm_send(struct rpmsg_endpoint *ept, struct rpmsg_srm_msg *msg);
+
+#endif
diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c
index 4b2e6ac..b3ed733 100644
--- a/drivers/remoteproc/rproc_srm_dev.c
+++ b/drivers/remoteproc/rproc_srm_dev.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
- * Author: Fabien Dessenne <fabien.dessenne@st.com>.
- *
- * License type: GPLv2
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
  */
 
 #include <linux/clk.h>
@@ -29,7 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#define SUPPLY_SUFFIX   "-supply"
+#include "rproc_srm_core.h"
 
 struct rproc_srm_clk_info {
 	struct list_head list;
@@ -43,6 +30,7 @@ struct rproc_srm_pin_info {
 	struct list_head list;
 	unsigned int index;
 	char *name;
+	bool selected;
 };
 
 struct rproc_srm_regu_info {
@@ -63,6 +51,8 @@ struct rproc_srm_irq_info {
 
 struct rproc_srm_dev {
 	struct device *dev;
+	struct rproc_srm_core *core;
+	struct notifier_block nb;
 	struct pinctrl *pctrl;
 
 	struct list_head clk_list_head;
@@ -71,17 +61,16 @@ struct rproc_srm_dev {
 	struct list_head irq_list_head;
 };
 
-/* irqs */
-static void rproc_srm_dev_put_irqs(struct rproc_srm_dev *rproc_srm_dev)
+/* Irqs */
+static void rproc_srm_dev_irqs_put(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
-	struct rproc_srm_irq_info *info, *tmp;
-	struct list_head *irq_head = &rproc_srm_dev->irq_list_head;
+	struct rproc_srm_irq_info *i, *tmp;
 
-	list_for_each_entry_safe(info, tmp, irq_head, list) {
-		devm_free_irq(dev, info->irq, NULL);
-		dev_dbg(dev, "Put irq %d (%s)\n", info->irq, info->name);
-		list_del(&info->list);
+	list_for_each_entry_safe(i, tmp, &rproc_srm_dev->irq_list_head, list) {
+		devm_free_irq(dev, i->irq, NULL);
+		dev_dbg(dev, "Put irq %d (%s)\n", i->irq, i->name);
+		list_del(&i->list);
 	}
 }
 
@@ -91,13 +80,12 @@ static irqreturn_t rproc_srm_dev_irq_handler(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static int rproc_srm_dev_get_irqs(struct rproc_srm_dev *rproc_srm_dev)
+static int rproc_srm_dev_irqs_get(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct device_node *np = dev->of_node;
 	struct rproc_srm_irq_info *info;
-	struct list_head *irq_head = &rproc_srm_dev->irq_list_head;
 	const char *name;
 	int nr, ret, irq;
 	unsigned int i;
@@ -141,87 +129,166 @@ static int rproc_srm_dev_get_irqs(struct rproc_srm_dev *rproc_srm_dev)
 		 */
 		irq_set_status_flags(info->irq, IRQ_DISABLE_UNLAZY);
 
+		/* Note: "interrupt-names" is optional */
 		if (!of_property_read_string_index(np, "interrupt-names", i,
 						   &name))
 			info->name = devm_kstrdup(dev, name, GFP_KERNEL);
+		else
+			info->name = devm_kstrdup(dev, "", GFP_KERNEL);
 
 		info->index = i;
 
-		list_add_tail(&info->list, irq_head);
+		list_add_tail(&info->list, &rproc_srm_dev->irq_list_head);
 		dev_dbg(dev, "Got irq %d (%s)\n", info->irq, info->name);
 	}
 
 	return 0;
 
 err:
-	rproc_srm_dev_put_irqs(rproc_srm_dev);
+	rproc_srm_dev_irqs_put(rproc_srm_dev);
 
 	return ret;
 }
 
 /* Clocks */
-static void rproc_srm_dev_deconfig_clocks(struct rproc_srm_dev *rproc_srm_dev)
+static void rproc_srm_dev_clocks_unsetup(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct rproc_srm_clk_info *c;
-	struct list_head *clk_head = &rproc_srm_dev->clk_list_head;
 
-	list_for_each_entry(c, clk_head, list) {
+	list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) {
 		if (!c->enabled)
 			continue;
 
 		clk_disable_unprepare(c->clk);
 		c->enabled = false;
-		dev_dbg(rproc_srm_dev->dev, "clk %d (%s) deconfigured\n",
+		dev_dbg(rproc_srm_dev->dev, "clk %d (%s) unsetup\n",
 			c->index, c->name);
 	}
 }
 
-static int rproc_srm_dev_config_clocks(struct rproc_srm_dev *rproc_srm_dev)
+static int rproc_srm_dev_clocks_setup(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct rproc_srm_clk_info *c;
-	struct list_head *clk_head = &rproc_srm_dev->clk_list_head;
 	int ret;
 
-	/* Note: not only configuring, but also enabling */
-
-	list_for_each_entry(c, clk_head, list) {
+	/* Prepare and enable clocks */
+	list_for_each_entry(c, &rproc_srm_dev->clk_list_head, list) {
 		if (c->enabled)
 			continue;
 
 		ret = clk_prepare_enable(c->clk);
 		if (ret) {
-			dev_err(rproc_srm_dev->dev, "clk %d (%s) cfg failed\n",
+			dev_err(rproc_srm_dev->dev,
+				"clk %d (%s) enable failed\n",
 				c->index, c->name);
-			rproc_srm_dev_deconfig_clocks(rproc_srm_dev);
+			rproc_srm_dev_clocks_unsetup(rproc_srm_dev);
 			return ret;
 		}
 		c->enabled = true;
-		dev_dbg(rproc_srm_dev->dev, "clk %d (%s) configured\n",
+		dev_dbg(rproc_srm_dev->dev, "clk %d (%s) enabled\n",
 			c->index, c->name);
 	}
 
 	return 0;
 }
 
-static void rproc_srm_dev_put_clocks(struct rproc_srm_dev *rproc_srm_dev)
+static struct rproc_srm_clk_info *rproc_srm_dev_clock_find(
+		struct rproc_srm_dev *rproc_srm_dev, struct clock_cfg *cfg)
+{
+	struct rproc_srm_clk_info *ci;
+
+	/* Search by index (if valid value) otherwise search by name */
+	list_for_each_entry(ci, &rproc_srm_dev->clk_list_head, list) {
+		if (cfg->index != U32_MAX) {
+			if (ci->index == cfg->index)
+				return ci;
+		} else {
+			if (!strcmp(ci->name, cfg->name))
+				return ci;
+		}
+	}
+
+	return NULL;
+}
+
+static int rproc_srm_dev_clock_set_cfg(struct rproc_srm_dev *rproc_srm_dev,
+				       struct clock_cfg *cfg)
+{
+	struct rproc_srm_clk_info *c;
+	struct device *dev = rproc_srm_dev->dev;
+	int ret;
+
+	c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg);
+
+	if (!c) {
+		dev_err(dev, "unknown clock (id %d)\n", cfg->index);
+		return -EINVAL;
+	}
+
+	if (!c->enabled && cfg->enable) {
+		ret = clk_enable(c->clk);
+		if (ret) {
+			dev_err(dev, "clk enable failed\n");
+			return ret;
+		}
+		c->enabled = true;
+		dev_dbg(dev, "clk %d (%s) enabled\n", c->index, c->name);
+	} else if (c->enabled && !cfg->enable) {
+		clk_disable(c->clk);
+		c->enabled = false;
+		dev_dbg(dev, "clk %d (%s) disabled\n", c->index, c->name);
+	}
+
+	if (cfg->rate && clk_get_rate(c->clk) != cfg->rate) {
+		ret = clk_set_rate(c->clk, cfg->rate);
+		if (ret) {
+			dev_err(dev, "clk set rate failed\n");
+			return ret;
+		}
+
+		dev_dbg(dev, "clk %d (%s) rate = %d\n", c->index, c->name,
+			cfg->rate);
+	}
+
+	return 0;
+}
+
+static int rproc_srm_dev_clock_get_cfg(struct rproc_srm_dev *rproc_srm_dev,
+				       struct clock_cfg *cfg)
+{
+	struct rproc_srm_clk_info *c;
+
+	c = rproc_srm_dev_clock_find(rproc_srm_dev, cfg);
+	if (!c) {
+		dev_err(rproc_srm_dev->dev, "unknown clock (%d)\n", cfg->index);
+		return -EINVAL;
+	}
+
+	strlcpy(cfg->name, c->name, sizeof(cfg->name));
+	cfg->index = c->index;
+	cfg->enable = c->enabled;
+	cfg->rate = (u32)clk_get_rate(c->clk);
+
+	return 0;
+}
+
+static void rproc_srm_dev_clocks_put(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
 	struct rproc_srm_clk_info *c, *tmp;
-	struct list_head *clk_head = &rproc_srm_dev->clk_list_head;
 
-	list_for_each_entry_safe(c, tmp, clk_head, list) {
+	list_for_each_entry_safe(c, tmp, &rproc_srm_dev->clk_list_head, list) {
 		clk_put(c->clk);
 		dev_dbg(dev, "put clock %d (%s)\n", c->index, c->name);
 		list_del(&c->list);
 	}
 }
 
-static int rproc_srm_dev_get_clocks(struct rproc_srm_dev *rproc_srm_dev)
+static int rproc_srm_dev_clocks_get(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
 	struct device_node *np = dev->of_node;
 	struct rproc_srm_clk_info *c;
-	struct list_head *clk_head = &rproc_srm_dev->clk_list_head;
 	const char *name;
 	int nb_c, ret;
 	unsigned int i;
@@ -248,48 +315,53 @@ static int rproc_srm_dev_get_clocks(struct rproc_srm_dev *rproc_srm_dev)
 			goto err;
 		}
 
+		/* Note: "clock-names" is optional */
 		if (!of_property_read_string_index(np, "clock-names", i,
 						   &name))
 			c->name = devm_kstrdup(dev, name, GFP_KERNEL);
+		else
+			c->name = devm_kstrdup(dev, "", GFP_KERNEL);
 
 		c->index = i;
 
-		list_add_tail(&c->list, clk_head);
+		list_add_tail(&c->list, &rproc_srm_dev->clk_list_head);
 		dev_dbg(dev, "got clock %d (%s)\n", c->index, c->name);
 	}
 
 	return 0;
 
 err:
-	rproc_srm_dev_put_clocks(rproc_srm_dev);
+	rproc_srm_dev_clocks_put(rproc_srm_dev);
 	return ret;
 }
 
 /* Regulators */
-static void rproc_srm_dev_deconfig_regus(struct rproc_srm_dev *rproc_srm_dev)
+static void rproc_srm_dev_regus_unsetup(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct rproc_srm_regu_info *r;
-	struct list_head *regu_head = &rproc_srm_dev->regu_list_head;
+	struct device *dev = rproc_srm_dev->dev;
 
-	list_for_each_entry(r, regu_head, list) {
+	list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) {
 		if (!r->enabled)
 			continue;
 
-		regulator_disable(r->regu);
+		if (regulator_disable(r->regu)) {
+			dev_warn(dev, "regu %d disabled failed\n", r->index);
+			continue;
+		}
+
 		r->enabled = false;
-		dev_dbg(rproc_srm_dev->dev, "regu %d (%s) disabled\n",
-			r->index, r->name);
+		dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name);
 	}
 }
 
-static int rproc_srm_dev_config_regus(struct rproc_srm_dev *rproc_srm_dev)
+static int rproc_srm_dev_regus_setup(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct rproc_srm_regu_info *r;
-	struct list_head *regu_head = &rproc_srm_dev->regu_list_head;
 	int ret;
 
 	/* Enable all the regulators */
-	list_for_each_entry(r, regu_head, list) {
+	list_for_each_entry(r, &rproc_srm_dev->regu_list_head, list) {
 		if (r->enabled)
 			continue;
 
@@ -297,7 +369,7 @@ static int rproc_srm_dev_config_regus(struct rproc_srm_dev *rproc_srm_dev)
 		if (ret) {
 			dev_err(rproc_srm_dev->dev, "regu %d (%s) failed\n",
 				r->index, r->name);
-			rproc_srm_dev_deconfig_regus(rproc_srm_dev);
+			rproc_srm_dev_regus_unsetup(rproc_srm_dev);
 			return ret;
 		}
 		r->enabled = true;
@@ -308,20 +380,113 @@ static int rproc_srm_dev_config_regus(struct rproc_srm_dev *rproc_srm_dev)
 	return 0;
 }
 
-static void rproc_srm_dev_put_regus(struct rproc_srm_dev *rproc_srm_dev)
+static struct rproc_srm_regu_info *rproc_srm_dev_regu_find(
+		struct rproc_srm_dev *rproc_srm_dev, struct regu_cfg *cfg)
+{
+	struct rproc_srm_regu_info *ri;
+
+	list_for_each_entry(ri, &rproc_srm_dev->regu_list_head, list) {
+		if (cfg->index != U32_MAX) {
+			if (ri->index == cfg->index)
+				return ri;
+		} else {
+			if (!strcmp(ri->name, cfg->name))
+				return ri;
+		}
+	}
+
+	return NULL;
+}
+
+static int rproc_srm_dev_regu_set_cfg(struct rproc_srm_dev *rproc_srm_dev,
+				      struct regu_cfg *cfg)
+{
+	struct rproc_srm_regu_info *r;
+	struct device *dev = rproc_srm_dev->dev;
+	int ret;
+
+	r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg);
+	if (!r) {
+		dev_err(dev, "unknown regu (%d)\n", cfg->index);
+		return -EINVAL;
+	}
+
+	if (!r->enabled && cfg->enable) {
+		ret = regulator_enable(r->regu);
+		if (ret) {
+			dev_err(dev, "regu %d enable failed\n", r->index);
+			return ret;
+		}
+		r->enabled = true;
+		dev_dbg(dev, "regu %d (%s) enabled\n", r->index, r->name);
+	} else if (r->enabled && !cfg->enable) {
+		ret = regulator_disable(r->regu);
+		if (ret) {
+			dev_err(dev, "regu %d disable failed\n", r->index);
+			return ret;
+		}
+		r->enabled = false;
+		dev_dbg(dev, "regu %d (%s) disabled\n", r->index, r->name);
+	}
+
+	if (cfg->min_voltage_mv || cfg->max_voltage_mv) {
+		ret = regulator_set_voltage(r->regu, cfg->min_voltage_mv * 1000,
+					    cfg->max_voltage_mv * 1000);
+		if (ret) {
+			dev_err(dev, "regu %d set voltage failed\n", r->index);
+			return ret;
+		}
+
+		dev_dbg(dev, "regu %d (%s) voltage = [%d - %d] mv\n", r->index,
+			r->name, cfg->min_voltage_mv, cfg->max_voltage_mv);
+	}
+
+	return 0;
+}
+
+static int rproc_srm_dev_regu_get_cfg(struct rproc_srm_dev *rproc_srm_dev,
+				      struct regu_cfg *cfg)
+{
+	struct rproc_srm_regu_info *r;
+	struct device *dev = rproc_srm_dev->dev;
+	int v;
+
+	r = rproc_srm_dev_regu_find(rproc_srm_dev, cfg);
+	if (!r) {
+		dev_err(dev, "unknown regu (%d)\n", cfg->index);
+		return -EINVAL;
+	}
+
+	strlcpy(cfg->name, r->name, sizeof(cfg->name));
+	cfg->index = r->index;
+	cfg->enable = r->enabled;
+	cfg->min_voltage_mv = 0;
+	cfg->max_voltage_mv = 0;
+
+	v = regulator_get_voltage(r->regu);
+	if (v < 0) {
+		dev_warn(dev, "cannot get %s voltage\n", r->name);
+		cfg->curr_voltage_mv = 0;
+	} else {
+		cfg->curr_voltage_mv = v / 1000;
+	}
+
+	return 0;
+}
+
+static void rproc_srm_dev_regus_put(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
 	struct rproc_srm_regu_info *r, *tmp;
-	struct list_head *regu_head = &rproc_srm_dev->regu_list_head;
 
-	list_for_each_entry_safe(r, tmp, regu_head, list) {
+	list_for_each_entry_safe(r, tmp, &rproc_srm_dev->regu_list_head, list) {
 		devm_regulator_put(r->regu);
 		dev_dbg(dev, "put regu %d (%s)\n", r->index, r->name);
 		list_del(&r->list);
 	}
 }
 
-static int rproc_srm_dev_get_regus(struct rproc_srm_dev *rproc_srm_dev)
+static int rproc_srm_dev_regus_get(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
 	struct device_node *np = dev->of_node;
@@ -329,14 +494,13 @@ static int rproc_srm_dev_get_regus(struct rproc_srm_dev *rproc_srm_dev)
 	const char *n;
 	char *name;
 	struct rproc_srm_regu_info *r;
-	struct list_head *regu_head = &rproc_srm_dev->regu_list_head;
 	int ret, nb_s = 0;
 
 	if (!np)
 		return 0;
 
 	for_each_property_of_node(np, p) {
-		n = strstr(p->name, SUPPLY_SUFFIX);
+		n = strstr(p->name, "-supply");
 		if (!n || n == p->name)
 			continue;
 
@@ -347,7 +511,7 @@ static int rproc_srm_dev_get_regus(struct rproc_srm_dev *rproc_srm_dev)
 		}
 
 		name = devm_kstrdup(dev, p->name, GFP_KERNEL);
-		name[strlen(p->name) - strlen(SUPPLY_SUFFIX)] = '\0';
+		name[strlen(p->name) - strlen("-supply")] = '\0';
 		r->name = name;
 
 		r->regu = devm_regulator_get(dev, r->name);
@@ -359,25 +523,83 @@ static int rproc_srm_dev_get_regus(struct rproc_srm_dev *rproc_srm_dev)
 
 		r->index = nb_s++;
 
-		list_add_tail(&r->list, regu_head);
+		list_add_tail(&r->list, &rproc_srm_dev->regu_list_head);
 		dev_dbg(dev, "got regu %d (%s)\n", r->index, r->name);
 	}
 
 	return 0;
 
 err_list:
-	rproc_srm_dev_put_regus(rproc_srm_dev);
+	rproc_srm_dev_regus_put(rproc_srm_dev);
 	return ret;
 }
 
 /* Pins */
-static void rproc_srm_dev_put_pins(struct rproc_srm_dev *rproc_srm_dev)
+static int rproc_srm_dev_pin_set_cfg(struct rproc_srm_dev *rproc_srm_dev,
+				     struct pin_cfg *cfg)
+{
+	struct rproc_srm_pin_info *pi, *p = NULL;
+	struct device *dev = rproc_srm_dev->dev;
+	struct pinctrl_state *state;
+	int ret;
+
+	list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) {
+		if (!strcmp(pi->name, cfg->name)) {
+			p = pi;
+			break;
+		}
+	}
+
+	if (!p) {
+		dev_err(dev, "unknown pin config (%s)\n", cfg->name);
+		return -EINVAL;
+	}
+
+	state = pinctrl_lookup_state(rproc_srm_dev->pctrl, cfg->name);
+	if (IS_ERR(state)) {
+		dev_err(dev, "cannot get pin config (%s)\n", cfg->name);
+		return -EINVAL;
+	}
+
+	ret = pinctrl_select_state(rproc_srm_dev->pctrl, state);
+	if (ret < 0) {
+		dev_err(dev, "cannot set pin config (%s)\n", cfg->name);
+		return ret;
+	}
+
+	list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) {
+		pi->selected = (pi == p);
+	}
+
+	dev_dbg(dev, "pin config (%s) selected\n", p->name);
+
+	return 0;
+}
+
+static int rproc_srm_dev_pin_get_cfg(struct rproc_srm_dev *rproc_srm_dev,
+				     struct pin_cfg *cfg)
+{
+	struct rproc_srm_pin_info *p;
+
+	list_for_each_entry(p, &rproc_srm_dev->pin_list_head, list) {
+		if (p->selected) {
+			strlcpy(cfg->name, p->name, sizeof(cfg->name));
+			return 0;
+		}
+	}
+
+	dev_warn(rproc_srm_dev->dev, "cannot find selected pin state\n");
+	strcpy(cfg->name, "");
+
+	return 0;
+}
+
+static void rproc_srm_dev_pins_put(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
 	struct rproc_srm_pin_info *p, *tmp;
-	struct list_head *pin_head = &rproc_srm_dev->pin_list_head;
 
-	list_for_each_entry_safe(p, tmp, pin_head, list) {
+	list_for_each_entry_safe(p, tmp, &rproc_srm_dev->pin_list_head, list) {
 		devm_kfree(dev, p->name);
 		devm_kfree(dev, p);
 		dev_dbg(dev, "remove pin cfg %d (%s)\n", p->index, p->name);
@@ -390,12 +612,11 @@ static void rproc_srm_dev_put_pins(struct rproc_srm_dev *rproc_srm_dev)
 	}
 }
 
-static int rproc_srm_dev_get_pins(struct rproc_srm_dev *rproc_srm_dev)
+static int rproc_srm_dev_pins_get(struct rproc_srm_dev *rproc_srm_dev)
 {
 	struct device *dev = rproc_srm_dev->dev;
 	struct device_node *np = dev->of_node;
 	struct rproc_srm_pin_info *p;
-	struct list_head *pin_head = &rproc_srm_dev->pin_list_head;
 	int ret, nb_p;
 	unsigned int i;
 	const char *name;
@@ -403,8 +624,6 @@ static int rproc_srm_dev_get_pins(struct rproc_srm_dev *rproc_srm_dev)
 	if (!np)
 		return 0;
 
-	/* Assumption here is that "default" pinctrl applied before probe */
-
 	rproc_srm_dev->pctrl = devm_pinctrl_get(dev);
 	if (IS_ERR(rproc_srm_dev->pctrl))
 		return 0;
@@ -430,20 +649,107 @@ static int rproc_srm_dev_get_pins(struct rproc_srm_dev *rproc_srm_dev)
 			goto err;
 		}
 		p->name = devm_kstrdup(dev, name, GFP_KERNEL);
+		if (!strcmp(p->name, PINCTRL_STATE_DEFAULT))
+			p->selected = true;
 
 		p->index = i;
 
-		list_add_tail(&p->list, pin_head);
+		list_add_tail(&p->list, &rproc_srm_dev->pin_list_head);
 		dev_dbg(dev, "found pin cfg %d (%s)\n", p->index, p->name);
 	}
 	return 0;
 
 err:
-	rproc_srm_dev_put_pins(rproc_srm_dev);
+	rproc_srm_dev_pins_put(rproc_srm_dev);
 	return ret;
 }
 
 /* Core */
+static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt,
+				   void *data)
+{
+	struct rproc_srm_dev *rproc_srm_dev =
+			container_of(nb, struct rproc_srm_dev, nb);
+	struct device *dev = rproc_srm_dev->dev;
+	struct rpmsg_srm_msg_desc *desc;
+	struct rpmsg_srm_msg *i, o;
+	int ret = 0;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	desc = (struct rpmsg_srm_msg_desc *)data;
+	i = desc->msg;
+	o = *i;
+
+	/* Check if 'device_id' (name / addr ) matches this device */
+	if (!strstr(dev_name(dev), i->device_id))
+		return NOTIFY_DONE;
+
+	switch (i->message_type) {
+	case RPROC_SRM_MSG_SETCONFIG:
+		switch (i->rsc_type) {
+		case RPROC_SRM_RSC_CLOCK:
+			ret = rproc_srm_dev_clock_set_cfg(rproc_srm_dev,
+							  &i->clock_cfg);
+			if (!ret)
+				ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev,
+								  &o.clock_cfg);
+			break;
+		case RPROC_SRM_RSC_PIN:
+			ret = rproc_srm_dev_pin_set_cfg(rproc_srm_dev,
+							&i->pin_cfg);
+			if (!ret)
+				ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev,
+								&o.pin_cfg);
+			break;
+		case RPROC_SRM_RSC_REGU:
+			ret = rproc_srm_dev_regu_set_cfg(rproc_srm_dev,
+							 &i->regu_cfg);
+			if (!ret)
+				ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev,
+								 &o.regu_cfg);
+			break;
+		default:
+			dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type);
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	case RPROC_SRM_MSG_GETCONFIG:
+		switch (i->rsc_type) {
+		case RPROC_SRM_RSC_CLOCK:
+			ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev,
+							  &o.clock_cfg);
+			break;
+		case RPROC_SRM_RSC_PIN:
+			ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev,
+							&o.pin_cfg);
+			break;
+		case RPROC_SRM_RSC_REGU:
+			ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev,
+							 &o.regu_cfg);
+			break;
+		default:
+			dev_warn(dev, "bad rsc type (%d)\n", i->rsc_type);
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	default:
+		dev_warn(dev, "bad msg type (%d)\n", i->message_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	/* Send return msg */
+	if (ret)
+		o.message_type = RPROC_SRM_MSG_ERROR;
+
+	ret = rpmsg_srm_send(desc->ept, &o);
+
+	return ret ? NOTIFY_BAD : NOTIFY_STOP;
+}
+
 static void
 rproc_srm_dev_unbind(struct device *dev, struct device *master, void *data)
 {
@@ -451,10 +757,10 @@ rproc_srm_dev_unbind(struct device *dev, struct device *master, void *data)
 
 	dev_dbg(dev, "%s\n", __func__);
 
-	rproc_srm_dev_deconfig_regus(rproc_srm_dev);
-	rproc_srm_dev_deconfig_clocks(rproc_srm_dev);
+	rproc_srm_dev_regus_unsetup(rproc_srm_dev);
+	rproc_srm_dev_clocks_unsetup(rproc_srm_dev);
 
-	/* For pins and IRQs: nothing to deconfigure */
+	/* For pins and IRQs: nothing to unsetup */
 }
 
 static int
@@ -465,15 +771,15 @@ rproc_srm_dev_bind(struct device *dev, struct device *master, void *data)
 
 	dev_dbg(dev, "%s\n", __func__);
 
-	ret = rproc_srm_dev_config_clocks(rproc_srm_dev);
+	ret = rproc_srm_dev_clocks_setup(rproc_srm_dev);
 	if (ret)
 		return ret;
 
-	ret = rproc_srm_dev_config_regus(rproc_srm_dev);
+	ret = rproc_srm_dev_regus_setup(rproc_srm_dev);
 	if (ret)
 		return ret;
 
-	/* For pins and IRQs: nothing to configure */
+	/* For pins and IRQs: nothing to setup */
 	return 0;
 }
 
@@ -496,37 +802,48 @@ static int rproc_srm_dev_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	rproc_srm_dev->dev = dev;
+	rproc_srm_dev->core = dev_get_drvdata(dev->parent);
+
 	INIT_LIST_HEAD(&rproc_srm_dev->clk_list_head);
 	INIT_LIST_HEAD(&rproc_srm_dev->pin_list_head);
 	INIT_LIST_HEAD(&rproc_srm_dev->regu_list_head);
 	INIT_LIST_HEAD(&rproc_srm_dev->irq_list_head);
 
 	/* Get clocks, regu, irqs and pinctrl */
-	ret = rproc_srm_dev_get_clocks(rproc_srm_dev);
+	ret = rproc_srm_dev_clocks_get(rproc_srm_dev);
 	if (ret)
 		return ret;
 
-	ret = rproc_srm_dev_get_regus(rproc_srm_dev);
+	ret = rproc_srm_dev_regus_get(rproc_srm_dev);
 	if (ret)
-		goto err;
+		goto err_get;
 
-	ret = rproc_srm_dev_get_pins(rproc_srm_dev);
+	ret = rproc_srm_dev_pins_get(rproc_srm_dev);
 	if (ret)
-		goto err;
+		goto err_get;
 
-	ret = rproc_srm_dev_get_irqs(rproc_srm_dev);
+	ret = rproc_srm_dev_irqs_get(rproc_srm_dev);
 	if (ret)
-		goto err;
+		goto err_get;
+
+	rproc_srm_dev->nb.notifier_call = rproc_srm_dev_notify_cb;
+	ret = rproc_srm_core_register_notifier(rproc_srm_dev->core,
+					       &rproc_srm_dev->nb);
+	if (ret)
+		goto err_register;
 
 	dev_set_drvdata(dev, rproc_srm_dev);
 
-	return  component_add(dev, &rproc_srm_dev_ops);
+	return component_add(dev, &rproc_srm_dev_ops);
 
-err:
-	rproc_srm_dev_put_irqs(rproc_srm_dev);
-	rproc_srm_dev_put_pins(rproc_srm_dev);
-	rproc_srm_dev_put_regus(rproc_srm_dev);
-	rproc_srm_dev_put_clocks(rproc_srm_dev);
+err_register:
+	rproc_srm_core_unregister_notifier(rproc_srm_dev->core,
+					   &rproc_srm_dev->nb);
+err_get:
+	rproc_srm_dev_irqs_put(rproc_srm_dev);
+	rproc_srm_dev_pins_put(rproc_srm_dev);
+	rproc_srm_dev_regus_put(rproc_srm_dev);
+	rproc_srm_dev_clocks_put(rproc_srm_dev);
 	return ret;
 }
 
@@ -539,10 +856,13 @@ static int rproc_srm_dev_remove(struct platform_device *pdev)
 
 	component_del(dev, &rproc_srm_dev_ops);
 
-	rproc_srm_dev_put_irqs(rproc_srm_dev);
-	rproc_srm_dev_put_regus(rproc_srm_dev);
-	rproc_srm_dev_put_pins(rproc_srm_dev);
-	rproc_srm_dev_put_clocks(rproc_srm_dev);
+	rproc_srm_core_unregister_notifier(rproc_srm_dev->core,
+					   &rproc_srm_dev->nb);
+
+	rproc_srm_dev_irqs_put(rproc_srm_dev);
+	rproc_srm_dev_regus_put(rproc_srm_dev);
+	rproc_srm_dev_pins_put(rproc_srm_dev);
+	rproc_srm_dev_clocks_put(rproc_srm_dev);
 
 	return 0;
 }
