diff --git a/Documentation/devicetree/bindings/i2c/i2c-rpmsg-imx.txt b/Documentation/devicetree/bindings/i2c/i2c-rpmsg-imx.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fce660d0f179d31bc5baa8217182fa8b19565900
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-rpmsg-imx.txt
@@ -0,0 +1,29 @@
+* Freescale Virtual I2C RPMSG bus driver for i.MX
+
+Required properties:
+- compatible :
+  - "fsl,i2c-rpbus" for I2C bus over RPMSG compatible on i.MX8QXP/QM soc
+The i2c-rpbus node should define its bus id (which is the node communicating
+with M4) in alias.
+
+Examples:
+
+aliases {
+	...
+	i2c1 = &i2c_rpbus_1;
+	...
+};
+
+&i2c_rpbus_1 {
+	compatible = "fsl,i2c-rpbus";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	devs_in_this_i2c_bus__for_example: pca6416@20 {
+		compatible = "ti,tca6416";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index a49e0ed4a599d538ea45815c10daed5f37eb9977..9c9b7e990fd9ac3f7772c4512a53657017257aa5 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -954,6 +954,12 @@ config I2C_RK3X
 	  This driver can also be built as a module. If so, the module will
 	  be called i2c-rk3x.
 
+config I2C_RPBUS
+	tristate "I2C proxy bus over RPMSG"
+	depends on I2C && RPMSG
+	help
+	  This driver can support virtual i2c-rpmsg function.
+
 config HAVE_S3C2410_I2C
 	bool
 	help
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 683c49faca05c4501a36316c9e816556e90c9841..f15b20a6d11383d90a7e36f61faf86c2c883d9df 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o
 obj-$(CONFIG_I2C_DLN2)		+= i2c-dln2.o
 obj-$(CONFIG_I2C_PARPORT)	+= i2c-parport.o
 obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF)	+= i2c-robotfuzz-osif.o
+obj-$(CONFIG_I2C_RPBUS)		+= i2c-rpmsg-imx.o
 obj-$(CONFIG_I2C_TAOS_EVM)	+= i2c-taos-evm.o
 obj-$(CONFIG_I2C_TINY_USB)	+= i2c-tiny-usb.o
 obj-$(CONFIG_I2C_VIPERBOARD)	+= i2c-viperboard.o
diff --git a/drivers/i2c/busses/i2c-rpmsg-imx.c b/drivers/i2c/busses/i2c-rpmsg-imx.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c13056167f11880a64613ac86246634c4c61a94
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rpmsg-imx.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2019 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* The i2c-rpmsg transfer protocol:
+ *
+ *   +---------------+-------------------------------+
+ *   |  Byte Offset  |            Content            |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       0       |           Category            |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |     1 ~ 2     |           Version             |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       3       |             Type              |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       4       |           Command             |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       5       |           Priority            |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       6       |           Reserved1           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       7       |           Reserved2           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       8       |           Reserved3           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       9       |           Reserved4           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       10      |            BUS ID             |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       11      |         Return Value          |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |    12 ~ 13    |            BUS ID             |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |    14 ~ 15    |            Address            |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |    16 ~ 17    |           Data Len            |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |    18 ~ 33    |        16 Bytes Data          |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *
+ * The definition of Return Value:
+ * 0x00 = Success
+ * 0x01 = Failed
+ * 0x02 = Invalid parameter
+ * 0x03 = Invalid message
+ * 0x04 = Operate in invalid state
+ * 0x05 = Memory allocation failed
+ * 0x06 = Timeout when waiting for an event
+ * 0x07 = Cannot add to list as node already in another list
+ * 0x08 = Cannot remove from list as node not in list
+ * 0x09 = Transfer timeout
+ * 0x0A = Transfer failed due to peer core not ready
+ * 0x0B = Transfer failed due to communication failure
+ * 0x0C = Cannot find service for a request/notification
+ * 0x0D = Service version cannot support the request/notification
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/imx_rpmsg.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/rpmsg.h>
+
+#define I2C_RPMSG_MAX_BUF_SIZE			16
+#define I2C_RPMSG_TIMEOUT			100 /* unit: ms */
+
+#define I2C_RPMSG_CATEGORY			0x09
+#define I2C_RPMSG_VERSION			0x0001
+#define I2C_RPMSG_TYPE_REQUEST			0x00
+#define I2C_RPMSG_TYPE_RESPONSE			0x01
+#define I2C_RPMSG_COMMAND_READ			0x00
+#define I2C_RPMSG_COMMAND_WRITE			0x01
+#define I2C_RPMSG_PRIORITY			0x01
+
+#define I2C_RPMSG_M_STOP			0x0200
+
+struct i2c_rpmsg_msg {
+	struct imx_rpmsg_head header;
+
+	/* Payload Start*/
+	u8 bus_id;
+	u8 ret_val;
+	u16 addr;
+	u16 flags;
+	u16 len;
+	u8 buf[I2C_RPMSG_MAX_BUF_SIZE];
+} __packed __aligned(1);
+
+struct i2c_rpmsg_info {
+	struct rpmsg_device *rpdev;
+	struct device *dev;
+	struct i2c_rpmsg_msg *msg;
+	struct completion cmd_complete;
+};
+
+static struct i2c_rpmsg_info i2c_rpmsg;
+
+struct imx_rpmsg_i2c_data {
+	struct i2c_adapter adapter;
+};
+
+static int i2c_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
+			   void *priv, u32 src)
+{
+	struct i2c_rpmsg_msg *msg = (struct i2c_rpmsg_msg *)data;
+
+	if (msg->header.type != I2C_RPMSG_TYPE_RESPONSE)
+		return -EINVAL;
+
+	if (msg->len > I2C_RPMSG_MAX_BUF_SIZE) {
+		dev_err(&rpdev->dev,
+		"%s failed: data length greater than %d, len=%d\n",
+		__func__, I2C_RPMSG_MAX_BUF_SIZE, msg->len);
+		return -EINVAL;
+	}
+
+	/* Receive Success */
+	i2c_rpmsg.msg = msg;
+
+	complete(&i2c_rpmsg.cmd_complete);
+
+	return 0;
+}
+
+static int rpmsg_xfer(struct i2c_rpmsg_msg *rmsg, struct i2c_rpmsg_info *info)
+{
+	int ret = 0;
+
+	ret = rpmsg_send(info->rpdev->ept, (void *)rmsg,
+						sizeof(struct i2c_rpmsg_msg));
+	if (ret < 0) {
+		dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = wait_for_completion_timeout(&info->cmd_complete,
+					msecs_to_jiffies(I2C_RPMSG_TIMEOUT));
+	if (!ret) {
+		dev_err(&info->rpdev->dev, "%s failed: timeout\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	if (info->msg->ret_val) {
+		dev_dbg(&info->rpdev->dev,
+			"%s failed: %d\n", __func__, info->msg->ret_val);
+		return -(info->msg->ret_val);
+	}
+
+	return 0;
+}
+
+static int i2c_rpmsg_read(struct i2c_msg *msg, struct i2c_rpmsg_info *info,
+						int bus_id, bool is_last)
+{
+	int ret;
+	struct i2c_rpmsg_msg rmsg;
+
+	if (!info->rpdev)
+		return -EINVAL;
+
+	if (msg->len > I2C_RPMSG_MAX_BUF_SIZE) {
+		dev_err(&info->rpdev->dev,
+		"%s failed: data length greater than %d, len=%d\n",
+		__func__, I2C_RPMSG_MAX_BUF_SIZE, msg->len);
+		return -EINVAL;
+	}
+
+	memset(&rmsg, 0, sizeof(struct i2c_rpmsg_msg));
+	rmsg.header.cate = I2C_RPMSG_CATEGORY;
+	rmsg.header.major = I2C_RPMSG_VERSION;
+	rmsg.header.minor = I2C_RPMSG_VERSION >> 8;
+	rmsg.header.type = I2C_RPMSG_TYPE_REQUEST;
+	rmsg.header.cmd = I2C_RPMSG_COMMAND_READ;
+	rmsg.header.reserved[0] = I2C_RPMSG_PRIORITY;
+	rmsg.bus_id = bus_id;
+	rmsg.ret_val = 0;
+	rmsg.addr = msg->addr;
+	if (is_last)
+		rmsg.flags = msg->flags | I2C_RPMSG_M_STOP;
+	else
+		rmsg.flags = msg->flags;
+	rmsg.len = (msg->len);
+
+	reinit_completion(&info->cmd_complete);
+
+	ret = rpmsg_xfer(&rmsg, info);
+	if (ret)
+		return ret;
+
+	if (!info->msg ||
+	    (info->msg->len != msg->len)) {
+		dev_err(&info->rpdev->dev,
+					"%s failed: %d\n", __func__, -EPROTO);
+		return -EPROTO;
+	}
+
+	memcpy(msg->buf, info->msg->buf, info->msg->len);
+
+	return msg->len;
+}
+
+int i2c_rpmsg_write(struct i2c_msg *msg, struct i2c_rpmsg_info *info,
+						int bus_id, bool is_last)
+{
+	int i, ret;
+	struct i2c_rpmsg_msg rmsg;
+
+	if (!info || !info->rpdev)
+		return -EINVAL;
+
+	if (msg->len > I2C_RPMSG_MAX_BUF_SIZE) {
+		dev_err(&info->rpdev->dev,
+		"%s failed: data length greater than %d, len=%d\n",
+		__func__, I2C_RPMSG_MAX_BUF_SIZE, msg->len);
+		return -EINVAL;
+	}
+
+	memset(&rmsg, 0, sizeof(struct i2c_rpmsg_msg));
+	rmsg.header.cate = I2C_RPMSG_CATEGORY;
+	rmsg.header.major = I2C_RPMSG_VERSION;
+	rmsg.header.minor = I2C_RPMSG_VERSION >> 8;
+	rmsg.header.type = I2C_RPMSG_TYPE_REQUEST;
+	rmsg.header.cmd = I2C_RPMSG_COMMAND_WRITE;
+	rmsg.header.reserved[0] = I2C_RPMSG_PRIORITY;
+	rmsg.bus_id = bus_id;
+	rmsg.ret_val = 0;
+	rmsg.addr = msg->addr;
+	if (is_last)
+		rmsg.flags = msg->flags | I2C_RPMSG_M_STOP;
+	else
+		rmsg.flags = msg->flags;
+	rmsg.len = msg->len;
+
+	for (i = 0; i < rmsg.len; i++)
+		rmsg.buf[i] = msg->buf[i];
+
+	reinit_completion(&info->cmd_complete);
+
+	ret = rpmsg_xfer(&rmsg, info);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int i2c_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+	int ret = 0;
+
+	if (!rpdev) {
+		dev_info(&rpdev->dev, "%s failed, rpdev=NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	i2c_rpmsg.rpdev = rpdev;
+
+	init_completion(&i2c_rpmsg.cmd_complete);
+
+	dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+						rpdev->src, rpdev->dst);
+
+	return ret;
+}
+
+static void i2c_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+	i2c_rpmsg.rpdev = NULL;
+	dev_info(&rpdev->dev, "i2c rpmsg driver is removed\n");
+}
+
+static struct rpmsg_device_id i2c_rpmsg_id_table[] = {
+	{ .name	= "rpmsg-i2c-channel" },
+	{ },
+};
+
+static struct rpmsg_driver i2c_rpmsg_driver = {
+	.drv.name	= "i2c-rpmsg",
+	.drv.owner	= THIS_MODULE,
+	.id_table	= i2c_rpmsg_id_table,
+	.probe		= i2c_rpmsg_probe,
+	.remove		= i2c_rpmsg_remove,
+	.callback	= i2c_rpmsg_cb,
+};
+
+
+static int i2c_rpbus_xfer(struct i2c_adapter *adapter,
+			  struct i2c_msg *msgs, int num)
+{
+	struct imx_rpmsg_i2c_data *rdata =
+		container_of(adapter, struct imx_rpmsg_i2c_data, adapter);
+	struct i2c_msg *pmsg;
+	int i, ret;
+	bool is_last = false;
+
+	for (i = 0; i < num; i++) {
+		if (i == num - 1)
+			is_last = true;
+
+		pmsg = &msgs[i];
+
+		if (pmsg->flags & I2C_M_RD) {
+			ret = i2c_rpmsg_read(pmsg, &i2c_rpmsg,
+						rdata->adapter.nr, is_last);
+			if (ret < 0)
+				return ret;
+
+			pmsg->len = ret;
+		} else {
+			ret = i2c_rpmsg_write(pmsg, &i2c_rpmsg,
+						rdata->adapter.nr, is_last);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return num;
+}
+
+static u32 i2c_rpbus_func(struct i2c_adapter *a)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+		| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm i2c_rpbus_algorithm = {
+	.master_xfer = i2c_rpbus_xfer,
+	.functionality = i2c_rpbus_func,
+};
+
+static const struct i2c_adapter_quirks i2c_rpbus_quirks = {
+	.max_write_len = I2C_RPMSG_MAX_BUF_SIZE,
+	.max_read_len = I2C_RPMSG_MAX_BUF_SIZE,
+};
+
+static int i2c_rpbus_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct imx_rpmsg_i2c_data *rdata;
+	struct i2c_adapter *adapter;
+	int ret;
+
+	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata), GFP_KERNEL);
+	if (!rdata)
+		return -ENOMEM;
+
+	adapter = &rdata->adapter;
+	/* setup i2c adapter description */
+	adapter->owner = THIS_MODULE;
+	adapter->class = I2C_CLASS_HWMON;
+	adapter->algo = &i2c_rpbus_algorithm;
+	adapter->dev.parent = dev;
+	adapter->dev.of_node = np;
+	adapter->nr = of_alias_get_id(np, "i2c");
+	adapter->quirks = &i2c_rpbus_quirks;
+	snprintf(rdata->adapter.name, sizeof(rdata->adapter.name), "%s",
+							"i2c-rpmsg-adapter");
+	platform_set_drvdata(pdev, rdata);
+
+	ret = i2c_add_adapter(&rdata->adapter);
+	if (ret < 0) {
+		dev_err(dev, "failed to add I2C adapter: %d\n", ret);
+		return ret;
+	}
+
+	dev_info(dev, "add I2C adapter %s successfully\n", rdata->adapter.name);
+
+	return 0;
+}
+
+static int i2c_rpbus_remove(struct platform_device *pdev)
+{
+	struct imx_rpmsg_i2c_data *rdata = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&rdata->adapter);
+
+	return 0;
+}
+
+static const struct of_device_id imx_rpmsg_i2c_dt_ids[] = {
+	{ .compatible = "fsl,i2c-rpbus", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_rpmsg_i2c_dt_ids);
+
+static struct platform_driver imx_rpmsg_i2c_driver = {
+	.driver = {
+		.name	= "imx_rpmsg_i2c",
+		.of_match_table = imx_rpmsg_i2c_dt_ids,
+	},
+	.probe		= i2c_rpbus_probe,
+	.remove		= i2c_rpbus_remove
+};
+
+static int __init imx_rpmsg_i2c_driver_init(void)
+{
+	int ret = 0;
+
+	ret = register_rpmsg_driver(&i2c_rpmsg_driver);
+	if (ret < 0)
+		return ret;
+
+	return platform_driver_register(&(imx_rpmsg_i2c_driver));
+}
+subsys_initcall(imx_rpmsg_i2c_driver_init);
+
+MODULE_AUTHOR("Clark Wang<xiaoning.wang@nxp.com>");
+MODULE_DESCRIPTION("Driver for i2c over rpmsg");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-rpbus");