GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / clk / sunxi-ng / ccu_reset.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2016 Maxime Ripard
4  * Maxime Ripard <maxime.ripard@free-electrons.com>
5  */
6
7 #include <linux/delay.h>
8 #include <linux/io.h>
9 #include <linux/reset-controller.h>
10
11 #include "ccu_reset.h"
12
13 static int ccu_reset_assert(struct reset_controller_dev *rcdev,
14                             unsigned long id)
15 {
16         struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev);
17         const struct ccu_reset_map *map = &ccu->reset_map[id];
18         unsigned long flags;
19         u32 reg;
20
21         spin_lock_irqsave(ccu->lock, flags);
22
23         reg = readl(ccu->base + map->reg);
24         writel(reg & ~map->bit, ccu->base + map->reg);
25
26         spin_unlock_irqrestore(ccu->lock, flags);
27
28         return 0;
29 }
30
31 static int ccu_reset_deassert(struct reset_controller_dev *rcdev,
32                               unsigned long id)
33 {
34         struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev);
35         const struct ccu_reset_map *map = &ccu->reset_map[id];
36         unsigned long flags;
37         u32 reg;
38
39         spin_lock_irqsave(ccu->lock, flags);
40
41         reg = readl(ccu->base + map->reg);
42         writel(reg | map->bit, ccu->base + map->reg);
43
44         spin_unlock_irqrestore(ccu->lock, flags);
45
46         return 0;
47 }
48
49 static int ccu_reset_reset(struct reset_controller_dev *rcdev,
50                            unsigned long id)
51 {
52         ccu_reset_assert(rcdev, id);
53         udelay(10);
54         ccu_reset_deassert(rcdev, id);
55
56         return 0;
57 }
58
59 static int ccu_reset_status(struct reset_controller_dev *rcdev,
60                             unsigned long id)
61 {
62         struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev);
63         const struct ccu_reset_map *map = &ccu->reset_map[id];
64
65         /*
66          * The reset control API expects 0 if reset is not asserted,
67          * which is the opposite of what our hardware uses.
68          */
69         return !(map->bit & readl(ccu->base + map->reg));
70 }
71
72 const struct reset_control_ops ccu_reset_ops = {
73         .assert         = ccu_reset_assert,
74         .deassert       = ccu_reset_deassert,
75         .reset          = ccu_reset_reset,
76         .status         = ccu_reset_status,
77 };
78 EXPORT_SYMBOL_NS_GPL(ccu_reset_ops, SUNXI_CCU);