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