linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] reset: meson: add level reset support for GX SoC family
@ 2017-10-17 10:19 Neil Armstrong
  2017-10-17 11:07 ` Philipp Zabel
  0 siblings, 1 reply; 2+ messages in thread
From: Neil Armstrong @ 2017-10-17 10:19 UTC (permalink / raw)
  To: linux-arm-kernel

The Amlogic GX SoC family embeds alternate registers to drive the reset
levels next to the pulse registers.

This patch adds support for level reset handling on the GX family only.

The Meson8 family has an alternate way to handle level reset.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/reset/reset-meson.c | 62 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 58 insertions(+), 4 deletions(-)

Changes since v1:
- protected read/change/modify with a spinlock
- removed unnedded check
- remove useless type conversion

diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c
index a8b915e..f3b9d69 100644
--- a/drivers/reset/reset-meson.c
+++ b/drivers/reset/reset-meson.c
@@ -62,13 +62,16 @@
 #include <linux/reset-controller.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/of_device.h>
 
 #define REG_COUNT	8
 #define BITS_PER_REG	32
+#define LEVEL_OFFSET	0x7c
 
 struct meson_reset {
 	void __iomem *reg_base;
 	struct reset_controller_dev rcdev;
+	spinlock_t lock;
 };
 
 static int meson_reset_reset(struct reset_controller_dev *rcdev,
@@ -88,18 +91,63 @@ static int meson_reset_reset(struct reset_controller_dev *rcdev,
 	return 0;
 }
 
-static const struct reset_control_ops meson_reset_ops = {
+static int meson_reset_level(struct reset_controller_dev *rcdev,
+			    unsigned long id, bool assert)
+{
+	struct meson_reset *data =
+		container_of(rcdev, struct meson_reset, rcdev);
+	unsigned int bank = id / BITS_PER_REG;
+	unsigned int offset = id % BITS_PER_REG;
+	void __iomem *reg_addr = data->reg_base + LEVEL_OFFSET + (bank << 2);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl(reg_addr);
+	if (assert)
+		writel(reg & ~BIT(offset), reg_addr);
+	else
+		writel(reg | BIT(offset), reg_addr);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int meson_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	return meson_reset_level(rcdev, id, true);
+}
+
+static int meson_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	return meson_reset_level(rcdev, id, false);
+}
+
+static const struct reset_control_ops meson_reset_meson8_ops = {
 	.reset		= meson_reset_reset,
 };
 
+static const struct reset_control_ops meson_reset_gx_ops = {
+	.reset		= meson_reset_reset,
+	.assert		= meson_reset_assert,
+	.deassert	= meson_reset_deassert,
+};
+
 static const struct of_device_id meson_reset_dt_ids[] = {
-	 { .compatible = "amlogic,meson8b-reset", },
-	 { .compatible = "amlogic,meson-gxbb-reset", },
+	 { .compatible = "amlogic,meson8b-reset",
+	   .data = &meson_reset_meson8_ops, },
+	 { .compatible = "amlogic,meson-gxbb-reset",
+	   .data = &meson_reset_gx_ops, },
 	 { /* sentinel */ },
 };
 
 static int meson_reset_probe(struct platform_device *pdev)
 {
+	const struct reset_control_ops *ops;
 	struct meson_reset *data;
 	struct resource *res;
 
@@ -107,6 +155,10 @@ static int meson_reset_probe(struct platform_device *pdev)
 	if (!data)
 		return -ENOMEM;
 
+	ops = of_device_get_match_data(&pdev->dev);
+	if (!ops)
+		return -EINVAL;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	data->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(data->reg_base))
@@ -114,9 +166,11 @@ static int meson_reset_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, data);
 
+	spin_lock_init(&data->lock);
+
 	data->rcdev.owner = THIS_MODULE;
 	data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG;
-	data->rcdev.ops = &meson_reset_ops;
+	data->rcdev.ops = ops;
 	data->rcdev.of_node = pdev->dev.of_node;
 
 	return devm_reset_controller_register(&pdev->dev, &data->rcdev);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH v2] reset: meson: add level reset support for GX SoC family
  2017-10-17 10:19 [PATCH v2] reset: meson: add level reset support for GX SoC family Neil Armstrong
@ 2017-10-17 11:07 ` Philipp Zabel
  0 siblings, 0 replies; 2+ messages in thread
From: Philipp Zabel @ 2017-10-17 11:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2017-10-17 at 12:19 +0200, Neil Armstrong wrote:
> The Amlogic GX SoC family embeds alternate registers to drive the reset
> levels next to the pulse registers.
> 
> This patch adds support for level reset handling on the GX family only.
> 
> The Meson8 family has an alternate way to handle level reset.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Applied both to reset/next, thanks!

regards
Philipp

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-10-17 11:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-17 10:19 [PATCH v2] reset: meson: add level reset support for GX SoC family Neil Armstrong
2017-10-17 11:07 ` Philipp Zabel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).