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