lkml.org 
[lkml]   [2018]   [Aug]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH v2 08/10] reset: Add Actions Semi S900 SoC Reset Management Unit support
Date
Add Reset Management Unit (RMU) support for Actions Semi S900 SoC
of the Owl family series. RMU belongs to the Owl SoCs system-controller
which also includes CMU (Clock Management Unit).

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
drivers/reset/Kconfig | 6 ++
drivers/reset/Makefile | 1 +
drivers/reset/reset-owl.c | 192 ++++++++++++++++++++++++++++++++++++++
3 files changed, 199 insertions(+)
create mode 100644 drivers/reset/reset-owl.c

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c0b292be1b72..90627430569b 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -73,6 +73,12 @@ config RESET_MESON
help
This enables the reset driver for Amlogic Meson SoCs.

+config RESET_OWL
+ bool "Actions Semi Owl SoCs Reset Driver" if COMPILE_TEST
+ default ARCH_ACTIONS
+ help
+ This enables the reset controller driver for Actions Semi Owl SoCs.
+
config RESET_OXNAS
bool

diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index c1261dcfe9ad..fa655319cf17 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
+obj-$(CONFIG_RESET_OWL) += reset-owl.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
diff --git a/drivers/reset/reset-owl.c b/drivers/reset/reset-owl.c
new file mode 100644
index 000000000000..c4f07691fb36
--- /dev/null
+++ b/drivers/reset/reset-owl.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Actions Semi Owl SoCs Reset Management Unit driver
+//
+// Copyright (c) 2018 Linaro Ltd.
+// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/reset/actions,s900-rmu.h>
+
+#define CMU_DEVRST0 0x00a8
+#define CMU_DEVRST1 0x00ac
+
+struct owl_reset_map {
+ u32 reg;
+ u32 bit;
+};
+
+struct owl_reset_hw {
+ const struct owl_reset_map *resets;
+ u32 num_resets;
+};
+
+struct owl_reset {
+ struct reset_controller_dev rcdev;
+ const struct owl_reset_hw *hw;
+ struct regmap *regmap;
+};
+
+static const struct owl_reset_map s900_resets[] = {
+ [S900_RESET_DMAC] = { CMU_DEVRST0, BIT(0) },
+ [S900_RESET_SRAMI] = { CMU_DEVRST0, BIT(1) },
+ [S900_RESET_DDR_CTL_PHY] = { CMU_DEVRST0, BIT(2) },
+ [S900_RESET_NANDC0] = { CMU_DEVRST0, BIT(3) },
+ [S900_RESET_SD0] = { CMU_DEVRST0, BIT(4) },
+ [S900_RESET_SD1] = { CMU_DEVRST0, BIT(5) },
+ [S900_RESET_PCM1] = { CMU_DEVRST0, BIT(6) },
+ [S900_RESET_DE] = { CMU_DEVRST0, BIT(7) },
+ [S900_RESET_LVDS] = { CMU_DEVRST0, BIT(8) },
+ [S900_RESET_SD2] = { CMU_DEVRST0, BIT(9) },
+ [S900_RESET_DSI] = { CMU_DEVRST0, BIT(10) },
+ [S900_RESET_CSI0] = { CMU_DEVRST0, BIT(11) },
+ [S900_RESET_BISP_AXI] = { CMU_DEVRST0, BIT(12) },
+ [S900_RESET_CSI1] = { CMU_DEVRST0, BIT(13) },
+ [S900_RESET_GPIO] = { CMU_DEVRST0, BIT(15) },
+ [S900_RESET_EDP] = { CMU_DEVRST0, BIT(16) },
+ [S900_RESET_AUDIO] = { CMU_DEVRST0, BIT(17) },
+ [S900_RESET_PCM0] = { CMU_DEVRST0, BIT(18) },
+ [S900_RESET_HDE] = { CMU_DEVRST0, BIT(21) },
+ [S900_RESET_GPU3D_PA] = { CMU_DEVRST0, BIT(22) },
+ [S900_RESET_IMX] = { CMU_DEVRST0, BIT(23) },
+ [S900_RESET_SE] = { CMU_DEVRST0, BIT(24) },
+ [S900_RESET_NANDC1] = { CMU_DEVRST0, BIT(25) },
+ [S900_RESET_SD3] = { CMU_DEVRST0, BIT(26) },
+ [S900_RESET_GIC] = { CMU_DEVRST0, BIT(27) },
+ [S900_RESET_GPU3D_PB] = { CMU_DEVRST0, BIT(28) },
+ [S900_RESET_DDR_CTL_PHY_AXI] = { CMU_DEVRST0, BIT(29) },
+ [S900_RESET_CMU_DDR] = { CMU_DEVRST0, BIT(30) },
+ [S900_RESET_DMM] = { CMU_DEVRST0, BIT(31) },
+ [S900_RESET_USB2HUB] = { CMU_DEVRST1, BIT(0) },
+ [S900_RESET_USB2HSIC] = { CMU_DEVRST1, BIT(1) },
+ [S900_RESET_HDMI] = { CMU_DEVRST1, BIT(2) },
+ [S900_RESET_HDCP2TX] = { CMU_DEVRST1, BIT(3) },
+ [S900_RESET_UART6] = { CMU_DEVRST1, BIT(4) },
+ [S900_RESET_UART0] = { CMU_DEVRST1, BIT(5) },
+ [S900_RESET_UART1] = { CMU_DEVRST1, BIT(6) },
+ [S900_RESET_UART2] = { CMU_DEVRST1, BIT(7) },
+ [S900_RESET_SPI0] = { CMU_DEVRST1, BIT(8) },
+ [S900_RESET_SPI1] = { CMU_DEVRST1, BIT(9) },
+ [S900_RESET_SPI2] = { CMU_DEVRST1, BIT(10) },
+ [S900_RESET_SPI3] = { CMU_DEVRST1, BIT(11) },
+ [S900_RESET_I2C0] = { CMU_DEVRST1, BIT(12) },
+ [S900_RESET_I2C1] = { CMU_DEVRST1, BIT(13) },
+ [S900_RESET_USB3] = { CMU_DEVRST1, BIT(14) },
+ [S900_RESET_UART3] = { CMU_DEVRST1, BIT(15) },
+ [S900_RESET_UART4] = { CMU_DEVRST1, BIT(16) },
+ [S900_RESET_UART5] = { CMU_DEVRST1, BIT(17) },
+ [S900_RESET_I2C2] = { CMU_DEVRST1, BIT(18) },
+ [S900_RESET_I2C3] = { CMU_DEVRST1, BIT(19) },
+};
+
+static const struct owl_reset_hw s900_reset_hw = {
+ .resets = s900_resets,
+ .num_resets = ARRAY_SIZE(s900_resets),
+};
+
+static inline struct owl_reset *to_owl_reset(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct owl_reset, rcdev);
+}
+
+static int owl_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct owl_reset *reset = to_owl_reset(rcdev);
+ const struct owl_reset_map *map = &reset->hw->resets[id];
+
+ return regmap_update_bits(reset->regmap, map->reg, map->bit, 0);
+}
+
+static int owl_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct owl_reset *reset = to_owl_reset(rcdev);
+ const struct owl_reset_map *map = &reset->hw->resets[id];
+
+ return regmap_update_bits(reset->regmap, map->reg, map->bit, map->bit);
+}
+
+static int owl_reset_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ owl_reset_assert(rcdev, id);
+ udelay(1);
+ owl_reset_deassert(rcdev, id);
+
+ return 0;
+}
+
+static int owl_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct owl_reset *reset = to_owl_reset(rcdev);
+ const struct owl_reset_map *map = &reset->hw->resets[id];
+ u32 reg;
+ int ret;
+
+ ret = regmap_read(reset->regmap, map->reg, &reg);
+ if (ret)
+ return ret;
+
+ /*
+ * The reset control API expects 0 if reset is not asserted,
+ * which is the opposite of what our hardware uses.
+ */
+ return !(map->bit & reg);
+}
+
+static const struct reset_control_ops owl_reset_ops = {
+ .assert = owl_reset_assert,
+ .deassert = owl_reset_deassert,
+ .reset = owl_reset_reset,
+ .status = owl_reset_status,
+};
+
+static int owl_reset_probe(struct platform_device *pdev)
+{
+ struct owl_reset *reset;
+ struct regmap *regmap;
+ const struct owl_reset_hw *hw;
+
+ hw = of_device_get_match_data(&pdev->dev);
+ if (!hw)
+ return -EINVAL;
+
+ reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
+ if (!reset)
+ return -ENOMEM;
+
+ regmap = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
+ if (IS_ERR(regmap)) {
+ dev_err(&pdev->dev, "failed to get regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ reset->rcdev.of_node = pdev->dev.of_node;
+ reset->rcdev.ops = &owl_reset_ops;
+ reset->rcdev.nr_resets = hw->num_resets;
+ reset->hw = hw;
+ reset->regmap = regmap;
+
+ return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
+}
+
+static const struct of_device_id owl_reset_of_match[] = {
+ { .compatible = "actions,s900-rmu", .data = &s900_reset_hw },
+ { /* sentinel */ }
+};
+
+static struct platform_driver owl_reset_driver = {
+ .probe = owl_reset_probe,
+ .driver = {
+ .name = "owl-reset",
+ .of_match_table = owl_reset_of_match,
+ },
+};
+builtin_platform_driver(owl_reset_driver);
--
2.17.1
\
 
 \ /
  Last update: 2018-08-01 05:42    [W:0.150 / U:0.136 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site