blob: 4da0d13261b90a34dbae7100ddded3a06fb0d566 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2014 MediaTek Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/mfd/syscon.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/platform_device.h>
18#include <linux/regmap.h>
19#include <linux/reset-controller.h>
20#include <linux/slab.h>
21
22#include "clk-mtk.h"
23
24struct mtk_reset {
25 struct regmap *regmap;
26 int regofs;
27 struct reset_controller_dev rcdev;
28};
29
30static int mtk_reset_assert_set_clr(struct reset_controller_dev *rcdev,
31 unsigned long id)
32{
33 struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
34
35 return regmap_write(data->regmap, data->regofs + ((id / 32) << 4), 1);
36}
37
38static int mtk_reset_deassert_set_clr(struct reset_controller_dev *rcdev,
39 unsigned long id)
40{
41 struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
42
43 return regmap_write(data->regmap,
44 data->regofs + ((id / 32) << 4) + 0x4, 1);
45}
46
47static int mtk_reset_assert(struct reset_controller_dev *rcdev,
48 unsigned long id)
49{
50 struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
51
52 return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
53 BIT(id % 32), ~0);
54}
55
56static int mtk_reset_deassert(struct reset_controller_dev *rcdev,
57 unsigned long id)
58{
59 struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev);
60
61 return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2),
62 BIT(id % 32), 0);
63}
64
65static int mtk_reset(struct reset_controller_dev *rcdev,
66 unsigned long id)
67{
68 int ret;
69
70 ret = mtk_reset_assert(rcdev, id);
71 if (ret)
72 return ret;
73
74 return mtk_reset_deassert(rcdev, id);
75}
76
77static int mtk_reset_set_clr(struct reset_controller_dev *rcdev,
78 unsigned long id)
79{
80 int ret;
81
82 ret = mtk_reset_assert_set_clr(rcdev, id);
83 if (ret)
84 return ret;
85
86 return mtk_reset_deassert_set_clr(rcdev, id);
87}
88
89static const struct reset_control_ops mtk_reset_ops = {
90 .assert = mtk_reset_assert,
91 .deassert = mtk_reset_deassert,
92 .reset = mtk_reset,
93};
94
95static const struct reset_control_ops mtk_reset_ops_set_clr = {
96 .assert = mtk_reset_assert_set_clr,
97 .deassert = mtk_reset_deassert_set_clr,
98 .reset = mtk_reset_set_clr,
99};
100
101void mtk_register_reset_controller_common(struct device_node *np,
102 unsigned int num_regs, int regofs,
103 struct reset_control_ops *reset_ops)
104{
105 struct mtk_reset *data;
106 int ret;
107 struct regmap *regmap;
108
109 regmap = syscon_node_to_regmap(np);
110 if (IS_ERR(regmap)) {
111 pr_err("Cannot find regmap for %pOF: %ld\n", np,
112 PTR_ERR(regmap));
113 return;
114 }
115
116 data = kzalloc(sizeof(*data), GFP_KERNEL);
117 if (!data)
118 return;
119
120 data->regmap = regmap;
121 data->regofs = regofs;
122 data->rcdev.owner = THIS_MODULE;
123 data->rcdev.nr_resets = num_regs * 32;
124 data->rcdev.ops = reset_ops;
125 data->rcdev.of_node = np;
126
127 ret = reset_controller_register(&data->rcdev);
128 if (ret) {
129 pr_err("could not register reset controller: %d\n", ret);
130 kfree(data);
131 return;
132 }
133}
134
135void mtk_register_reset_controller(struct device_node *np,
136 unsigned int num_regs, int regofs)
137{
138 mtk_register_reset_controller_common(np, num_regs, regofs,
139 &mtk_reset_ops);
140}
141
142void mtk_register_reset_controller_set_clr(struct device_node *np,
143 unsigned int num_regs, int regofs)
144{
145 mtk_register_reset_controller_common(np, num_regs, regofs,
146 &mtk_reset_ops_set_clr);
147}
148