1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Toshiba Visconti ARM SoC reset controller |
4 | * |
5 | * Copyright (c) 2021 TOSHIBA CORPORATION |
6 | * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation |
7 | * |
8 | * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> |
9 | */ |
10 | #include <linux/delay.h> |
11 | #include <linux/device.h> |
12 | #include <linux/mfd/syscon.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/slab.h> |
15 | |
16 | #include "reset.h" |
17 | |
18 | static inline struct visconti_reset *to_visconti_reset(struct reset_controller_dev *rcdev) |
19 | { |
20 | return container_of(rcdev, struct visconti_reset, rcdev); |
21 | } |
22 | |
23 | static int visconti_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) |
24 | { |
25 | struct visconti_reset *reset = to_visconti_reset(rcdev); |
26 | const struct visconti_reset_data *data = &reset->resets[id]; |
27 | u32 rst = BIT(data->rs_idx); |
28 | unsigned long flags; |
29 | int ret; |
30 | |
31 | spin_lock_irqsave(reset->lock, flags); |
32 | ret = regmap_update_bits(map: reset->regmap, reg: data->rson_offset, mask: rst, val: rst); |
33 | spin_unlock_irqrestore(lock: reset->lock, flags); |
34 | |
35 | return ret; |
36 | } |
37 | |
38 | static int visconti_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) |
39 | { |
40 | struct visconti_reset *reset = to_visconti_reset(rcdev); |
41 | const struct visconti_reset_data *data = &reset->resets[id]; |
42 | u32 rst = BIT(data->rs_idx); |
43 | unsigned long flags; |
44 | int ret; |
45 | |
46 | spin_lock_irqsave(reset->lock, flags); |
47 | ret = regmap_update_bits(map: reset->regmap, reg: data->rsoff_offset, mask: rst, val: rst); |
48 | spin_unlock_irqrestore(lock: reset->lock, flags); |
49 | |
50 | return ret; |
51 | } |
52 | |
53 | static int visconti_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) |
54 | { |
55 | visconti_reset_assert(rcdev, id); |
56 | udelay(1); |
57 | visconti_reset_deassert(rcdev, id); |
58 | |
59 | return 0; |
60 | } |
61 | |
62 | static int visconti_reset_status(struct reset_controller_dev *rcdev, unsigned long id) |
63 | { |
64 | struct visconti_reset *reset = to_visconti_reset(rcdev); |
65 | const struct visconti_reset_data *data = &reset->resets[id]; |
66 | unsigned long flags; |
67 | u32 reg; |
68 | int ret; |
69 | |
70 | spin_lock_irqsave(reset->lock, flags); |
71 | ret = regmap_read(map: reset->regmap, reg: data->rson_offset, val: ®); |
72 | spin_unlock_irqrestore(lock: reset->lock, flags); |
73 | if (ret) |
74 | return ret; |
75 | |
76 | return !(reg & data->rs_idx); |
77 | } |
78 | |
79 | const struct reset_control_ops visconti_reset_ops = { |
80 | .assert = visconti_reset_assert, |
81 | .deassert = visconti_reset_deassert, |
82 | .reset = visconti_reset_reset, |
83 | .status = visconti_reset_status, |
84 | }; |
85 | |
86 | int visconti_register_reset_controller(struct device *dev, |
87 | struct regmap *regmap, |
88 | const struct visconti_reset_data *resets, |
89 | unsigned int num_resets, |
90 | const struct reset_control_ops *reset_ops, |
91 | spinlock_t *lock) |
92 | { |
93 | struct visconti_reset *reset; |
94 | |
95 | reset = devm_kzalloc(dev, size: sizeof(*reset), GFP_KERNEL); |
96 | if (!reset) |
97 | return -ENOMEM; |
98 | |
99 | reset->regmap = regmap; |
100 | reset->resets = resets; |
101 | reset->rcdev.ops = reset_ops; |
102 | reset->rcdev.nr_resets = num_resets; |
103 | reset->rcdev.of_node = dev->of_node; |
104 | reset->lock = lock; |
105 | |
106 | return devm_reset_controller_register(dev, rcdev: &reset->rcdev); |
107 | } |
108 | |