xref: /linux/drivers/reset/amlogic/reset-meson-aux.c (revision fb4c31587adfa9cd50661a535bdbfcc4da57ee38)
1*fb4c3158SJerome Brunet // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2*fb4c3158SJerome Brunet /*
3*fb4c3158SJerome Brunet  * Amlogic Meson Reset Auxiliary driver
4*fb4c3158SJerome Brunet  *
5*fb4c3158SJerome Brunet  * Copyright (c) 2024 BayLibre, SAS.
6*fb4c3158SJerome Brunet  * Author: Jerome Brunet <jbrunet@baylibre.com>
7*fb4c3158SJerome Brunet  */
8*fb4c3158SJerome Brunet 
9*fb4c3158SJerome Brunet #include <linux/err.h>
10*fb4c3158SJerome Brunet #include <linux/module.h>
11*fb4c3158SJerome Brunet #include <linux/auxiliary_bus.h>
12*fb4c3158SJerome Brunet #include <linux/regmap.h>
13*fb4c3158SJerome Brunet #include <linux/reset-controller.h>
14*fb4c3158SJerome Brunet #include <linux/slab.h>
15*fb4c3158SJerome Brunet 
16*fb4c3158SJerome Brunet #include "reset-meson.h"
17*fb4c3158SJerome Brunet #include <soc/amlogic/reset-meson-aux.h>
18*fb4c3158SJerome Brunet 
19*fb4c3158SJerome Brunet static DEFINE_IDA(meson_rst_aux_ida);
20*fb4c3158SJerome Brunet 
21*fb4c3158SJerome Brunet struct meson_reset_adev {
22*fb4c3158SJerome Brunet 	struct auxiliary_device adev;
23*fb4c3158SJerome Brunet 	struct regmap *map;
24*fb4c3158SJerome Brunet };
25*fb4c3158SJerome Brunet 
26*fb4c3158SJerome Brunet #define to_meson_reset_adev(_adev) \
27*fb4c3158SJerome Brunet 	container_of((_adev), struct meson_reset_adev, adev)
28*fb4c3158SJerome Brunet 
29*fb4c3158SJerome Brunet static const struct meson_reset_param meson_g12a_audio_param = {
30*fb4c3158SJerome Brunet 	.reset_ops	= &meson_reset_toggle_ops,
31*fb4c3158SJerome Brunet 	.reset_num	= 26,
32*fb4c3158SJerome Brunet 	.level_offset	= 0x24,
33*fb4c3158SJerome Brunet };
34*fb4c3158SJerome Brunet 
35*fb4c3158SJerome Brunet static const struct meson_reset_param meson_sm1_audio_param = {
36*fb4c3158SJerome Brunet 	.reset_ops	= &meson_reset_toggle_ops,
37*fb4c3158SJerome Brunet 	.reset_num	= 39,
38*fb4c3158SJerome Brunet 	.level_offset	= 0x28,
39*fb4c3158SJerome Brunet };
40*fb4c3158SJerome Brunet 
41*fb4c3158SJerome Brunet static const struct auxiliary_device_id meson_reset_aux_ids[] = {
42*fb4c3158SJerome Brunet 	{
43*fb4c3158SJerome Brunet 		.name = "axg-audio-clkc.rst-g12a",
44*fb4c3158SJerome Brunet 		.driver_data = (kernel_ulong_t)&meson_g12a_audio_param,
45*fb4c3158SJerome Brunet 	}, {
46*fb4c3158SJerome Brunet 		.name = "axg-audio-clkc.rst-sm1",
47*fb4c3158SJerome Brunet 		.driver_data = (kernel_ulong_t)&meson_sm1_audio_param,
48*fb4c3158SJerome Brunet 	}, {}
49*fb4c3158SJerome Brunet };
50*fb4c3158SJerome Brunet MODULE_DEVICE_TABLE(auxiliary, meson_reset_aux_ids);
51*fb4c3158SJerome Brunet 
52*fb4c3158SJerome Brunet static int meson_reset_aux_probe(struct auxiliary_device *adev,
53*fb4c3158SJerome Brunet 				 const struct auxiliary_device_id *id)
54*fb4c3158SJerome Brunet {
55*fb4c3158SJerome Brunet 	const struct meson_reset_param *param =
56*fb4c3158SJerome Brunet 		(const struct meson_reset_param *)(id->driver_data);
57*fb4c3158SJerome Brunet 	struct meson_reset_adev *raux =
58*fb4c3158SJerome Brunet 		to_meson_reset_adev(adev);
59*fb4c3158SJerome Brunet 
60*fb4c3158SJerome Brunet 	return meson_reset_controller_register(&adev->dev, raux->map, param);
61*fb4c3158SJerome Brunet }
62*fb4c3158SJerome Brunet 
63*fb4c3158SJerome Brunet static struct auxiliary_driver meson_reset_aux_driver = {
64*fb4c3158SJerome Brunet 	.probe		= meson_reset_aux_probe,
65*fb4c3158SJerome Brunet 	.id_table	= meson_reset_aux_ids,
66*fb4c3158SJerome Brunet };
67*fb4c3158SJerome Brunet module_auxiliary_driver(meson_reset_aux_driver);
68*fb4c3158SJerome Brunet 
69*fb4c3158SJerome Brunet static void meson_rst_aux_release(struct device *dev)
70*fb4c3158SJerome Brunet {
71*fb4c3158SJerome Brunet 	struct auxiliary_device *adev = to_auxiliary_dev(dev);
72*fb4c3158SJerome Brunet 	struct meson_reset_adev *raux =
73*fb4c3158SJerome Brunet 		to_meson_reset_adev(adev);
74*fb4c3158SJerome Brunet 
75*fb4c3158SJerome Brunet 	ida_free(&meson_rst_aux_ida, adev->id);
76*fb4c3158SJerome Brunet 	kfree(raux);
77*fb4c3158SJerome Brunet }
78*fb4c3158SJerome Brunet 
79*fb4c3158SJerome Brunet static void meson_rst_aux_unregister_adev(void *_adev)
80*fb4c3158SJerome Brunet {
81*fb4c3158SJerome Brunet 	struct auxiliary_device *adev = _adev;
82*fb4c3158SJerome Brunet 
83*fb4c3158SJerome Brunet 	auxiliary_device_delete(adev);
84*fb4c3158SJerome Brunet 	auxiliary_device_uninit(adev);
85*fb4c3158SJerome Brunet }
86*fb4c3158SJerome Brunet 
87*fb4c3158SJerome Brunet int devm_meson_rst_aux_register(struct device *dev,
88*fb4c3158SJerome Brunet 				struct regmap *map,
89*fb4c3158SJerome Brunet 				const char *adev_name)
90*fb4c3158SJerome Brunet {
91*fb4c3158SJerome Brunet 	struct meson_reset_adev *raux;
92*fb4c3158SJerome Brunet 	struct auxiliary_device *adev;
93*fb4c3158SJerome Brunet 	int ret;
94*fb4c3158SJerome Brunet 
95*fb4c3158SJerome Brunet 	raux = kzalloc(sizeof(*raux), GFP_KERNEL);
96*fb4c3158SJerome Brunet 	if (!raux)
97*fb4c3158SJerome Brunet 		return -ENOMEM;
98*fb4c3158SJerome Brunet 
99*fb4c3158SJerome Brunet 	ret = ida_alloc(&meson_rst_aux_ida, GFP_KERNEL);
100*fb4c3158SJerome Brunet 	if (ret < 0)
101*fb4c3158SJerome Brunet 		goto raux_free;
102*fb4c3158SJerome Brunet 
103*fb4c3158SJerome Brunet 	raux->map = map;
104*fb4c3158SJerome Brunet 
105*fb4c3158SJerome Brunet 	adev = &raux->adev;
106*fb4c3158SJerome Brunet 	adev->id = ret;
107*fb4c3158SJerome Brunet 	adev->name = adev_name;
108*fb4c3158SJerome Brunet 	adev->dev.parent = dev;
109*fb4c3158SJerome Brunet 	adev->dev.release = meson_rst_aux_release;
110*fb4c3158SJerome Brunet 	device_set_of_node_from_dev(&adev->dev, dev);
111*fb4c3158SJerome Brunet 
112*fb4c3158SJerome Brunet 	ret = auxiliary_device_init(adev);
113*fb4c3158SJerome Brunet 	if (ret)
114*fb4c3158SJerome Brunet 		goto ida_free;
115*fb4c3158SJerome Brunet 
116*fb4c3158SJerome Brunet 	ret = __auxiliary_device_add(adev, dev->driver->name);
117*fb4c3158SJerome Brunet 	if (ret) {
118*fb4c3158SJerome Brunet 		auxiliary_device_uninit(adev);
119*fb4c3158SJerome Brunet 		return ret;
120*fb4c3158SJerome Brunet 	}
121*fb4c3158SJerome Brunet 
122*fb4c3158SJerome Brunet 	return devm_add_action_or_reset(dev, meson_rst_aux_unregister_adev,
123*fb4c3158SJerome Brunet 					adev);
124*fb4c3158SJerome Brunet 
125*fb4c3158SJerome Brunet ida_free:
126*fb4c3158SJerome Brunet 	ida_free(&meson_rst_aux_ida, adev->id);
127*fb4c3158SJerome Brunet raux_free:
128*fb4c3158SJerome Brunet 	kfree(raux);
129*fb4c3158SJerome Brunet 	return ret;
130*fb4c3158SJerome Brunet }
131*fb4c3158SJerome Brunet EXPORT_SYMBOL_GPL(devm_meson_rst_aux_register);
132*fb4c3158SJerome Brunet 
133*fb4c3158SJerome Brunet MODULE_DESCRIPTION("Amlogic Meson Reset Auxiliary driver");
134*fb4c3158SJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
135*fb4c3158SJerome Brunet MODULE_LICENSE("Dual BSD/GPL");
136*fb4c3158SJerome Brunet MODULE_IMPORT_NS(MESON_RESET);
137