Message ID | 20170816003847.6208-4-afaerber@suse.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Andreas, On Wed, 2017-08-16 at 02:38 +0200, Andreas Färber wrote: > Add a per-register reset controller driver. This deals with the fact > that not all registers are adjoined. the way you handle the non-contiguous reset registers, this looks like a candidate to join the recently discussed reset-simple driver [1]. Could you check if that would fit? regards Philipp
Hi Philipp, Am 16.08.2017 um 11:44 schrieb Philipp Zabel: > On Wed, 2017-08-16 at 02:38 +0200, Andreas Färber wrote: >> Add a per-register reset controller driver. This deals with the fact >> that not all registers are adjoined. > > the way you handle the non-contiguous reset registers, this looks like > a candidate to join the recently discussed reset-simple driver [1]. > Could you check if that would fit? Thanks, I appreciate the idea, and it looks like you already have the active-low logic in place. Are you okay with keeping the first three as separate nodes, or would you rather want one node to cover the first three registers, plus two separate ones for the non-contiguous cases? Or is the simple driver supposed to cover gaps, too? Then we could go with just two nodes. (I found it weird to have reset and then reset4, so I went with separate ones as seen downstream.) Regards, Andreas
On Wed, 2017-08-16 at 14:09 +0200, Andreas Färber wrote: > Hi Philipp, > > Am 16.08.2017 um 11:44 schrieb Philipp Zabel: > > On Wed, 2017-08-16 at 02:38 +0200, Andreas Färber wrote: > > > Add a per-register reset controller driver. This deals with the > > > fact > > > that not all registers are adjoined. > > > > the way you handle the non-contiguous reset registers, this looks > > like > > a candidate to join the recently discussed reset-simple driver [1]. > > Could you check if that would fit? > > Thanks, I appreciate the idea, and it looks like you already have the > active-low logic in place. > > Are you okay with keeping the first three as separate nodes, or would > you rather want one node to cover the first three registers, plus two > separate ones for the non-contiguous cases? I am fine with keeping them separate, if you think this best describes the hardware. > Or is the simple driver supposed to cover gaps, too? Then we could go > with just two nodes. (I found it weird to have reset and then reset4, > so I went with separate ones as seen downstream.) I had declared gaps as out of scope of the simple reset controller driver, but if the implementation could be kept reasonably simple, we could think about supporting something like this, too: reset: reset-controller@98000000 { compatible = "realtek,rtd1295-reset"; reg = <0x98000000 0xc>, <0x98000050 0x4>; #reset-cells = <1>; }; regards Philipp
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 52d5251660b9..dbac75e3f82c 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -68,6 +68,12 @@ config RESET_PISTACHIO help This enables the reset driver for ImgTec Pistachio SoCs. +config RESET_RTD129X + bool "Realtek RTD129x Reset Driver" if COMPILE_TEST + default ARCH_REALTEK if ARM64 + help + This enables the reset controller driver for Realtek RTD1295 SoC. + config RESET_SOCFPGA bool "SoCFPGA Reset Driver" if COMPILE_TEST default ARCH_SOCFPGA diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index b62783f50fe5..bca900260a57 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o +obj-$(CONFIG_RESET_RTD129X) += reset-rtd129x.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o diff --git a/drivers/reset/reset-rtd129x.c b/drivers/reset/reset-rtd129x.c new file mode 100644 index 000000000000..d553900096c6 --- /dev/null +++ b/drivers/reset/reset-rtd129x.c @@ -0,0 +1,100 @@ +/* + * Realtek RTD129x reset controller + * + * Copyright (c) 2017 Andreas Färber + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +struct rtd129x_reset_controller { + struct reset_controller_dev rcdev; + void __iomem *base; + spinlock_t lock; +}; + +#define to_rtd129x_rcdev(_rcdev) \ + container_of(_rcdev, struct rtd129x_reset_controller, rcdev) + +static int rtd129x_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rtd129x_reset_controller *data = to_rtd129x_rcdev(rcdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&data->lock, flags); + + reg = readl(data->base); + writel(reg & ~BIT(id), data->base); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static int rtd129x_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rtd129x_reset_controller *data = to_rtd129x_rcdev(rcdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&data->lock, flags); + + reg = readl(data->base); + writel(reg | BIT(id), data->base); + + spin_unlock_irqrestore(&data->lock, flags); + + return 0; +} + +static const struct reset_control_ops rtd129x_reset_ops = { + .assert = rtd129x_reset_assert, + .deassert = rtd129x_reset_deassert, +}; + +static const struct of_device_id rtd129x_reset_dt_ids[] = { + { .compatible = "realtek,rtd1295-reset" }, + { } +}; + +static int rtd129x_reset_probe(struct platform_device *pdev) +{ + struct rtd129x_reset_controller *data; + struct resource *res; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + spin_lock_init(&data->lock); + + data->rcdev.owner = THIS_MODULE; + data->rcdev.nr_resets = 32; + data->rcdev.ops = &rtd129x_reset_ops; + data->rcdev.of_node = pdev->dev.of_node; + + return devm_reset_controller_register(&pdev->dev, &data->rcdev); +} + +static struct platform_driver rtd129x_reset_driver = { + .probe = rtd129x_reset_probe, + .driver = { + .name = "rtd129x-reset", + .of_match_table = rtd129x_reset_dt_ids, + }, +}; +builtin_platform_driver(rtd129x_reset_driver);
Add a per-register reset controller driver. This deals with the fact that not all registers are adjoined. Signed-off-by: Andreas Färber <afaerber@suse.de> --- drivers/reset/Kconfig | 6 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-rtd129x.c | 100 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 drivers/reset/reset-rtd129x.c