diff mbox

[v2,2/5] reset: socfpga: use the reset-simple driver

Message ID 20170811130618.3676-3-p.zabel@pengutronix.de (mailing list archive)
State New, archived
Headers show

Commit Message

Philipp Zabel Aug. 11, 2017, 1:06 p.m. UTC
Add reset line status readback, inverted status support, and socfpga
device tree quirks to the simple reset driver, and use it to replace
the socfpga driver.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

fixup! reset: socfpga: use the reset-simple driver
---
 drivers/reset/Kconfig         |  10 +--
 drivers/reset/Makefile        |   1 -
 drivers/reset/reset-simple.c  |  51 +++++++++++++-
 drivers/reset/reset-simple.h  |   1 +
 drivers/reset/reset-socfpga.c | 154 ------------------------------------------
 5 files changed, 53 insertions(+), 164 deletions(-)
 delete mode 100644 drivers/reset/reset-socfpga.c

Comments

Alexandru Gagniuc Aug. 11, 2017, 4:28 p.m. UTC | #1
Hi Phillip,

On 08/11/2017 06:06 AM, Philipp Zabel wrote:
[snip]

> @@ -113,8 +137,33 @@ static int reset_simple_probe(struct platform_device *pdev)
>  	data->rcdev.ops = &reset_simple_ops;
>  	data->rcdev.of_node = dev->of_node;
>
> -	if (devdata)
> +	if (devdata == &reset_simple_socfpga) {

This sort of special-case handling opens the gate to adding special-case 
handling for any new device, which somewhat defeats the purpose of a 
generic driver.

> +		u32 modrst_offset;
> +
> +		/*
> +		 * The binding was mainlined without the required property.
> +		 * Do not continue, when we encounter an old DT.
> +		 */
> +		if (!of_find_property(dev->of_node, "#reset-cells", NULL)) {
> +			dev_err(dev, "%pOF missing #reset-cells property\n",
> +				dev->of_node);
> +			return -EINVAL;
> +		}

Is the check still required in this context, since 
(devm_)reset_control_get() complains really loudly if #reset-cells is 
missing?

> +
> +		if (of_property_read_u32(dev->of_node, "altr,modrst-offset",
> +					 &modrst_offset)) {
> +			dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
> +			modrst_offset = 0x10;
> +		}

This can be a generic "reg-offset" property. If and until the 
devicetrees are updated, "altr,modrst-offset" would also have to be read 
as an alternative. Since a platform data already exists, 
reset_simple_devdata could be a better place to store the default offset 
of 0x10 for socfpga.

Alex
Philipp Zabel Aug. 11, 2017, 4:50 p.m. UTC | #2
Hi Alexandru,

thank you for the comments.

On Fri, 2017-08-11 at 09:28 -0700, Alexandru Gagniuc wrote:
> Hi Phillip,
> 
> On 08/11/2017 06:06 AM, Philipp Zabel wrote:
> [snip]
> 
> > @@ -113,8 +137,33 @@ static int reset_simple_probe(struct platform_device *pdev)
> > > >  	data->rcdev.ops = &reset_simple_ops;
> > > >  	data->rcdev.of_node = dev->of_node;
> > 
> > > > -	if (devdata)
> > +	if (devdata == &reset_simple_socfpga) {
> 
> This sort of special-case handling opens the gate to adding special-case 
> handling for any new device, which somewhat defeats the purpose of a 
> generic driver.

That is why I initially only unified the reset ops and not the whole
platorm driver.

I could partially revert this latest change and keep the reset-socfpga
driver, just reusing the reset-simple ops to avoid potential "quirk
creep" in the reset-simple driver.

Or I could drop the #reset-cells warning below and just read the
altr,modrst-offset property for any reset controller, to avoid the
special-case.

> > +		u32 modrst_offset;
> > +
> > > > +		/*
> > > > +		 * The binding was mainlined without the required property.
> > > > +		 * Do not continue, when we encounter an old DT.
> > > > +		 */
> > > > +		if (!of_find_property(dev->of_node, "#reset-cells", NULL)) {
> > > > +			dev_err(dev, "%pOF missing #reset-cells property\n",
> > > > +				dev->of_node);
> > > > +			return -EINVAL;
> > > > +		}
> 
> Is the check still required in this context, since 
> (devm_)reset_control_get() complains really loudly if #reset-cells is 
> missing?

I'm fine with removing this. Ideally, this is something that the device
tree compiler should check already.

> > +
> > > > +		if (of_property_read_u32(dev->of_node, "altr,modrst-offset",
> > > > +					 &modrst_offset)) {
> > > > +			dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
> > > > +			modrst_offset = 0x10;
> > +		}
> 
> This can be a generic "reg-offset" property. If and until the 
> devicetrees are updated, "altr,modrst-offset" would also have to be read 
> as an alternative.

Possibly. Adding new device tree bindings is a separate discussion.

> Since a platform data already exists, reset_simple_devdata could be a
> better place to store the default offset of 0x10 for socfpga.

I'll change this as you suggest.

regards
Philipp
diff mbox

Patch

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index f7ba01a71daee..78a8f6057985b 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -70,19 +70,13 @@  config RESET_PISTACHIO
 
 config RESET_SIMPLE
 	bool "Simple Reset Controller Driver" if COMPILE_TEST
-	default ARCH_SUNXI
+	default ARCH_SOCFPGA || ARCH_SUNXI
 	help
 	  This enables a simple reset controller driver for reset lines that
 	  that can be asserted and deasserted by toggling bits in a contiguous,
 	  exclusive register space.
 
-	  Currently this driver supports Allwinner SoCs.
-
-config RESET_SOCFPGA
-	bool "SoCFPGA Reset Driver" if COMPILE_TEST
-	default ARCH_SOCFPGA
-	help
-	  This enables the reset controller driver for Altera SoCFPGAs.
+	  Currently this driver supports Altera SoCFPGAs and Allwinner SoCs.
 
 config RESET_STM32
 	bool "STM32 Reset Driver" if COMPILE_TEST
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index ab4af99c3dfdc..25f5f722dec01 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -12,7 +12,6 @@  obj-$(CONFIG_RESET_MESON) += reset-meson.o
 obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
 obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
-obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_RESET_STM32) += reset-stm32.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c
index 08fc79d79e86d..e553d434ca362 100644
--- a/drivers/reset/reset-simple.c
+++ b/drivers/reset/reset-simple.c
@@ -68,25 +68,49 @@  static int reset_simple_deassert(struct reset_controller_dev *rcdev,
 	return reset_simple_set(rcdev, id, false);
 }
 
+static int reset_simple_status(struct reset_controller_dev *rcdev,
+			       unsigned long id)
+{
+	struct reset_simple_data *data = to_reset_simple_data(rcdev);
+	int reg_width = sizeof(u32);
+	int bank = id / (reg_width * BITS_PER_BYTE);
+	int offset = id % (reg_width * BITS_PER_BYTE);
+	u32 reg;
+
+	reg = readl(data->membase + (bank * reg_width));
+
+	return !(reg & BIT(offset)) ^ !data->status_inverted;
+}
+
 const struct reset_control_ops reset_simple_ops = {
 	.assert		= reset_simple_assert,
 	.deassert	= reset_simple_deassert,
+	.status		= reset_simple_status,
 };
 
 struct reset_simple_devdata {
 	bool inverted;
+	bool status_inverted;
+};
+
+static const struct reset_simple_devdata reset_simple_socfpga = {
+	.status_inverted = true,
 };
 
 static const struct reset_simple_devdata reset_simple_inverted = {
 	.inverted = true,
+	.status_inverted = true,
 };
 
 static const struct of_device_id reset_simple_dt_ids[] = {
+	{ .compatible = "altr,rst-mgr", .data = &reset_simple_socfpga },
 	{ .compatible = "allwinner,sun6i-a31-clock-reset",
 		.data = &reset_simple_inverted },
 	{ /* sentinel */ },
 };
 
+#define SOCFPGA_NR_BANKS		8
+
 static int reset_simple_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -113,8 +137,33 @@  static int reset_simple_probe(struct platform_device *pdev)
 	data->rcdev.ops = &reset_simple_ops;
 	data->rcdev.of_node = dev->of_node;
 
-	if (devdata)
+	if (devdata == &reset_simple_socfpga) {
+		u32 modrst_offset;
+
+		/*
+		 * The binding was mainlined without the required property.
+		 * Do not continue, when we encounter an old DT.
+		 */
+		if (!of_find_property(dev->of_node, "#reset-cells", NULL)) {
+			dev_err(dev, "%pOF missing #reset-cells property\n",
+				dev->of_node);
+			return -EINVAL;
+		}
+
+		if (of_property_read_u32(dev->of_node, "altr,modrst-offset",
+					 &modrst_offset)) {
+			dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
+			modrst_offset = 0x10;
+		}
+
+		data->membase += modrst_offset;
+		data->rcdev.nr_resets = SOCFPGA_NR_BANKS * 32;
+	}
+
+	if (devdata) {
 		data->inverted = devdata->inverted;
+		data->status_inverted = devdata->status_inverted;
+	}
 
 	return devm_reset_controller_register(dev, &data->rcdev);
 }
diff --git a/drivers/reset/reset-simple.h b/drivers/reset/reset-simple.h
index a26dc62b2f349..52dc28d4ffac3 100644
--- a/drivers/reset/reset-simple.h
+++ b/drivers/reset/reset-simple.h
@@ -25,6 +25,7 @@  struct reset_simple_data {
 	void __iomem			*membase;
 	struct reset_controller_dev	rcdev;
 	bool				inverted;
+	bool				status_inverted;
 };
 
 extern const struct reset_control_ops reset_simple_ops;
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
deleted file mode 100644
index 07224c0198920..0000000000000
--- a/drivers/reset/reset-socfpga.c
+++ /dev/null
@@ -1,154 +0,0 @@ 
-/*
- * Socfpga Reset Controller Driver
- *
- * Copyright 2014 Steffen Trumtrar <s.trumtrar@pengutronix.de>
- *
- * based on
- * Allwinner SoCs Reset Controller driver
- *
- * Copyright 2013 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * 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/err.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/reset-controller.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#define BANK_INCREMENT		4
-#define NR_BANKS		8
-
-struct socfpga_reset_data {
-	spinlock_t			lock;
-	void __iomem			*membase;
-	struct reset_controller_dev	rcdev;
-};
-
-static int socfpga_reset_assert(struct reset_controller_dev *rcdev,
-				unsigned long id)
-{
-	struct socfpga_reset_data *data = container_of(rcdev,
-						     struct socfpga_reset_data,
-						     rcdev);
-	int bank = id / BITS_PER_LONG;
-	int offset = id % BITS_PER_LONG;
-	unsigned long flags;
-	u32 reg;
-
-	spin_lock_irqsave(&data->lock, flags);
-
-	reg = readl(data->membase + (bank * BANK_INCREMENT));
-	writel(reg | BIT(offset), data->membase + (bank * BANK_INCREMENT));
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	return 0;
-}
-
-static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
-				  unsigned long id)
-{
-	struct socfpga_reset_data *data = container_of(rcdev,
-						     struct socfpga_reset_data,
-						     rcdev);
-
-	int bank = id / BITS_PER_LONG;
-	int offset = id % BITS_PER_LONG;
-	unsigned long flags;
-	u32 reg;
-
-	spin_lock_irqsave(&data->lock, flags);
-
-	reg = readl(data->membase + (bank * BANK_INCREMENT));
-	writel(reg & ~BIT(offset), data->membase + (bank * BANK_INCREMENT));
-
-	spin_unlock_irqrestore(&data->lock, flags);
-
-	return 0;
-}
-
-static int socfpga_reset_status(struct reset_controller_dev *rcdev,
-				unsigned long id)
-{
-	struct socfpga_reset_data *data = container_of(rcdev,
-						struct socfpga_reset_data, rcdev);
-	int bank = id / BITS_PER_LONG;
-	int offset = id % BITS_PER_LONG;
-	u32 reg;
-
-	reg = readl(data->membase + (bank * BANK_INCREMENT));
-
-	return !(reg & BIT(offset));
-}
-
-static const struct reset_control_ops socfpga_reset_ops = {
-	.assert		= socfpga_reset_assert,
-	.deassert	= socfpga_reset_deassert,
-	.status		= socfpga_reset_status,
-};
-
-static int socfpga_reset_probe(struct platform_device *pdev)
-{
-	struct socfpga_reset_data *data;
-	struct resource *res;
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
-	u32 modrst_offset;
-
-	/*
-	 * The binding was mainlined without the required property.
-	 * Do not continue, when we encounter an old DT.
-	 */
-	if (!of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) {
-		dev_err(&pdev->dev, "%s missing #reset-cells property\n",
-			pdev->dev.of_node->full_name);
-		return -EINVAL;
-	}
-
-	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	data->membase = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(data->membase))
-		return PTR_ERR(data->membase);
-
-	if (of_property_read_u32(np, "altr,modrst-offset", &modrst_offset)) {
-		dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
-		modrst_offset = 0x10;
-	}
-	data->membase += modrst_offset;
-
-	spin_lock_init(&data->lock);
-
-	data->rcdev.owner = THIS_MODULE;
-	data->rcdev.nr_resets = NR_BANKS * BITS_PER_LONG;
-	data->rcdev.ops = &socfpga_reset_ops;
-	data->rcdev.of_node = pdev->dev.of_node;
-
-	return devm_reset_controller_register(dev, &data->rcdev);
-}
-
-static const struct of_device_id socfpga_reset_dt_ids[] = {
-	{ .compatible = "altr,rst-mgr", },
-	{ /* sentinel */ },
-};
-
-static struct platform_driver socfpga_reset_driver = {
-	.probe	= socfpga_reset_probe,
-	.driver = {
-		.name		= "socfpga-reset",
-		.of_match_table	= socfpga_reset_dt_ids,
-	},
-};
-builtin_platform_driver(socfpga_reset_driver);