From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753997AbcGDNso (ORCPT ); Mon, 4 Jul 2016 09:48:44 -0400 Received: from mx08-00178001.pphosted.com ([91.207.212.93]:54950 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753952AbcGDNsk (ORCPT ); Mon, 4 Jul 2016 09:48:40 -0400 From: To: Philipp Zabel , Rob Herring , Mark Rutland , Maxime Coquelin , Russell King , , CC: , , , Gabriel Fernandez Subject: [PATCH 3/4] drivers: reset: Add STM32 reset driver Date: Mon, 4 Jul 2016 15:47:31 +0200 Message-ID: <1467640052-6770-3-git-send-email-gabriel.fernandez@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1467640052-6770-1-git-send-email-gabriel.fernandez@st.com> References: <1467640052-6770-1-git-send-email-gabriel.fernandez@st.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.48.0.158] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2016-07-04_07:,, signatures=0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Gabriel Fernandez 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. Signed-off-by: Maxime Coquelin Signed-off-by: Gabriel Fernandez --- drivers/reset/Makefile | 1 + drivers/reset/reset-stm32.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 drivers/reset/reset-stm32.c diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 03dc1bb..3776b7b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_ARCH_MESON) += reset-meson.o +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c new file mode 100644 index 0000000..be42bff --- /dev/null +++ b/drivers/reset/reset-stm32.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) Maxime Coquelin 2015 + * Author: Maxime Coquelin + * License terms: GNU General Public License (GPL), version 2 + * + * Heavily based on sunxi driver from Maxime Ripard. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 const 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 */ }, +}; + +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 devm_reset_controller_register(&pdev->dev, &data->rcdev); +} + +static struct platform_driver stm32_reset_driver = { + .probe = stm32_reset_probe, + .driver = { + .name = "stm32-rcc-reset", + .of_match_table = stm32_reset_dt_ids, + }, +}; +module_platform_driver(stm32_reset_driver); + +MODULE_AUTHOR("Maxime Coquelin "); +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver"); +MODULE_LICENSE("GPL"); -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Subject: [PATCH 3/4] drivers: reset: Add STM32 reset driver Date: Mon, 4 Jul 2016 15:47:31 +0200 Message-ID: <1467640052-6770-3-git-send-email-gabriel.fernandez@st.com> References: <1467640052-6770-1-git-send-email-gabriel.fernandez@st.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1467640052-6770-1-git-send-email-gabriel.fernandez@st.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: Philipp Zabel , Rob Herring , Mark Rutland , Maxime Coquelin , Russell King , patrice.chotard@st.com, alexandre.torgue@st.com Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Gabriel Fernandez List-Id: devicetree@vger.kernel.org From: Gabriel Fernandez 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. Signed-off-by: Maxime Coquelin Signed-off-by: Gabriel Fernandez --- drivers/reset/Makefile | 1 + drivers/reset/reset-stm32.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 drivers/reset/reset-stm32.c diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 03dc1bb..3776b7b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_ARCH_MESON) += reset-meson.o +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c new file mode 100644 index 0000000..be42bff --- /dev/null +++ b/drivers/reset/reset-stm32.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) Maxime Coquelin 2015 + * Author: Maxime Coquelin + * License terms: GNU General Public License (GPL), version 2 + * + * Heavily based on sunxi driver from Maxime Ripard. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 const 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 */ }, +}; + +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 devm_reset_controller_register(&pdev->dev, &data->rcdev); +} + +static struct platform_driver stm32_reset_driver = { + .probe = stm32_reset_probe, + .driver = { + .name = "stm32-rcc-reset", + .of_match_table = stm32_reset_dt_ids, + }, +}; +module_platform_driver(stm32_reset_driver); + +MODULE_AUTHOR("Maxime Coquelin "); +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver"); +MODULE_LICENSE("GPL"); -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: gabriel.fernandez@st.com (gabriel.fernandez at st.com) Date: Mon, 4 Jul 2016 15:47:31 +0200 Subject: [PATCH 3/4] drivers: reset: Add STM32 reset driver In-Reply-To: <1467640052-6770-1-git-send-email-gabriel.fernandez@st.com> References: <1467640052-6770-1-git-send-email-gabriel.fernandez@st.com> Message-ID: <1467640052-6770-3-git-send-email-gabriel.fernandez@st.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org From: Gabriel Fernandez 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. Signed-off-by: Maxime Coquelin Signed-off-by: Gabriel Fernandez --- drivers/reset/Makefile | 1 + drivers/reset/reset-stm32.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 drivers/reset/reset-stm32.c diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 03dc1bb..3776b7b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_ARCH_MESON) += reset-meson.o +obj-$(CONFIG_ARCH_STM32) += reset-stm32.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c new file mode 100644 index 0000000..be42bff --- /dev/null +++ b/drivers/reset/reset-stm32.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) Maxime Coquelin 2015 + * Author: Maxime Coquelin + * License terms: GNU General Public License (GPL), version 2 + * + * Heavily based on sunxi driver from Maxime Ripard. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 const 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 */ }, +}; + +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 devm_reset_controller_register(&pdev->dev, &data->rcdev); +} + +static struct platform_driver stm32_reset_driver = { + .probe = stm32_reset_probe, + .driver = { + .name = "stm32-rcc-reset", + .of_match_table = stm32_reset_dt_ids, + }, +}; +module_platform_driver(stm32_reset_driver); + +MODULE_AUTHOR("Maxime Coquelin "); +MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver"); +MODULE_LICENSE("GPL"); -- 1.9.1