1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
5 * Copyright (C) Sunplus Technology Co., Ltd.
10 #include <linux/init.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/platform_device.h>
13 #include <linux/reset-controller.h>
14 #include <linux/reboot.h>
16 /* HIWORD_MASK_REG BITS */
17 #define BITS_PER_HWM_REG 16
19 /* resets HW info: reg_index_shift */
20 static const u32 sp_resets
[] = {
21 /* SP7021: mo_reset0 ~ mo_reset9 */
102 struct reset_controller_dev rcdev
;
103 struct notifier_block notifier
;
107 static inline struct sp_reset
*to_sp_reset(struct reset_controller_dev
*rcdev
)
109 return container_of(rcdev
, struct sp_reset
, rcdev
);
112 static int sp_reset_update(struct reset_controller_dev
*rcdev
,
113 unsigned long id
, bool assert)
115 struct sp_reset
*reset
= to_sp_reset(rcdev
);
116 int index
= sp_resets
[id
] / BITS_PER_HWM_REG
;
117 int shift
= sp_resets
[id
] % BITS_PER_HWM_REG
;
120 val
= (1 << (16 + shift
)) | (assert << shift
);
121 writel(val
, reset
->base
+ (index
* 4));
126 static int sp_reset_assert(struct reset_controller_dev
*rcdev
,
129 return sp_reset_update(rcdev
, id
, true);
132 static int sp_reset_deassert(struct reset_controller_dev
*rcdev
,
135 return sp_reset_update(rcdev
, id
, false);
138 static int sp_reset_status(struct reset_controller_dev
*rcdev
,
141 struct sp_reset
*reset
= to_sp_reset(rcdev
);
142 int index
= sp_resets
[id
] / BITS_PER_HWM_REG
;
143 int shift
= sp_resets
[id
] % BITS_PER_HWM_REG
;
146 reg
= readl(reset
->base
+ (index
* 4));
148 return !!(reg
& BIT(shift
));
151 static const struct reset_control_ops sp_reset_ops
= {
152 .assert = sp_reset_assert
,
153 .deassert
= sp_reset_deassert
,
154 .status
= sp_reset_status
,
157 static int sp_restart(struct notifier_block
*nb
, unsigned long mode
,
160 struct sp_reset
*reset
= container_of(nb
, struct sp_reset
, notifier
);
162 sp_reset_assert(&reset
->rcdev
, 0);
163 sp_reset_deassert(&reset
->rcdev
, 0);
168 static int sp_reset_probe(struct platform_device
*pdev
)
170 struct device
*dev
= &pdev
->dev
;
171 struct sp_reset
*reset
;
172 struct resource
*res
;
175 reset
= devm_kzalloc(dev
, sizeof(*reset
), GFP_KERNEL
);
179 reset
->base
= devm_platform_get_and_ioremap_resource(pdev
, 0, &res
);
180 if (IS_ERR(reset
->base
))
181 return PTR_ERR(reset
->base
);
183 reset
->rcdev
.ops
= &sp_reset_ops
;
184 reset
->rcdev
.owner
= THIS_MODULE
;
185 reset
->rcdev
.of_node
= dev
->of_node
;
186 reset
->rcdev
.nr_resets
= resource_size(res
) / 4 * BITS_PER_HWM_REG
;
188 ret
= devm_reset_controller_register(dev
, &reset
->rcdev
);
192 reset
->notifier
.notifier_call
= sp_restart
;
193 reset
->notifier
.priority
= 192;
195 return register_restart_handler(&reset
->notifier
);
198 static const struct of_device_id sp_reset_dt_ids
[] = {
199 {.compatible
= "sunplus,sp7021-reset",},
203 static struct platform_driver sp_reset_driver
= {
204 .probe
= sp_reset_probe
,
206 .name
= "sunplus-reset",
207 .of_match_table
= sp_reset_dt_ids
,
208 .suppress_bind_attrs
= true,
211 builtin_platform_driver(sp_reset_driver
);