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 #include "ccu.h"
7 #include "ccu_reset.h"
8 #include <hal_timer.h>
9 #include <hal_log.h>
10 #include <stdlib.h>
11
12 /* FIXME: use udelay provided by OS */
__clk_udelay(u32 ns)13 static void __clk_udelay(u32 ns)
14 {
15 u32 i;
16 ns *= 100;
17 for (i = 0; i < ns; i ++)
18 {
19 ;
20 }
21 }
22
ccu_reset_assert(struct reset_control_dev * rcdev,hal_reset_id_t id)23 static int ccu_reset_assert(struct reset_control_dev *rcdev,
24 hal_reset_id_t id)
25 {
26 struct ccu_reset *ccu = rc_to_ccu_reset(rcdev);
27 const struct ccu_reset_map *map = &ccu->reset_map[id];
28 u32 reg;
29 u32 __cspr;
30
31 __cspr = hal_spin_lock_irqsave(&ccu->lock);
32
33 reg = readl(ccu->base + map->reg);
34 writel(reg & ~map->bit, ccu->base + map->reg);
35
36 hal_spin_unlock_irqrestore(&ccu->lock, __cspr);
37
38 return 0;
39 }
40
ccu_reset_deassert(struct reset_control_dev * rcdev,hal_reset_id_t id)41 static int ccu_reset_deassert(struct reset_control_dev *rcdev,
42 hal_reset_id_t id)
43 {
44 struct ccu_reset *ccu = rc_to_ccu_reset(rcdev);
45
46 const struct ccu_reset_map *map = &ccu->reset_map[id];
47 u32 reg;
48 u32 __cspr;
49
50 __cspr = hal_spin_lock_irqsave(&ccu->lock);
51
52 reg = readl(ccu->base + map->reg);
53 writel(reg | map->bit, ccu->base + map->reg);
54
55 hal_spin_unlock_irqrestore(&ccu->lock, __cspr);
56
57 return 0;
58 }
59
ccu_reset_reset(struct reset_control_dev * rcdev,hal_reset_id_t id)60 static int ccu_reset_reset(struct reset_control_dev *rcdev,
61 hal_reset_id_t id)
62 {
63 ccu_reset_assert(rcdev, id);
64 __clk_udelay(10);
65 ccu_reset_deassert(rcdev, id);
66
67 return 0;
68 }
69
ccu_reset_status(struct reset_control_dev * rcdev,hal_reset_id_t id)70 static int ccu_reset_status(struct reset_control_dev *rcdev,
71 hal_reset_id_t id)
72 {
73 struct ccu_reset *ccu = rc_to_ccu_reset(rcdev);
74 const struct ccu_reset_map *map = &ccu->reset_map[id];
75
76 /*
77 * The reset control API expects 0 if reset is not asserted,
78 * which is the opposite of what our hardware uses.
79 */
80 return !(map->bit & readl(ccu->base + map->reg));
81 }
82
83 const struct reset_control_ops ccu_reset_ops =
84 {
85 .assert = ccu_reset_assert,
86 .deassert = ccu_reset_deassert,
87 .reset = ccu_reset_reset,
88 .status = ccu_reset_status,
89 };
90