[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1431158038-3813-8-git-send-email-mcoquelin.stm32@gmail.com>
Date: Sat, 9 May 2015 09:53:49 +0200
From: Maxime Coquelin <mcoquelin.stm32@...il.com>
To: u.kleine-koenig@...gutronix.de, afaerber@...e.de,
geert@...ux-m68k.org, Rob Herring <robh+dt@...nel.org>,
Philipp Zabel <p.zabel@...gutronix.de>,
Linus Walleij <linus.walleij@...aro.org>,
Arnd Bergmann <arnd@...db.de>, stefan@...er.ch,
pmeerw@...erw.net, pebolle@...cali.nl, peter@...leysoftware.com,
andy.shevchenko@...il.com, cw00.choi@...sung.com,
Russell King <linux@....linux.org.uk>,
Daniel Lezcano <daniel.lezcano@...aro.org>, joe@...ches.com,
Vladimir Zapolskiy <vladimir_zapolskiy@...tor.com>,
lee.jones@...aro.org, Daniel Thompson <daniel.thompson@...aro.org>
Cc: Jonathan Corbet <corbet@....net>, Pawel Moll <pawel.moll@....com>,
Mark Rutland <mark.rutland@....com>,
Ian Campbell <ijc+devicetree@...lion.org.uk>,
Kumar Gala <galak@...eaurora.org>,
Thomas Gleixner <tglx@...utronix.de>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Jiri Slaby <jslaby@...e.cz>,
Andrew Morton <akpm@...ux-foundation.org>,
"David S. Miller" <davem@...emloft.net>,
Mauro Carvalho Chehab <mchehab@....samsung.com>,
Antti Palosaari <crope@....fi>, Tejun Heo <tj@...nel.org>,
Will Deacon <will.deacon@....com>,
Nikolay Borisov <Nikolay.Borisov@....com>,
Rusty Russell <rusty@...tcorp.com.au>,
Kees Cook <keescook@...omium.org>,
Michal Marek <mmarek@...e.cz>, linux-doc@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org, linux-kernel@...r.kernel.org,
devicetree@...r.kernel.org, linux-gpio@...r.kernel.org,
linux-serial@...r.kernel.org, linux-arch@...r.kernel.org,
linux-api@...r.kernel.org, mcoquelin.stm32@...il.com,
Nicolae Rosia <nicolae.rosia@...il.com>,
Kamil Lulko <rev13@...pl>
Subject: [PATCH v8 07/16] drivers: reset: Add STM32 reset driver
The STM32 MCUs family IPs can be reset by accessing some registers
from the RCC block.
The list of available reset lines is documented in the DT bindings.
Tested-by: Chanwoo Choi <cw00.choi@...sung.com>
Acked-by: Philipp Zabel <p.zabel@...gutronix.de>
Signed-off-by: Maxime Coquelin <mcoquelin.stm32@...il.com>
---
drivers/reset/Makefile | 1 +
drivers/reset/reset-stm32.c | 124 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+)
create mode 100644 drivers/reset/reset-stm32.c
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 157d421..aed12d1 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_RESET_CONTROLLER) += core.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
+obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 0000000..2c41858
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@...il.com>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Heavily based on sunxi driver from Maxime Ripard.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct stm32_reset_data {
+ spinlock_t lock;
+ void __iomem *membase;
+ struct reset_controller_dev rcdev;
+};
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct stm32_reset_data *data = container_of(rcdev,
+ struct stm32_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_relaxed(data->membase + (bank * 4));
+ writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct stm32_reset_data *data = container_of(rcdev,
+ struct stm32_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_relaxed(data->membase + (bank * 4));
+ writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ return 0;
+}
+
+static struct reset_control_ops stm32_reset_ops = {
+ .assert = stm32_reset_assert,
+ .deassert = stm32_reset_deassert,
+};
+
+static const struct of_device_id stm32_reset_dt_ids[] = {
+ { .compatible = "st,stm32-rcc", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sstm32_reset_dt_ids);
+
+static int stm32_reset_probe(struct platform_device *pdev)
+{
+ struct stm32_reset_data *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->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->membase))
+ return PTR_ERR(data->membase);
+
+ spin_lock_init(&data->lock);
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.nr_resets = resource_size(res) * 8;
+ data->rcdev.ops = &stm32_reset_ops;
+ data->rcdev.of_node = pdev->dev.of_node;
+
+ return reset_controller_register(&data->rcdev);
+}
+
+static int stm32_reset_remove(struct platform_device *pdev)
+{
+ struct stm32_reset_data *data = platform_get_drvdata(pdev);
+
+ reset_controller_unregister(&data->rcdev);
+
+ return 0;
+}
+
+static struct platform_driver stm32_reset_driver = {
+ .probe = stm32_reset_probe,
+ .remove = stm32_reset_remove,
+ .driver = {
+ .name = "stm32-rcc-reset",
+ .of_match_table = stm32_reset_dt_ids,
+ },
+};
+module_platform_driver(stm32_reset_driver);
+
+MODULE_AUTHOR("Maxime Coquelin <maxime.coquelin@...il.com>");
+MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
+MODULE_LICENSE("GPL");
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists