1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f59d23c2SChen Feng /*
3f59d23c2SChen Feng * Hisilicon Hi6220 reset controller driver
4f59d23c2SChen Feng *
58768a26cSChen Feng * Copyright (c) 2016 Linaro Limited.
66eed6a4bSHao Fang * Copyright (c) 2015-2016 HiSilicon Limited.
7f59d23c2SChen Feng *
8f59d23c2SChen Feng * Author: Feng Chen <puck.chen@hisilicon.com>
9f59d23c2SChen Feng */
10f59d23c2SChen Feng
11f59d23c2SChen Feng #include <linux/io.h>
12f59d23c2SChen Feng #include <linux/init.h>
1370b3590fSArnd Bergmann #include <linux/module.h>
14f59d23c2SChen Feng #include <linux/bitops.h>
15f59d23c2SChen Feng #include <linux/of.h>
168768a26cSChen Feng #include <linux/regmap.h>
178768a26cSChen Feng #include <linux/mfd/syscon.h>
18f59d23c2SChen Feng #include <linux/reset-controller.h>
19f59d23c2SChen Feng #include <linux/reset.h>
20f59d23c2SChen Feng #include <linux/platform_device.h>
21f59d23c2SChen Feng
228768a26cSChen Feng #define PERIPH_ASSERT_OFFSET 0x300
238768a26cSChen Feng #define PERIPH_DEASSERT_OFFSET 0x304
248768a26cSChen Feng #define PERIPH_MAX_INDEX 0x509
25f59d23c2SChen Feng
26ab52b599SXinliang Liu #define SC_MEDIA_RSTEN 0x052C
27ab52b599SXinliang Liu #define SC_MEDIA_RSTDIS 0x0530
28ab52b599SXinliang Liu #define MEDIA_MAX_INDEX 8
29ab52b599SXinliang Liu
30f59d23c2SChen Feng #define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)
31f59d23c2SChen Feng
32ab52b599SXinliang Liu enum hi6220_reset_ctrl_type {
33ab52b599SXinliang Liu PERIPHERAL,
34ab52b599SXinliang Liu MEDIA,
35697fa27dSPeter Griffin AO,
36ab52b599SXinliang Liu };
37ab52b599SXinliang Liu
38f59d23c2SChen Feng struct hi6220_reset_data {
39f59d23c2SChen Feng struct reset_controller_dev rc_dev;
408768a26cSChen Feng struct regmap *regmap;
41f59d23c2SChen Feng };
42f59d23c2SChen Feng
hi6220_peripheral_assert(struct reset_controller_dev * rc_dev,unsigned long idx)438768a26cSChen Feng static int hi6220_peripheral_assert(struct reset_controller_dev *rc_dev,
44f59d23c2SChen Feng unsigned long idx)
45f59d23c2SChen Feng {
46f59d23c2SChen Feng struct hi6220_reset_data *data = to_reset_data(rc_dev);
478768a26cSChen Feng struct regmap *regmap = data->regmap;
488768a26cSChen Feng u32 bank = idx >> 8;
498768a26cSChen Feng u32 offset = idx & 0xff;
508768a26cSChen Feng u32 reg = PERIPH_ASSERT_OFFSET + bank * 0x10;
51f59d23c2SChen Feng
528768a26cSChen Feng return regmap_write(regmap, reg, BIT(offset));
53f59d23c2SChen Feng }
54f59d23c2SChen Feng
hi6220_peripheral_deassert(struct reset_controller_dev * rc_dev,unsigned long idx)558768a26cSChen Feng static int hi6220_peripheral_deassert(struct reset_controller_dev *rc_dev,
56f59d23c2SChen Feng unsigned long idx)
57f59d23c2SChen Feng {
58f59d23c2SChen Feng struct hi6220_reset_data *data = to_reset_data(rc_dev);
598768a26cSChen Feng struct regmap *regmap = data->regmap;
608768a26cSChen Feng u32 bank = idx >> 8;
618768a26cSChen Feng u32 offset = idx & 0xff;
628768a26cSChen Feng u32 reg = PERIPH_DEASSERT_OFFSET + bank * 0x10;
63f59d23c2SChen Feng
648768a26cSChen Feng return regmap_write(regmap, reg, BIT(offset));
65f59d23c2SChen Feng }
66f59d23c2SChen Feng
678768a26cSChen Feng static const struct reset_control_ops hi6220_peripheral_reset_ops = {
688768a26cSChen Feng .assert = hi6220_peripheral_assert,
698768a26cSChen Feng .deassert = hi6220_peripheral_deassert,
70f59d23c2SChen Feng };
71f59d23c2SChen Feng
hi6220_media_assert(struct reset_controller_dev * rc_dev,unsigned long idx)72ab52b599SXinliang Liu static int hi6220_media_assert(struct reset_controller_dev *rc_dev,
73ab52b599SXinliang Liu unsigned long idx)
74ab52b599SXinliang Liu {
75ab52b599SXinliang Liu struct hi6220_reset_data *data = to_reset_data(rc_dev);
76ab52b599SXinliang Liu struct regmap *regmap = data->regmap;
77ab52b599SXinliang Liu
78ab52b599SXinliang Liu return regmap_write(regmap, SC_MEDIA_RSTEN, BIT(idx));
79ab52b599SXinliang Liu }
80ab52b599SXinliang Liu
hi6220_media_deassert(struct reset_controller_dev * rc_dev,unsigned long idx)81ab52b599SXinliang Liu static int hi6220_media_deassert(struct reset_controller_dev *rc_dev,
82ab52b599SXinliang Liu unsigned long idx)
83ab52b599SXinliang Liu {
84ab52b599SXinliang Liu struct hi6220_reset_data *data = to_reset_data(rc_dev);
85ab52b599SXinliang Liu struct regmap *regmap = data->regmap;
86ab52b599SXinliang Liu
87ab52b599SXinliang Liu return regmap_write(regmap, SC_MEDIA_RSTDIS, BIT(idx));
88ab52b599SXinliang Liu }
89ab52b599SXinliang Liu
90ab52b599SXinliang Liu static const struct reset_control_ops hi6220_media_reset_ops = {
91ab52b599SXinliang Liu .assert = hi6220_media_assert,
92ab52b599SXinliang Liu .deassert = hi6220_media_deassert,
93ab52b599SXinliang Liu };
94ab52b599SXinliang Liu
95697fa27dSPeter Griffin #define AO_SCTRL_SC_PW_CLKEN0 0x800
96697fa27dSPeter Griffin #define AO_SCTRL_SC_PW_CLKDIS0 0x804
97697fa27dSPeter Griffin
98697fa27dSPeter Griffin #define AO_SCTRL_SC_PW_RSTEN0 0x810
99697fa27dSPeter Griffin #define AO_SCTRL_SC_PW_RSTDIS0 0x814
100697fa27dSPeter Griffin
101697fa27dSPeter Griffin #define AO_SCTRL_SC_PW_ISOEN0 0x820
102697fa27dSPeter Griffin #define AO_SCTRL_SC_PW_ISODIS0 0x824
103697fa27dSPeter Griffin #define AO_MAX_INDEX 12
104697fa27dSPeter Griffin
hi6220_ao_assert(struct reset_controller_dev * rc_dev,unsigned long idx)105697fa27dSPeter Griffin static int hi6220_ao_assert(struct reset_controller_dev *rc_dev,
106697fa27dSPeter Griffin unsigned long idx)
107697fa27dSPeter Griffin {
108697fa27dSPeter Griffin struct hi6220_reset_data *data = to_reset_data(rc_dev);
109697fa27dSPeter Griffin struct regmap *regmap = data->regmap;
110697fa27dSPeter Griffin int ret;
111697fa27dSPeter Griffin
112697fa27dSPeter Griffin ret = regmap_write(regmap, AO_SCTRL_SC_PW_RSTEN0, BIT(idx));
113697fa27dSPeter Griffin if (ret)
114697fa27dSPeter Griffin return ret;
115697fa27dSPeter Griffin
116697fa27dSPeter Griffin ret = regmap_write(regmap, AO_SCTRL_SC_PW_ISOEN0, BIT(idx));
117697fa27dSPeter Griffin if (ret)
118697fa27dSPeter Griffin return ret;
119697fa27dSPeter Griffin
120697fa27dSPeter Griffin ret = regmap_write(regmap, AO_SCTRL_SC_PW_CLKDIS0, BIT(idx));
121697fa27dSPeter Griffin return ret;
122697fa27dSPeter Griffin }
123697fa27dSPeter Griffin
hi6220_ao_deassert(struct reset_controller_dev * rc_dev,unsigned long idx)124697fa27dSPeter Griffin static int hi6220_ao_deassert(struct reset_controller_dev *rc_dev,
125697fa27dSPeter Griffin unsigned long idx)
126697fa27dSPeter Griffin {
127697fa27dSPeter Griffin struct hi6220_reset_data *data = to_reset_data(rc_dev);
128697fa27dSPeter Griffin struct regmap *regmap = data->regmap;
129697fa27dSPeter Griffin int ret;
130697fa27dSPeter Griffin
131697fa27dSPeter Griffin /*
132697fa27dSPeter Griffin * It was suggested to disable isolation before enabling
133697fa27dSPeter Griffin * the clocks and deasserting reset, to avoid glitches.
134697fa27dSPeter Griffin * But this order is preserved to keep it matching the
135697fa27dSPeter Griffin * vendor code.
136697fa27dSPeter Griffin */
137697fa27dSPeter Griffin ret = regmap_write(regmap, AO_SCTRL_SC_PW_RSTDIS0, BIT(idx));
138697fa27dSPeter Griffin if (ret)
139697fa27dSPeter Griffin return ret;
140697fa27dSPeter Griffin
141697fa27dSPeter Griffin ret = regmap_write(regmap, AO_SCTRL_SC_PW_ISODIS0, BIT(idx));
142697fa27dSPeter Griffin if (ret)
143697fa27dSPeter Griffin return ret;
144697fa27dSPeter Griffin
145697fa27dSPeter Griffin ret = regmap_write(regmap, AO_SCTRL_SC_PW_CLKEN0, BIT(idx));
146697fa27dSPeter Griffin return ret;
147697fa27dSPeter Griffin }
148697fa27dSPeter Griffin
149697fa27dSPeter Griffin static const struct reset_control_ops hi6220_ao_reset_ops = {
150697fa27dSPeter Griffin .assert = hi6220_ao_assert,
151697fa27dSPeter Griffin .deassert = hi6220_ao_deassert,
152697fa27dSPeter Griffin };
153697fa27dSPeter Griffin
hi6220_reset_probe(struct platform_device * pdev)154f59d23c2SChen Feng static int hi6220_reset_probe(struct platform_device *pdev)
155f59d23c2SChen Feng {
1568768a26cSChen Feng struct device_node *np = pdev->dev.of_node;
1578768a26cSChen Feng struct device *dev = &pdev->dev;
158ab52b599SXinliang Liu enum hi6220_reset_ctrl_type type;
159f59d23c2SChen Feng struct hi6220_reset_data *data;
1608768a26cSChen Feng struct regmap *regmap;
161f59d23c2SChen Feng
1628768a26cSChen Feng data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
163f59d23c2SChen Feng if (!data)
164f59d23c2SChen Feng return -ENOMEM;
165f59d23c2SChen Feng
166*88c38fd2SKrzysztof Kozlowski type = (uintptr_t)of_device_get_match_data(dev);
167ab52b599SXinliang Liu
1688768a26cSChen Feng regmap = syscon_node_to_regmap(np);
1698768a26cSChen Feng if (IS_ERR(regmap)) {
1708768a26cSChen Feng dev_err(dev, "failed to get reset controller regmap\n");
1718768a26cSChen Feng return PTR_ERR(regmap);
1728768a26cSChen Feng }
173f59d23c2SChen Feng
1748768a26cSChen Feng data->regmap = regmap;
1758768a26cSChen Feng data->rc_dev.of_node = np;
176ab52b599SXinliang Liu if (type == MEDIA) {
177ab52b599SXinliang Liu data->rc_dev.ops = &hi6220_media_reset_ops;
178ab52b599SXinliang Liu data->rc_dev.nr_resets = MEDIA_MAX_INDEX;
179697fa27dSPeter Griffin } else if (type == PERIPHERAL) {
1808768a26cSChen Feng data->rc_dev.ops = &hi6220_peripheral_reset_ops;
1818768a26cSChen Feng data->rc_dev.nr_resets = PERIPH_MAX_INDEX;
182697fa27dSPeter Griffin } else {
183697fa27dSPeter Griffin data->rc_dev.ops = &hi6220_ao_reset_ops;
184697fa27dSPeter Griffin data->rc_dev.nr_resets = AO_MAX_INDEX;
185ab52b599SXinliang Liu }
186f59d23c2SChen Feng
187c41ef91fSMasahiro Yamada return reset_controller_register(&data->rc_dev);
188f59d23c2SChen Feng }
189f59d23c2SChen Feng
190f59d23c2SChen Feng static const struct of_device_id hi6220_reset_match[] = {
1918768a26cSChen Feng {
1928768a26cSChen Feng .compatible = "hisilicon,hi6220-sysctrl",
193ab52b599SXinliang Liu .data = (void *)PERIPHERAL,
194ab52b599SXinliang Liu },
195ab52b599SXinliang Liu {
196ab52b599SXinliang Liu .compatible = "hisilicon,hi6220-mediactrl",
197ab52b599SXinliang Liu .data = (void *)MEDIA,
1988768a26cSChen Feng },
199697fa27dSPeter Griffin {
200697fa27dSPeter Griffin .compatible = "hisilicon,hi6220-aoctrl",
201697fa27dSPeter Griffin .data = (void *)AO,
202697fa27dSPeter Griffin },
2038768a26cSChen Feng { /* sentinel */ },
204f59d23c2SChen Feng };
2058768a26cSChen Feng MODULE_DEVICE_TABLE(of, hi6220_reset_match);
206f59d23c2SChen Feng
207f59d23c2SChen Feng static struct platform_driver hi6220_reset_driver = {
208f59d23c2SChen Feng .probe = hi6220_reset_probe,
209f59d23c2SChen Feng .driver = {
210f59d23c2SChen Feng .name = "reset-hi6220",
211f59d23c2SChen Feng .of_match_table = hi6220_reset_match,
212f59d23c2SChen Feng },
213f59d23c2SChen Feng };
214f59d23c2SChen Feng
hi6220_reset_init(void)215f59d23c2SChen Feng static int __init hi6220_reset_init(void)
216f59d23c2SChen Feng {
217f59d23c2SChen Feng return platform_driver_register(&hi6220_reset_driver);
218f59d23c2SChen Feng }
219f59d23c2SChen Feng
220f59d23c2SChen Feng postcore_initcall(hi6220_reset_init);
2214497a224SJeremy Linton
2224497a224SJeremy Linton MODULE_LICENSE("GPL v2");
223