diff mbox

[3/4] drivers: reset: Add STM32 reset driver

Message ID 1467640052-6770-3-git-send-email-gabriel.fernandez@st.com (mailing list archive)
State New, archived
Headers show

Commit Message

Gabriel FERNANDEZ July 4, 2016, 1:47 p.m. UTC
From: Gabriel Fernandez <gabriel.fernandez@st.com>

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 <mcoquelin.stm32@gmail.com>
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
---
 drivers/reset/Makefile      |   1 +
 drivers/reset/reset-stm32.c | 113 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 114 insertions(+)
 create mode 100644 drivers/reset/reset-stm32.c

Comments

Philipp Zabel July 4, 2016, 5:36 p.m. UTC | #1
Hi Gabriel,

Am Montag, den 04.07.2016, 15:47 +0200 schrieb gabriel.fernandez@st.com:
> From: Gabriel Fernandez <gabriel.fernandez@st.com>

Isn't Maxime the author of this 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.
> 
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---
>  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
[...]
> +static const struct reset_control_ops stm32_reset_ops = {
> +	.assert		= stm32_reset_assert,
> +	.deassert	= stm32_reset_deassert,

Are the registers not readable, or did you choose not to
implement .status on purpose?

regards
Philipp
Gabriel FERNANDEZ July 5, 2016, 7:29 a.m. UTC | #2
Hi Philipp,

Thanks for reviewing.

On 07/04/2016 07:36 PM, Philipp Zabel wrote:
> Hi Gabriel,
>
> Am Montag, den 04.07.2016, 15:47 +0200 schrieb gabriel.fernandez@st.com:
>> From: Gabriel Fernandez <gabriel.fernandez@st.com>
> Isn't Maxime the author of this driver?
Yes i upstream with his agreement.
I only made small modifications (use of devm_reset_controller_register(),
make reset_control_ops const...) that's why the author in the git 
history has
been changed... I will use g |it commit  --amend --author="Maxime.." for 
the v2.
|
>> 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 <mcoquelin.stm32@gmail.com>
>> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
>> ---
>>   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
> [...]
>> +static const struct reset_control_ops stm32_reset_ops = {
>> +	.assert		= stm32_reset_assert,
>> +	.deassert	= stm32_reset_deassert,
> Are the registers not readable, or did you choose not to
> implement .status on purpose?
We choose to not implement.

Thanks!

Best Regards

Gabriel

> regards
> Philipp
>
Philipp Zabel July 5, 2016, 1:28 p.m. UTC | #3
Am Montag, den 04.07.2016, 15:47 +0200 schrieb gabriel.fernandez@st.com:
> From: Gabriel Fernandez <gabriel.fernandez@st.com>
> 
> 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 <mcoquelin.stm32@gmail.com>
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---
>  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 <mcoquelin.stm32@gmail.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));

Please also switch to the non-relaxed variants. It shouldn't make a
difference here, and as Arnd points out, reduces the risk of new
developers using readl/writel_relaxed without thinking about the
consequences.
Further, this will make the stm32, sunxi, and socfpga accessors look the
same. I'd like to try and combine them after this is merged.

regards
Philipp
Philipp Zabel July 5, 2016, 1:29 p.m. UTC | #4
Am Dienstag, den 05.07.2016, 09:29 +0200 schrieb Gabriel Fernandez:
[...]
> >> +static const struct reset_control_ops stm32_reset_ops = {
> >> +	.assert		= stm32_reset_assert,
> >> +	.deassert	= stm32_reset_deassert,
> > Are the registers not readable, or did you choose not to
> > implement .status on purpose?
> We choose to not implement.

Ok. Because of size issues or just because you don't need them in any of
your drivers?

regards
Philipp
Gabriel FERNANDEZ July 6, 2016, 7:44 a.m. UTC | #5
Hi Philipp,

On 07/05/2016 03:28 PM, Philipp Zabel wrote:
> Am Montag, den 04.07.2016, 15:47 +0200 schrieb gabriel.fernandez@st.com:
>> From: Gabriel Fernandez <gabriel.fernandez@st.com>
>>
>> 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 <mcoquelin.stm32@gmail.com>
>> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
>> ---
>>   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 <mcoquelin.stm32@gmail.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));
> Please also switch to the non-relaxed variants. It shouldn't make a
> difference here, and as Arnd points out, reduces the risk of new
> developers using readl/writel_relaxed without thinking about the
> consequences.
> Further, this will make the stm32, sunxi, and socfpga accessors look the
> same. I'd like to try and combine them after this is merged.
>
> regards
> Philipp
>
ok no problem, i will fix it.

Thanks

Gabriel
Gabriel FERNANDEZ July 6, 2016, 3:39 p.m. UTC | #6
Hi Philipp

On 07/05/2016 03:29 PM, Philipp Zabel wrote:
> Am Dienstag, den 05.07.2016, 09:29 +0200 schrieb Gabriel Fernandez:
> [...]
>>>> +static const struct reset_control_ops stm32_reset_ops = {
>>>> +	.assert		= stm32_reset_assert,
>>>> +	.deassert	= stm32_reset_deassert,
>>> Are the registers not readable, or did you choose not to
>>> implement .status on purpose?
>> We choose to not implement.
> Ok. Because of size issues or just because you don't need them in any of
> your drivers?
Because i don't need them.

BR

Gabriel

>
> regards
> Philipp
>
Philipp Zabel July 6, 2016, 3:43 p.m. UTC | #7
Am Mittwoch, den 06.07.2016, 17:39 +0200 schrieb Gabriel Fernandez:
> Hi Philipp
> 
> On 07/05/2016 03:29 PM, Philipp Zabel wrote:
> > Am Dienstag, den 05.07.2016, 09:29 +0200 schrieb Gabriel Fernandez:
> > [...]
> >>>> +static const struct reset_control_ops stm32_reset_ops = {
> >>>> +	.assert		= stm32_reset_assert,
> >>>> +	.deassert	= stm32_reset_deassert,
> >>> Are the registers not readable, or did you choose not to
> >>> implement .status on purpose?
> >> We choose to not implement.
> > Ok. Because of size issues or just because you don't need them in any of
> > your drivers?
> Because i don't need them.

Ok, thanks for clarifying.

regards
Philipp
diff mbox

Patch

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 <mcoquelin.stm32@gmail.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 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 <maxime.coquelin@gmail.com>");
+MODULE_DESCRIPTION("STM32 MCUs Reset Controller Driver");
+MODULE_LICENSE("GPL");