linux/drivers/reset/reset-stm32.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) Maxime Coquelin 2015
   3 * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
   4 * License terms:  GNU General Public License (GPL), version 2
   5 *
   6 * Heavily based on sunxi driver from Maxime Ripard.
   7 */
   8
   9#include <linux/err.h>
  10#include <linux/io.h>
  11#include <linux/of.h>
  12#include <linux/of_address.h>
  13#include <linux/platform_device.h>
  14#include <linux/reset-controller.h>
  15#include <linux/slab.h>
  16#include <linux/spinlock.h>
  17#include <linux/types.h>
  18
  19struct stm32_reset_data {
  20        spinlock_t                      lock;
  21        void __iomem                    *membase;
  22        struct reset_controller_dev     rcdev;
  23};
  24
  25static int stm32_reset_assert(struct reset_controller_dev *rcdev,
  26                              unsigned long id)
  27{
  28        struct stm32_reset_data *data = container_of(rcdev,
  29                                                     struct stm32_reset_data,
  30                                                     rcdev);
  31        int bank = id / BITS_PER_LONG;
  32        int offset = id % BITS_PER_LONG;
  33        unsigned long flags;
  34        u32 reg;
  35
  36        spin_lock_irqsave(&data->lock, flags);
  37
  38        reg = readl(data->membase + (bank * 4));
  39        writel(reg | BIT(offset), data->membase + (bank * 4));
  40
  41        spin_unlock_irqrestore(&data->lock, flags);
  42
  43        return 0;
  44}
  45
  46static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
  47                                unsigned long id)
  48{
  49        struct stm32_reset_data *data = container_of(rcdev,
  50                                                     struct stm32_reset_data,
  51                                                     rcdev);
  52        int bank = id / BITS_PER_LONG;
  53        int offset = id % BITS_PER_LONG;
  54        unsigned long flags;
  55        u32 reg;
  56
  57        spin_lock_irqsave(&data->lock, flags);
  58
  59        reg = readl(data->membase + (bank * 4));
  60        writel(reg & ~BIT(offset), data->membase + (bank * 4));
  61
  62        spin_unlock_irqrestore(&data->lock, flags);
  63
  64        return 0;
  65}
  66
  67static const struct reset_control_ops stm32_reset_ops = {
  68        .assert         = stm32_reset_assert,
  69        .deassert       = stm32_reset_deassert,
  70};
  71
  72static const struct of_device_id stm32_reset_dt_ids[] = {
  73         { .compatible = "st,stm32-rcc", },
  74         { /* sentinel */ },
  75};
  76
  77static int stm32_reset_probe(struct platform_device *pdev)
  78{
  79        struct stm32_reset_data *data;
  80        struct resource *res;
  81
  82        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  83        if (!data)
  84                return -ENOMEM;
  85
  86        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  87        data->membase = devm_ioremap_resource(&pdev->dev, res);
  88        if (IS_ERR(data->membase))
  89                return PTR_ERR(data->membase);
  90
  91        spin_lock_init(&data->lock);
  92
  93        data->rcdev.owner = THIS_MODULE;
  94        data->rcdev.nr_resets = resource_size(res) * 8;
  95        data->rcdev.ops = &stm32_reset_ops;
  96        data->rcdev.of_node = pdev->dev.of_node;
  97
  98        return devm_reset_controller_register(&pdev->dev, &data->rcdev);
  99}
 100
 101static struct platform_driver stm32_reset_driver = {
 102        .probe  = stm32_reset_probe,
 103        .driver = {
 104                .name           = "stm32-rcc-reset",
 105                .of_match_table = stm32_reset_dt_ids,
 106        },
 107};
 108builtin_platform_driver(stm32_reset_driver);
 109