1c38ae95cSJerome Brunet // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2c38ae95cSJerome Brunet /*
3c38ae95cSJerome Brunet * Amlogic Meson Reset core functions
4c38ae95cSJerome Brunet *
5c38ae95cSJerome Brunet * Copyright (c) 2016-2024 BayLibre, SAS.
6c38ae95cSJerome Brunet * Authors: Neil Armstrong <narmstrong@baylibre.com>
7c38ae95cSJerome Brunet * Jerome Brunet <jbrunet@baylibre.com>
8c38ae95cSJerome Brunet */
9c38ae95cSJerome Brunet
10c38ae95cSJerome Brunet #include <linux/device.h>
11c38ae95cSJerome Brunet #include <linux/module.h>
12c38ae95cSJerome Brunet #include <linux/regmap.h>
13c38ae95cSJerome Brunet #include <linux/reset-controller.h>
14c38ae95cSJerome Brunet
15c38ae95cSJerome Brunet #include "reset-meson.h"
16c38ae95cSJerome Brunet
17c38ae95cSJerome Brunet struct meson_reset {
18c38ae95cSJerome Brunet const struct meson_reset_param *param;
19c38ae95cSJerome Brunet struct reset_controller_dev rcdev;
20c38ae95cSJerome Brunet struct regmap *map;
21c38ae95cSJerome Brunet };
22c38ae95cSJerome Brunet
meson_reset_offset_and_bit(struct meson_reset * data,unsigned long id,unsigned int * offset,unsigned int * bit)23c38ae95cSJerome Brunet static void meson_reset_offset_and_bit(struct meson_reset *data,
24c38ae95cSJerome Brunet unsigned long id,
25c38ae95cSJerome Brunet unsigned int *offset,
26c38ae95cSJerome Brunet unsigned int *bit)
27c38ae95cSJerome Brunet {
28c38ae95cSJerome Brunet unsigned int stride = regmap_get_reg_stride(data->map);
29c38ae95cSJerome Brunet
30c38ae95cSJerome Brunet *offset = (id / (stride * BITS_PER_BYTE)) * stride;
31c38ae95cSJerome Brunet *bit = id % (stride * BITS_PER_BYTE);
32c38ae95cSJerome Brunet }
33c38ae95cSJerome Brunet
meson_reset_reset(struct reset_controller_dev * rcdev,unsigned long id)34c38ae95cSJerome Brunet static int meson_reset_reset(struct reset_controller_dev *rcdev,
35c38ae95cSJerome Brunet unsigned long id)
36c38ae95cSJerome Brunet {
37c38ae95cSJerome Brunet struct meson_reset *data =
38c38ae95cSJerome Brunet container_of(rcdev, struct meson_reset, rcdev);
39c38ae95cSJerome Brunet unsigned int offset, bit;
40c38ae95cSJerome Brunet
41c38ae95cSJerome Brunet meson_reset_offset_and_bit(data, id, &offset, &bit);
42c38ae95cSJerome Brunet offset += data->param->reset_offset;
43c38ae95cSJerome Brunet
44c38ae95cSJerome Brunet return regmap_write(data->map, offset, BIT(bit));
45c38ae95cSJerome Brunet }
46c38ae95cSJerome Brunet
meson_reset_level(struct reset_controller_dev * rcdev,unsigned long id,bool assert)47c38ae95cSJerome Brunet static int meson_reset_level(struct reset_controller_dev *rcdev,
48c38ae95cSJerome Brunet unsigned long id, bool assert)
49c38ae95cSJerome Brunet {
50c38ae95cSJerome Brunet struct meson_reset *data =
51c38ae95cSJerome Brunet container_of(rcdev, struct meson_reset, rcdev);
52c38ae95cSJerome Brunet unsigned int offset, bit;
53c38ae95cSJerome Brunet
54c38ae95cSJerome Brunet meson_reset_offset_and_bit(data, id, &offset, &bit);
55c38ae95cSJerome Brunet offset += data->param->level_offset;
56c38ae95cSJerome Brunet assert ^= data->param->level_low_reset;
57c38ae95cSJerome Brunet
58c38ae95cSJerome Brunet return regmap_update_bits(data->map, offset,
59c38ae95cSJerome Brunet BIT(bit), assert ? BIT(bit) : 0);
60c38ae95cSJerome Brunet }
61c38ae95cSJerome Brunet
meson_reset_status(struct reset_controller_dev * rcdev,unsigned long id)62c38ae95cSJerome Brunet static int meson_reset_status(struct reset_controller_dev *rcdev,
63c38ae95cSJerome Brunet unsigned long id)
64c38ae95cSJerome Brunet {
65c38ae95cSJerome Brunet struct meson_reset *data =
66c38ae95cSJerome Brunet container_of(rcdev, struct meson_reset, rcdev);
67c38ae95cSJerome Brunet unsigned int val, offset, bit;
68c38ae95cSJerome Brunet
69c38ae95cSJerome Brunet meson_reset_offset_and_bit(data, id, &offset, &bit);
70c38ae95cSJerome Brunet offset += data->param->level_offset;
71c38ae95cSJerome Brunet
72c38ae95cSJerome Brunet regmap_read(data->map, offset, &val);
73c38ae95cSJerome Brunet val = !!(BIT(bit) & val);
74c38ae95cSJerome Brunet
75c38ae95cSJerome Brunet return val ^ data->param->level_low_reset;
76c38ae95cSJerome Brunet }
77c38ae95cSJerome Brunet
meson_reset_assert(struct reset_controller_dev * rcdev,unsigned long id)78c38ae95cSJerome Brunet static int meson_reset_assert(struct reset_controller_dev *rcdev,
79c38ae95cSJerome Brunet unsigned long id)
80c38ae95cSJerome Brunet {
81c38ae95cSJerome Brunet return meson_reset_level(rcdev, id, true);
82c38ae95cSJerome Brunet }
83c38ae95cSJerome Brunet
meson_reset_deassert(struct reset_controller_dev * rcdev,unsigned long id)84c38ae95cSJerome Brunet static int meson_reset_deassert(struct reset_controller_dev *rcdev,
85c38ae95cSJerome Brunet unsigned long id)
86c38ae95cSJerome Brunet {
87c38ae95cSJerome Brunet return meson_reset_level(rcdev, id, false);
88c38ae95cSJerome Brunet }
89c38ae95cSJerome Brunet
meson_reset_level_toggle(struct reset_controller_dev * rcdev,unsigned long id)90fb4c3158SJerome Brunet static int meson_reset_level_toggle(struct reset_controller_dev *rcdev,
91fb4c3158SJerome Brunet unsigned long id)
92fb4c3158SJerome Brunet {
93fb4c3158SJerome Brunet int ret;
94fb4c3158SJerome Brunet
95fb4c3158SJerome Brunet ret = meson_reset_assert(rcdev, id);
96fb4c3158SJerome Brunet if (ret)
97fb4c3158SJerome Brunet return ret;
98fb4c3158SJerome Brunet
99fb4c3158SJerome Brunet return meson_reset_deassert(rcdev, id);
100fb4c3158SJerome Brunet }
101fb4c3158SJerome Brunet
102fb4c3158SJerome Brunet const struct reset_control_ops meson_reset_ops = {
103c38ae95cSJerome Brunet .reset = meson_reset_reset,
104c38ae95cSJerome Brunet .assert = meson_reset_assert,
105c38ae95cSJerome Brunet .deassert = meson_reset_deassert,
106c38ae95cSJerome Brunet .status = meson_reset_status,
107c38ae95cSJerome Brunet };
108*cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS_GPL(meson_reset_ops, "MESON_RESET");
109fb4c3158SJerome Brunet
110fb4c3158SJerome Brunet const struct reset_control_ops meson_reset_toggle_ops = {
111fb4c3158SJerome Brunet .reset = meson_reset_level_toggle,
112fb4c3158SJerome Brunet .assert = meson_reset_assert,
113fb4c3158SJerome Brunet .deassert = meson_reset_deassert,
114fb4c3158SJerome Brunet .status = meson_reset_status,
115fb4c3158SJerome Brunet };
116*cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS_GPL(meson_reset_toggle_ops, "MESON_RESET");
117c38ae95cSJerome Brunet
meson_reset_controller_register(struct device * dev,struct regmap * map,const struct meson_reset_param * param)118c38ae95cSJerome Brunet int meson_reset_controller_register(struct device *dev, struct regmap *map,
119c38ae95cSJerome Brunet const struct meson_reset_param *param)
120c38ae95cSJerome Brunet {
121c38ae95cSJerome Brunet struct meson_reset *data;
122c38ae95cSJerome Brunet
123c38ae95cSJerome Brunet data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
124c38ae95cSJerome Brunet if (!data)
125c38ae95cSJerome Brunet return -ENOMEM;
126c38ae95cSJerome Brunet
127c38ae95cSJerome Brunet data->param = param;
128c38ae95cSJerome Brunet data->map = map;
129c38ae95cSJerome Brunet data->rcdev.owner = dev->driver->owner;
130c38ae95cSJerome Brunet data->rcdev.nr_resets = param->reset_num;
131fb4c3158SJerome Brunet data->rcdev.ops = data->param->reset_ops;
132c38ae95cSJerome Brunet data->rcdev.of_node = dev->of_node;
133c38ae95cSJerome Brunet
134c38ae95cSJerome Brunet return devm_reset_controller_register(dev, &data->rcdev);
135c38ae95cSJerome Brunet }
136*cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS_GPL(meson_reset_controller_register, "MESON_RESET");
137c38ae95cSJerome Brunet
138c38ae95cSJerome Brunet MODULE_DESCRIPTION("Amlogic Meson Reset Core function");
139c38ae95cSJerome Brunet MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
140c38ae95cSJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
141c38ae95cSJerome Brunet MODULE_LICENSE("Dual BSD/GPL");
142*cdd30ebbSPeter Zijlstra MODULE_IMPORT_NS("MESON_RESET");
143