156 lines
4.6 KiB
Diff
156 lines
4.6 KiB
Diff
|
From c91e8490e45c68ea517f70f24568034b7735e8b9 Mon Sep 17 00:00:00 2001
|
||
|
From: Sascha Hauer <s.hauer@pengutronix.de>
|
||
|
Date: Thu, 23 Apr 2015 10:35:40 +0200
|
||
|
Subject: [PATCH 03/76] clk: mediatek: Add reset controller support
|
||
|
|
||
|
The pericfg and infracfg units also provide reset lines to several
|
||
|
other SoC internal units. This adds a function which can be called
|
||
|
from the pericfg and infracfg initialization functions which will
|
||
|
register the reset controller using reset_controller_register. The
|
||
|
reset controller will provide support for resetting the units
|
||
|
connected to the pericfg and infracfg controller. The units resetted
|
||
|
by this controller can use the standard reset device tree binding
|
||
|
to gain access to the reset lines.
|
||
|
|
||
|
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
|
||
|
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
|
||
|
---
|
||
|
drivers/clk/mediatek/Makefile | 1 +
|
||
|
drivers/clk/mediatek/clk-mtk.h | 10 +++++
|
||
|
drivers/clk/mediatek/reset.c | 97 ++++++++++++++++++++++++++++++++++++++++
|
||
|
3 files changed, 108 insertions(+)
|
||
|
create mode 100644 drivers/clk/mediatek/reset.c
|
||
|
|
||
|
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
|
||
|
index c384e97..0b6f1c3 100644
|
||
|
--- a/drivers/clk/mediatek/Makefile
|
||
|
+++ b/drivers/clk/mediatek/Makefile
|
||
|
@@ -1 +1,2 @@
|
||
|
obj-y += clk-mtk.o clk-pll.o clk-gate.o
|
||
|
+obj-$(CONFIG_RESET_CONTROLLER) += reset.o
|
||
|
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
|
||
|
index 694fc39..61035b9 100644
|
||
|
--- a/drivers/clk/mediatek/clk-mtk.h
|
||
|
+++ b/drivers/clk/mediatek/clk-mtk.h
|
||
|
@@ -156,4 +156,14 @@ void __init mtk_clk_register_plls(struct device_node *node,
|
||
|
const struct mtk_pll_data *plls, int num_plls,
|
||
|
struct clk_onecell_data *clk_data);
|
||
|
|
||
|
+#ifdef CONFIG_RESET_CONTROLLER
|
||
|
+void mtk_register_reset_controller(struct device_node *np,
|
||
|
+ unsigned int num_regs, int regofs);
|
||
|
+#else
|
||
|
+static inline void mtk_register_reset_controller(struct device_node *np,
|
||
|
+ unsigned int num_regs, int regofs)
|
||
|
+{
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
#endif /* __DRV_CLK_MTK_H */
|
||
|
diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c
|
||
|
new file mode 100644
|
||
|
index 0000000..9e9fe4b
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/clk/mediatek/reset.c
|
||
|
@@ -0,0 +1,97 @@
|
||
|
+/*
|
||
|
+ * Copyright (c) 2014 MediaTek Inc.
|
||
|
+ *
|
||
|
+ * 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.
|
||
|
+ */
|
||
|
+
|
||
|
+#include <linux/mfd/syscon.h>
|
||
|
+#include <linux/module.h>
|
||
|
+#include <linux/of.h>
|
||
|
+#include <linux/platform_device.h>
|
||
|
+#include <linux/regmap.h>
|
||
|
+#include <linux/reset-controller.h>
|
||
|
+#include <linux/slab.h>
|
||
|
+
|
||
|
+#include "clk-mtk.h"
|
||
|
+
|
||
|
+struct mtk_reset {
|
||
|
+ struct regmap *regmap;
|
||
|
+ int regofs;
|
||
|
+ struct reset_controller_dev rcdev;
|
||
|
+};
|
||
|
+
|
||
|
+static int mtk_reset_assert(struct reset_controller_dev *rcdev,
|
||
|
+ unsigned long id)
|
||
|
+{
|
||
|
+ struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
|
||
|
+
|
||
|
+ return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
|
||
|
+ BIT(id % 32), ~0);
|
||
|
+}
|
||
|
+
|
||
|
+static int mtk_reset_deassert(struct reset_controller_dev *rcdev,
|
||
|
+ unsigned long id)
|
||
|
+{
|
||
|
+ struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
|
||
|
+
|
||
|
+ return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
|
||
|
+ BIT(id % 32), 0);
|
||
|
+}
|
||
|
+
|
||
|
+static int mtk_reset(struct reset_controller_dev *rcdev,
|
||
|
+ unsigned long id)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ ret = mtk_reset_assert(rcdev, id);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ return mtk_reset_deassert(rcdev, id);
|
||
|
+}
|
||
|
+
|
||
|
+static struct reset_control_ops mtk_reset_ops = {
|
||
|
+ .assert = mtk_reset_assert,
|
||
|
+ .deassert = mtk_reset_deassert,
|
||
|
+ .reset = mtk_reset,
|
||
|
+};
|
||
|
+
|
||
|
+void mtk_register_reset_controller(struct device_node *np,
|
||
|
+ unsigned int num_regs, int regofs)
|
||
|
+{
|
||
|
+ struct mtk_reset *data;
|
||
|
+ int ret;
|
||
|
+ struct regmap *regmap;
|
||
|
+
|
||
|
+ regmap = syscon_node_to_regmap(np);
|
||
|
+ if (IS_ERR(regmap)) {
|
||
|
+ pr_err("Cannot find regmap for %s: %ld\n", np->full_name,
|
||
|
+ PTR_ERR(regmap));
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||
|
+ if (!data)
|
||
|
+ return;
|
||
|
+
|
||
|
+ data->regmap = regmap;
|
||
|
+ data->regofs = regofs;
|
||
|
+ data->rcdev.owner = THIS_MODULE;
|
||
|
+ data->rcdev.nr_resets = num_regs * 32;
|
||
|
+ data->rcdev.ops = &mtk_reset_ops;
|
||
|
+ data->rcdev.of_node = np;
|
||
|
+
|
||
|
+ ret = reset_controller_register(&data->rcdev);
|
||
|
+ if (ret) {
|
||
|
+ pr_err("could not register reset controller: %d\n", ret);
|
||
|
+ kfree(data);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+}
|
||
|
--
|
||
|
1.7.10.4
|
||
|
|