From da686685d3013de6d374965da9473e026e894c6b Mon Sep 17 00:00:00 2001
From: Robert Nelson <robertcnelson@gmail.com>
Date: Wed, 18 Dec 2013 11:23:54 -0600
Subject: [PATCH 1/5] prcm: port from ti-linux-3.12.y

Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
---
 Documentation/devicetree/bindings/arm/omap/prcm.txt |   13 +
 arch/arm/boot/dts/am33xx.dtsi                       |    1 
 drivers/reset/Kconfig                               |   14 +
 drivers/reset/Makefile                              |    1 
 drivers/reset/core.c                                |   32 +++
 drivers/reset/ti_reset.c                            |  184 ++++++++++++++++++++
 include/linux/reset-controller.h                    |    2 
 include/linux/reset.h                               |    2 
 8 files changed, 249 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/omap/prcm.txt
 create mode 100644 drivers/reset/ti_reset.c

Index: linux-3.12.24-rt38-r7s5/Documentation/devicetree/bindings/arm/omap/prcm.txt
===================================================================
--- /dev/null
+++ linux-3.12.24-rt38-r7s5/Documentation/devicetree/bindings/arm/omap/prcm.txt
@@ -0,0 +1,13 @@
+TI Power Reset Clock Manager (PRCM)
+
+Properties:
+- compatible:	"ti,am4372-prcm" for prcm in am43x SoC's
+		"ti,am3352-prcm" for prcm in am335x SoC's
+- #reset-cells: 1 (refer generic reset bindings for details)
+
+example:
+	prcm: prcm@44df0000 {
+		compatible = "ti,am4372-prcm";
+		reg = <0x44df0000 0xa000>;
+		#reset-cells = <1>;
+	};
Index: linux-3.12.24-rt38-r7s5/arch/arm/boot/dts/am33xx.dtsi
===================================================================
--- linux-3.12.24-rt38-r7s5.orig/arch/arm/boot/dts/am33xx.dtsi
+++ linux-3.12.24-rt38-r7s5/arch/arm/boot/dts/am33xx.dtsi
@@ -99,6 +99,7 @@
 		prcm: prcm@44e00000 {
 			compatible = "ti,am3-prcm";
 			reg = <0x44e00000 0x4000>;
+			#reset-cells = <1>;
 
 			prcm_clocks: clocks {
 				#address-cells = <1>;
Index: linux-3.12.24-rt38-r7s5/drivers/reset/Kconfig
===================================================================
--- linux-3.12.24-rt38-r7s5.orig/drivers/reset/Kconfig
+++ linux-3.12.24-rt38-r7s5/drivers/reset/Kconfig
@@ -11,3 +11,17 @@ menuconfig RESET_CONTROLLER
 	  via GPIOs or SoC-internal reset controller modules.
 
 	  If unsure, say no.
+
+if RESET_CONTROLLER
+
+config	RESET_TI
+	bool "TI reset controller"
+	help
+	  Reset controller support for TI SoC's
+
+	  Reset controller found in TI's AM series of SoC's like
+	  AM335x and AM43x and OMAP SoC's like OMAP5 and DRA7
+
+	  If unsure, say no.
+
+endif
Index: linux-3.12.24-rt38-r7s5/drivers/reset/Makefile
===================================================================
--- linux-3.12.24-rt38-r7s5.orig/drivers/reset/Makefile
+++ linux-3.12.24-rt38-r7s5/drivers/reset/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
+obj-$(CONFIG_RESET_TI) += ti_reset.o
Index: linux-3.12.24-rt38-r7s5/drivers/reset/core.c
===================================================================
--- linux-3.12.24-rt38-r7s5.orig/drivers/reset/core.c
+++ linux-3.12.24-rt38-r7s5/drivers/reset/core.c
@@ -127,6 +127,38 @@ int reset_control_deassert(struct reset_
 EXPORT_SYMBOL_GPL(reset_control_deassert);
 
 /**
+ * reset_control_is_reset - check reset status
+ * @rstc: reset controller
+ *
+ * Returns a boolean or negative error code
+ *
+ */
+int reset_control_is_reset(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->is_reset)
+		return rstc->rcdev->ops->is_reset(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_is_reset);
+
+/**
+ * reset_control_clear_reset - clear the reset
+ * @rstc: reset controller
+ *
+ * Returns zero on success or negative error code
+ *
+ */
+int reset_control_clear_reset(struct reset_control *rstc)
+{
+	if (rstc->rcdev->ops->clear_reset)
+		return rstc->rcdev->ops->clear_reset(rstc->rcdev, rstc->id);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_clear_reset);
+
+/**
  * reset_control_get - Lookup and obtain a reference to a reset controller.
  * @dev: device to be reset by the controller
  * @id: reset line name
Index: linux-3.12.24-rt38-r7s5/drivers/reset/ti_reset.c
===================================================================
--- /dev/null
+++ linux-3.12.24-rt38-r7s5/drivers/reset/ti_reset.c
@@ -0,0 +1,184 @@
+/*
+ * PRCM reset driver for TI SoC's
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/reset-controller.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME "ti_reset"
+
+struct ti_reset_reg_data {
+	u32	rstctrl_offs;
+	u32	rstst_offs;
+	u8	rstctrl_bit;
+	u8	rstst_bit;
+};
+
+struct ti_reset_data {
+	struct	ti_reset_reg_data *reg_data;
+	u8	nr_resets;
+};
+
+static void __iomem *reg_base;
+static const struct ti_reset_data *reset_data;
+
+static struct ti_reset_reg_data am335x_reset_reg_data[] = {
+	{
+		.rstctrl_offs	= 0x1104,
+		.rstst_offs	= 0x1114,
+		.rstctrl_bit	= 0,
+		.rstst_bit	= 0,
+	},
+	{
+		.rstctrl_offs	= 0x0D00,
+		.rstst_offs	= 0x0D0C,
+		.rstctrl_bit	= 3,
+		.rstst_bit	= 5,
+	},
+};
+
+static struct ti_reset_data am335x_reset_data = {
+	.reg_data	= am335x_reset_reg_data,
+	.nr_resets	= ARRAY_SIZE(am335x_reset_reg_data),
+};
+
+static struct ti_reset_reg_data am43x_reset_reg_data[] = {
+	{
+		.rstctrl_offs	= 0x410,
+		.rstst_offs	= 0x414,
+		.rstctrl_bit	= 0,
+		.rstst_bit	= 0,
+	},
+	{
+		.rstctrl_offs	= 0x2010,
+		.rstst_offs	= 0x2014,
+		.rstctrl_bit	= 3,
+		.rstst_bit	= 5,
+	},
+};
+
+static struct ti_reset_data am43x_reset_data = {
+	.reg_data	= am43x_reset_reg_data,
+	.nr_resets	= ARRAY_SIZE(am43x_reset_reg_data),
+};
+
+static struct ti_reset_reg_data dra7_reset_reg_data[] = {
+	{
+		.rstctrl_offs	= 0x1310,
+		.rstst_offs	= 0x1314,
+		.rstctrl_bit	= 0,
+		.rstst_bit	= 0,
+	},
+};
+
+static struct ti_reset_data dra7_reset_data = {
+	.reg_data	= dra7_reset_reg_data,
+	.nr_resets	= ARRAY_SIZE(dra7_reset_reg_data),
+};
+
+static int ti_reset_clear_reset(struct reset_controller_dev *rcdev,
+				  unsigned long id)
+{
+	void __iomem *reg = reset_data->reg_data[id].rstst_offs + reg_base;
+	u8 bit = reset_data->reg_data[id].rstst_bit;
+	u32 val = readl(reg);
+
+	val &= ~(1 << bit);
+	val |= 1 << bit;
+	writel(val, reg);
+	return 0;
+}
+
+static int ti_reset_is_reset(struct reset_controller_dev *rcdev,
+			       unsigned long id)
+{
+	void __iomem *reg = reset_data->reg_data[id].rstst_offs + reg_base;
+	u8 bit = reset_data->reg_data[id].rstst_bit;
+	u32 val = readl(reg);
+
+	val &= (1 << bit);
+	return !!val;
+}
+
+static int ti_reset_deassert(struct reset_controller_dev *rcdev,
+			       unsigned long id)
+{
+	void __iomem *reg = reset_data->reg_data[id].rstctrl_offs +
+				reg_base;
+	u8 bit = reset_data->reg_data[id].rstctrl_bit;
+	u32 val = readl(reg);
+
+	val &= ~(1 << bit);
+	writel(val, reg);
+	return 0;
+}
+
+static struct reset_control_ops ti_reset_ops = {
+	.deassert = ti_reset_deassert,
+	.is_reset = ti_reset_is_reset,
+	.clear_reset = ti_reset_clear_reset,
+};
+
+static struct reset_controller_dev ti_reset_controller = {
+	.ops = &ti_reset_ops,
+};
+
+static const struct of_device_id ti_reset_of_match[] = {
+	{ .compatible = "ti,am3352-prcm", .data = &am335x_reset_data,},
+	{ .compatible = "ti,am4372-prcm", .data = &am43x_reset_data,},
+	{ .compatible = "ti,dra7-prcm", .data = &dra7_reset_data,},
+	{},
+};
+
+static int ti_reset_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	const struct of_device_id *id;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(reg_base))
+		return PTR_ERR(reg_base);
+
+	ti_reset_controller.of_node = pdev->dev.of_node;
+	id = of_match_device(ti_reset_of_match, &pdev->dev);
+	reset_data = id->data;
+	ti_reset_controller.nr_resets = reset_data->nr_resets;
+
+	reset_controller_register(&ti_reset_controller);
+
+	return 0;
+}
+
+static int ti_reset_remove(struct platform_device *pdev)
+{
+	reset_controller_unregister(&ti_reset_controller);
+
+	return 0;
+}
+
+static struct platform_driver ti_reset_driver = {
+	.probe	= ti_reset_probe,
+	.remove	= ti_reset_remove,
+	.driver	= {
+		.name		= DRIVER_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= of_match_ptr(ti_reset_of_match),
+	},
+};
+module_platform_driver(ti_reset_driver);
+
+MODULE_DESCRIPTION("PRCM reset driver for TI SoC's");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
Index: linux-3.12.24-rt38-r7s5/include/linux/reset-controller.h
===================================================================
--- linux-3.12.24-rt38-r7s5.orig/include/linux/reset-controller.h
+++ linux-3.12.24-rt38-r7s5/include/linux/reset-controller.h
@@ -17,6 +17,8 @@ struct reset_control_ops {
 	int (*reset)(struct reset_controller_dev *rcdev, unsigned long id);
 	int (*assert)(struct reset_controller_dev *rcdev, unsigned long id);
 	int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);
+	int (*is_reset)(struct reset_controller_dev *rcdev, unsigned long id);
+	int (*clear_reset)(struct reset_controller_dev *rcdev, unsigned long i);
 };
 
 struct module;
Index: linux-3.12.24-rt38-r7s5/include/linux/reset.h
===================================================================
--- linux-3.12.24-rt38-r7s5.orig/include/linux/reset.h
+++ linux-3.12.24-rt38-r7s5/include/linux/reset.h
@@ -7,6 +7,8 @@ struct reset_control;
 int reset_control_reset(struct reset_control *rstc);
 int reset_control_assert(struct reset_control *rstc);
 int reset_control_deassert(struct reset_control *rstc);
+int reset_control_is_reset(struct reset_control *rstc);
+int reset_control_clear_reset(struct reset_control *rstc);
 
 struct reset_control *reset_control_get(struct device *dev, const char *id);
 void reset_control_put(struct reset_control *rstc);