Merge tag 'tegra-for-4.8-i2c' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra...
[cascardo/linux.git] / drivers / reset / reset-stm32.c
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
19 struct stm32_reset_data {
20         spinlock_t                      lock;
21         void __iomem                    *membase;
22         struct reset_controller_dev     rcdev;
23 };
24
25 static 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
46 static 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
67 static const struct reset_control_ops stm32_reset_ops = {
68         .assert         = stm32_reset_assert,
69         .deassert       = stm32_reset_deassert,
70 };
71
72 static const struct of_device_id stm32_reset_dt_ids[] = {
73          { .compatible = "st,stm32-rcc", },
74          { /* sentinel */ },
75 };
76
77 static 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
101 static 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 };
108 builtin_platform_driver(stm32_reset_driver);