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