aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2017-05-24 04:19:20 -0400
committerPhilipp Zabel <p.zabel@pengutronix.de>2017-05-24 04:46:13 -0400
commit2acb037fc42b8ce5ae59a7d5db3c9b35672e3dd7 (patch)
treeec49133cd245bfb1bcec8750fdc43403899b1be1
parent128987916f50d38baa3fad7c1a6dea82f31e6d8c (diff)
reset: Add a Gemini reset controller
The Cortina Systems Gemini reset controller is a simple 32bit register with self-deasserting reset lines. It is accessed using regmap over syscon. Acked-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-rw-r--r--drivers/reset/Kconfig7
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-gemini.c110
3 files changed, 118 insertions, 0 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 42d5631c6da0..61fabf6ddaec 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -34,6 +34,13 @@ config RESET_BERLIN
34 help 34 help
35 This enables the reset controller driver for Marvell Berlin SoCs. 35 This enables the reset controller driver for Marvell Berlin SoCs.
36 36
37config RESET_GEMINI
38 bool "Gemini Reset Driver" if COMPILE_TEST
39 default ARCH_GEMINI
40 select MFD_SYSCON
41 help
42 This enables the reset controller driver for Cortina Systems Gemini.
43
37config RESET_IMX7 44config RESET_IMX7
38 bool "i.MX7 Reset Driver" if COMPILE_TEST 45 bool "i.MX7 Reset Driver" if COMPILE_TEST
39 default SOC_IMX7D 46 default SOC_IMX7D
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 26270e0f8342..e422a04f7b85 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
5obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o 5obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o
6obj-$(CONFIG_RESET_ATH79) += reset-ath79.o 6obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
7obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o 7obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
8obj-$(CONFIG_RESET_GEMINI) += reset-gemini.o
8obj-$(CONFIG_RESET_IMX7) += reset-imx7.o 9obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
9obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o 10obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
10obj-$(CONFIG_RESET_MESON) += reset-meson.o 11obj-$(CONFIG_RESET_MESON) += reset-meson.o
diff --git a/drivers/reset/reset-gemini.c b/drivers/reset/reset-gemini.c
new file mode 100644
index 000000000000..a2478997c75b
--- /dev/null
+++ b/drivers/reset/reset-gemini.c
@@ -0,0 +1,110 @@
1/*
2 * Cortina Gemini Reset controller driver
3 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/err.h>
11#include <linux/init.h>
12#include <linux/mfd/syscon.h>
13#include <linux/regmap.h>
14#include <linux/of.h>
15#include <linux/platform_device.h>
16#include <linux/reset-controller.h>
17#include <dt-bindings/reset/cortina,gemini-reset.h>
18
19/**
20 * struct gemini_reset - gemini reset controller
21 * @map: regmap to access the containing system controller
22 * @rcdev: reset controller device
23 */
24struct gemini_reset {
25 struct regmap *map;
26 struct reset_controller_dev rcdev;
27};
28
29#define GEMINI_GLOBAL_SOFT_RESET 0x0c
30
31#define to_gemini_reset(p) \
32 container_of((p), struct gemini_reset, rcdev)
33
34/*
35 * This is a self-deasserting reset controller.
36 */
37static int gemini_reset(struct reset_controller_dev *rcdev,
38 unsigned long id)
39{
40 struct gemini_reset *gr = to_gemini_reset(rcdev);
41
42 /* Manual says to always set BIT 30 (CPU1) to 1 */
43 return regmap_write(gr->map,
44 GEMINI_GLOBAL_SOFT_RESET,
45 BIT(GEMINI_RESET_CPU1) | BIT(id));
46}
47
48static int gemini_reset_status(struct reset_controller_dev *rcdev,
49 unsigned long id)
50{
51 struct gemini_reset *gr = to_gemini_reset(rcdev);
52 u32 val;
53 int ret;
54
55 ret = regmap_read(gr->map, GEMINI_GLOBAL_SOFT_RESET, &val);
56 if (ret)
57 return ret;
58
59 return !!(val & BIT(id));
60}
61
62static const struct reset_control_ops gemini_reset_ops = {
63 .reset = gemini_reset,
64 .status = gemini_reset_status,
65};
66
67static int gemini_reset_probe(struct platform_device *pdev)
68{
69 struct gemini_reset *gr;
70 struct device *dev = &pdev->dev;
71 struct device_node *np = dev->of_node;
72 int ret;
73
74 gr = devm_kzalloc(dev, sizeof(*gr), GFP_KERNEL);
75 if (!gr)
76 return -ENOMEM;
77
78 gr->map = syscon_node_to_regmap(np);
79 if (IS_ERR(gr->map)) {
80 ret = PTR_ERR(gr->map);
81 dev_err(dev, "unable to get regmap (%d)", ret);
82 return ret;
83 }
84 gr->rcdev.owner = THIS_MODULE;
85 gr->rcdev.nr_resets = 32;
86 gr->rcdev.ops = &gemini_reset_ops;
87 gr->rcdev.of_node = pdev->dev.of_node;
88
89 ret = devm_reset_controller_register(&pdev->dev, &gr->rcdev);
90 if (ret)
91 return ret;
92
93 dev_info(dev, "registered Gemini reset controller\n");
94 return 0;
95}
96
97static const struct of_device_id gemini_reset_dt_ids[] = {
98 { .compatible = "cortina,gemini-syscon", },
99 { /* sentinel */ },
100};
101
102static struct platform_driver gemini_reset_driver = {
103 .probe = gemini_reset_probe,
104 .driver = {
105 .name = "gemini-reset",
106 .of_match_table = gemini_reset_dt_ids,
107 .suppress_bind_attrs = true,
108 },
109};
110builtin_platform_driver(gemini_reset_driver);