diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 07d2e10..ac3ef43 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -92,6 +92,7 @@ config ARCH_OMAP2PLUS
 	select SOC_BUS
 	select TI_PRIV_EDMA
 	select OMAP_IRQCHIP
+	select RESET_CONTROLLER
 	help
 	  Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
 
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 3fc2cbe..161d8ab 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -27,6 +27,8 @@
 #include <linux/of_address.h>
 #include <linux/clk-provider.h>
 #include <linux/clk/ti.h>
+#include <linux/reset.h>
+#include <linux/reset-controller.h>
 
 #include "soc.h"
 #include "prm2xxx_3xxx.h"
@@ -51,6 +53,11 @@
 #define OMAP_PRCM_MAX_NR_PENDING_REG		2
 
 /*
+ * Default partition for OMAP resets, maps to PRM
+ */
+#define OMAP_RESET_DEFAULT_PARTITION		1
+
+/*
  * prcm_irq_chips: an array of all of the "generic IRQ chips" in use
  * by the PRCM interrupt handler code.  There will be one 'chip' per
  * PRM_{IRQSTATUS,IRQENABLE}_MPU register pair.  (So OMAP3 will have
@@ -737,6 +744,162 @@ static const struct of_device_id const omap_prcm_dt_match_table[] __initconst =
 	{ }
 };
 
+struct ti_reset_data {
+	s16 module;
+	u16 offset;
+	u16 st_offset;
+	u8 shift;
+	u8 st_shift;
+	u8 part;
+};
+
+struct ti_reset_ctrl {
+	struct reset_controller_dev rcdev;
+	struct ti_reset_data **resets;
+	int num_resets;
+	int max_resets;
+	s16 offset;
+};
+
+#define to_ti_reset_ctrl(_rcdev) container_of(_rcdev, struct ti_reset_ctrl, \
+					      rcdev)
+
+static struct ti_reset_data *_get_reset(struct reset_controller_dev *rcdev,
+					unsigned long id)
+{
+	struct ti_reset_ctrl *ctrl = to_ti_reset_ctrl(rcdev);
+
+	return ctrl->resets[id];
+}
+
+static int ti_reset_assert(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	struct ti_reset_data *reset = _get_reset(rcdev, id);
+
+	return omap_prm_assert_hardreset(reset->shift, reset->part,
+					 reset->module, reset->offset);
+}
+
+static int ti_reset_deassert(struct reset_controller_dev *rcdev,
+			     unsigned long id)
+{
+	struct ti_reset_data *reset = _get_reset(rcdev, id);
+
+	return omap_prm_deassert_hardreset(reset->shift, reset->st_shift,
+					   reset->part, reset->module,
+					   reset->offset, reset->st_offset);
+}
+
+static int ti_reset_status(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	struct ti_reset_data *reset = _get_reset(rcdev, id);
+
+	return omap_prm_is_hardreset_asserted(reset->shift, reset->part,
+					      reset->module, reset->offset);
+}
+
+static struct reset_control_ops ti_reset_ops = {
+	.assert = ti_reset_assert,
+	.deassert = ti_reset_deassert,
+	.status = ti_reset_status,
+};
+
+static int ti_reset_xlate(struct reset_controller_dev *rcdev,
+			  const struct of_phandle_args *reset_spec)
+{
+	struct ti_reset_ctrl *ctrl = to_ti_reset_ctrl(rcdev);
+	s16 module;
+	u16 offset, st_offset;
+	u8 shift, st_shift;
+	int index = 0;
+	struct ti_reset_data *reset;
+
+	if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
+		return -EINVAL;
+
+	module = reset_spec->args[0] - ctrl->offset;
+	offset = reset_spec->args[1];
+	shift = reset_spec->args[2];
+	st_offset = reset_spec->args[3];
+	st_shift = reset_spec->args[4];
+
+	for (index = 0; index < ctrl->num_resets; index++) {
+		reset = ctrl->resets[index];
+
+		if (module == reset->module && offset == reset->offset &&
+		    st_offset == reset->st_offset && shift == reset->shift &&
+		    st_shift == reset->st_shift)
+			return index;
+	}
+
+	reset = kzalloc(sizeof(*reset), GFP_KERNEL);
+
+	reset->module = module;
+	reset->offset = offset;
+	reset->st_offset = st_offset;
+	reset->shift = shift;
+	reset->st_shift = st_shift;
+	reset->part = OMAP_RESET_DEFAULT_PARTITION;
+
+	if (ctrl->num_resets + 1 > ctrl->max_resets) {
+		struct ti_reset_data **arr;
+		int num;
+
+		num = ctrl->num_resets;
+		num *= 2;
+		if (!num)
+			num = 1;
+
+		arr = kcalloc(num, sizeof(*arr), GFP_KERNEL);
+		ctrl->max_resets = num;
+		if (ctrl->num_resets)
+			memcpy(arr, ctrl->resets,
+			       sizeof(*arr) * ctrl->num_resets);
+
+		kfree(ctrl->resets);
+		ctrl->resets = arr;
+	}
+
+	ctrl->resets[index] = reset;
+	ctrl->num_resets++;
+
+	return index;
+}
+
+/**
+ * omap2_prm_reset_controller_register - register reset controller for a node
+ * @node: device node to register reset controller for
+ * @data: PRM init data for the node
+ *
+ * Registers a reset controller for the PRM node if applicable. Return 0
+ * in success, negative error value in failure.
+ */
+int __init
+omap2_prm_reset_controller_register(struct device_node *np,
+				    const struct omap_prcm_init_data *data)
+{
+	struct ti_reset_ctrl *ctrl;
+
+	/* Reset controllers available only for PRM nodes */
+	if (data->index != TI_CLKM_PRM)
+		return 0;
+
+	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+
+	ctrl->rcdev.of_node = np;
+	ctrl->rcdev.of_reset_n_cells = 5;
+	ctrl->rcdev.ops = &ti_reset_ops;
+	ctrl->rcdev.of_xlate = &ti_reset_xlate;
+
+	ctrl->offset = data->offset;
+
+	reset_controller_register(&ctrl->rcdev);
+
+	return 0;
+}
+
 /**
  * omap2_prm_base_init - initialize iomappings for the PRM driver
  *
@@ -802,6 +965,10 @@ int __init omap_prcm_init(void)
 		ret = omap2_clk_provider_init(np, data->index, NULL, data->mem);
 		if (ret)
 			return ret;
+
+		ret = omap2_prm_reset_controller_register(np, data);
+		if (ret)
+			return ret;
 	}
 
 	omap_cm_init();
