1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/slab.h> |
3 | #include <linux/io.h> |
4 | #include <linux/of.h> |
5 | #include <linux/of_address.h> |
6 | #include <linux/reset-controller.h> |
7 | |
8 | #include "reset.h" |
9 | |
10 | #define rcdev_to_unit(rcdev) container_of(rcdev, struct mmp_clk_reset_unit, rcdev) |
11 | |
12 | static int mmp_of_reset_xlate(struct reset_controller_dev *rcdev, |
13 | const struct of_phandle_args *reset_spec) |
14 | { |
15 | struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); |
16 | struct mmp_clk_reset_cell *cell; |
17 | int i; |
18 | |
19 | if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) |
20 | return -EINVAL; |
21 | |
22 | for (i = 0; i < rcdev->nr_resets; i++) { |
23 | cell = &unit->cells[i]; |
24 | if (cell->clk_id == reset_spec->args[0]) |
25 | break; |
26 | } |
27 | |
28 | if (i == rcdev->nr_resets) |
29 | return -EINVAL; |
30 | |
31 | return i; |
32 | } |
33 | |
34 | static int mmp_clk_reset_assert(struct reset_controller_dev *rcdev, |
35 | unsigned long id) |
36 | { |
37 | struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); |
38 | struct mmp_clk_reset_cell *cell; |
39 | unsigned long flags = 0; |
40 | u32 val; |
41 | |
42 | cell = &unit->cells[id]; |
43 | if (cell->lock) |
44 | spin_lock_irqsave(cell->lock, flags); |
45 | |
46 | val = readl(addr: cell->reg); |
47 | val |= cell->bits; |
48 | writel(val, addr: cell->reg); |
49 | |
50 | if (cell->lock) |
51 | spin_unlock_irqrestore(lock: cell->lock, flags); |
52 | |
53 | return 0; |
54 | } |
55 | |
56 | static int mmp_clk_reset_deassert(struct reset_controller_dev *rcdev, |
57 | unsigned long id) |
58 | { |
59 | struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); |
60 | struct mmp_clk_reset_cell *cell; |
61 | unsigned long flags = 0; |
62 | u32 val; |
63 | |
64 | cell = &unit->cells[id]; |
65 | if (cell->lock) |
66 | spin_lock_irqsave(cell->lock, flags); |
67 | |
68 | val = readl(addr: cell->reg); |
69 | val &= ~cell->bits; |
70 | writel(val, addr: cell->reg); |
71 | |
72 | if (cell->lock) |
73 | spin_unlock_irqrestore(lock: cell->lock, flags); |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | static const struct reset_control_ops mmp_clk_reset_ops = { |
79 | .assert = mmp_clk_reset_assert, |
80 | .deassert = mmp_clk_reset_deassert, |
81 | }; |
82 | |
83 | void mmp_clk_reset_register(struct device_node *np, |
84 | struct mmp_clk_reset_cell *cells, int nr_resets) |
85 | { |
86 | struct mmp_clk_reset_unit *unit; |
87 | |
88 | unit = kzalloc(size: sizeof(*unit), GFP_KERNEL); |
89 | if (!unit) |
90 | return; |
91 | |
92 | unit->cells = cells; |
93 | unit->rcdev.of_reset_n_cells = 1; |
94 | unit->rcdev.nr_resets = nr_resets; |
95 | unit->rcdev.ops = &mmp_clk_reset_ops; |
96 | unit->rcdev.of_node = np; |
97 | unit->rcdev.of_xlate = mmp_of_reset_xlate; |
98 | |
99 | reset_controller_register(rcdev: &unit->rcdev); |
100 | } |
101 | |