GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / clk / visconti / reset.c
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(reset->regmap, data->rson_offset, rst, rst);
33         spin_unlock_irqrestore(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(reset->regmap, data->rsoff_offset, rst, rst);
48         spin_unlock_irqrestore(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(reset->regmap, data->rson_offset, &reg);
72         spin_unlock_irqrestore(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, 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, &reset->rcdev);
107 }