xref: /linux/drivers/reset/amlogic/reset-meson-audio-arb.c (revision 2c138ee3354f8088769d05701a2e16d1cb4cc22d)
1*2c138ee3SJerome Brunet // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2*2c138ee3SJerome Brunet // Copyright (c) 2018 BayLibre, SAS.
3*2c138ee3SJerome Brunet // Author: Jerome Brunet <jbrunet@baylibre.com>
4*2c138ee3SJerome Brunet 
5*2c138ee3SJerome Brunet #include <linux/clk.h>
6*2c138ee3SJerome Brunet #include <linux/io.h>
7*2c138ee3SJerome Brunet #include <linux/module.h>
8*2c138ee3SJerome Brunet #include <linux/of.h>
9*2c138ee3SJerome Brunet #include <linux/platform_device.h>
10*2c138ee3SJerome Brunet #include <linux/reset-controller.h>
11*2c138ee3SJerome Brunet #include <linux/spinlock.h>
12*2c138ee3SJerome Brunet 
13*2c138ee3SJerome Brunet #include <dt-bindings/reset/amlogic,meson-axg-audio-arb.h>
14*2c138ee3SJerome Brunet 
15*2c138ee3SJerome Brunet struct meson_audio_arb_data {
16*2c138ee3SJerome Brunet 	struct reset_controller_dev rstc;
17*2c138ee3SJerome Brunet 	void __iomem *regs;
18*2c138ee3SJerome Brunet 	struct clk *clk;
19*2c138ee3SJerome Brunet 	const unsigned int *reset_bits;
20*2c138ee3SJerome Brunet 	spinlock_t lock;
21*2c138ee3SJerome Brunet };
22*2c138ee3SJerome Brunet 
23*2c138ee3SJerome Brunet struct meson_audio_arb_match_data {
24*2c138ee3SJerome Brunet 	const unsigned int *reset_bits;
25*2c138ee3SJerome Brunet 	unsigned int reset_num;
26*2c138ee3SJerome Brunet };
27*2c138ee3SJerome Brunet 
28*2c138ee3SJerome Brunet #define ARB_GENERAL_BIT	31
29*2c138ee3SJerome Brunet 
30*2c138ee3SJerome Brunet static const unsigned int axg_audio_arb_reset_bits[] = {
31*2c138ee3SJerome Brunet 	[AXG_ARB_TODDR_A]	= 0,
32*2c138ee3SJerome Brunet 	[AXG_ARB_TODDR_B]	= 1,
33*2c138ee3SJerome Brunet 	[AXG_ARB_TODDR_C]	= 2,
34*2c138ee3SJerome Brunet 	[AXG_ARB_FRDDR_A]	= 4,
35*2c138ee3SJerome Brunet 	[AXG_ARB_FRDDR_B]	= 5,
36*2c138ee3SJerome Brunet 	[AXG_ARB_FRDDR_C]	= 6,
37*2c138ee3SJerome Brunet };
38*2c138ee3SJerome Brunet 
39*2c138ee3SJerome Brunet static const struct meson_audio_arb_match_data axg_audio_arb_match = {
40*2c138ee3SJerome Brunet 	.reset_bits = axg_audio_arb_reset_bits,
41*2c138ee3SJerome Brunet 	.reset_num = ARRAY_SIZE(axg_audio_arb_reset_bits),
42*2c138ee3SJerome Brunet };
43*2c138ee3SJerome Brunet 
44*2c138ee3SJerome Brunet static const unsigned int sm1_audio_arb_reset_bits[] = {
45*2c138ee3SJerome Brunet 	[AXG_ARB_TODDR_A]	= 0,
46*2c138ee3SJerome Brunet 	[AXG_ARB_TODDR_B]	= 1,
47*2c138ee3SJerome Brunet 	[AXG_ARB_TODDR_C]	= 2,
48*2c138ee3SJerome Brunet 	[AXG_ARB_FRDDR_A]	= 4,
49*2c138ee3SJerome Brunet 	[AXG_ARB_FRDDR_B]	= 5,
50*2c138ee3SJerome Brunet 	[AXG_ARB_FRDDR_C]	= 6,
51*2c138ee3SJerome Brunet 	[AXG_ARB_TODDR_D]	= 3,
52*2c138ee3SJerome Brunet 	[AXG_ARB_FRDDR_D]	= 7,
53*2c138ee3SJerome Brunet };
54*2c138ee3SJerome Brunet 
55*2c138ee3SJerome Brunet static const struct meson_audio_arb_match_data sm1_audio_arb_match = {
56*2c138ee3SJerome Brunet 	.reset_bits = sm1_audio_arb_reset_bits,
57*2c138ee3SJerome Brunet 	.reset_num = ARRAY_SIZE(sm1_audio_arb_reset_bits),
58*2c138ee3SJerome Brunet };
59*2c138ee3SJerome Brunet 
60*2c138ee3SJerome Brunet static int meson_audio_arb_update(struct reset_controller_dev *rcdev,
61*2c138ee3SJerome Brunet 				  unsigned long id, bool assert)
62*2c138ee3SJerome Brunet {
63*2c138ee3SJerome Brunet 	u32 val;
64*2c138ee3SJerome Brunet 	struct meson_audio_arb_data *arb =
65*2c138ee3SJerome Brunet 		container_of(rcdev, struct meson_audio_arb_data, rstc);
66*2c138ee3SJerome Brunet 
67*2c138ee3SJerome Brunet 	spin_lock(&arb->lock);
68*2c138ee3SJerome Brunet 	val = readl(arb->regs);
69*2c138ee3SJerome Brunet 
70*2c138ee3SJerome Brunet 	if (assert)
71*2c138ee3SJerome Brunet 		val &= ~BIT(arb->reset_bits[id]);
72*2c138ee3SJerome Brunet 	else
73*2c138ee3SJerome Brunet 		val |= BIT(arb->reset_bits[id]);
74*2c138ee3SJerome Brunet 
75*2c138ee3SJerome Brunet 	writel(val, arb->regs);
76*2c138ee3SJerome Brunet 	spin_unlock(&arb->lock);
77*2c138ee3SJerome Brunet 
78*2c138ee3SJerome Brunet 	return 0;
79*2c138ee3SJerome Brunet }
80*2c138ee3SJerome Brunet 
81*2c138ee3SJerome Brunet static int meson_audio_arb_status(struct reset_controller_dev *rcdev,
82*2c138ee3SJerome Brunet 				  unsigned long id)
83*2c138ee3SJerome Brunet {
84*2c138ee3SJerome Brunet 	u32 val;
85*2c138ee3SJerome Brunet 	struct meson_audio_arb_data *arb =
86*2c138ee3SJerome Brunet 		container_of(rcdev, struct meson_audio_arb_data, rstc);
87*2c138ee3SJerome Brunet 
88*2c138ee3SJerome Brunet 	val = readl(arb->regs);
89*2c138ee3SJerome Brunet 
90*2c138ee3SJerome Brunet 	return !(val & BIT(arb->reset_bits[id]));
91*2c138ee3SJerome Brunet }
92*2c138ee3SJerome Brunet 
93*2c138ee3SJerome Brunet static int meson_audio_arb_assert(struct reset_controller_dev *rcdev,
94*2c138ee3SJerome Brunet 				  unsigned long id)
95*2c138ee3SJerome Brunet {
96*2c138ee3SJerome Brunet 	return meson_audio_arb_update(rcdev, id, true);
97*2c138ee3SJerome Brunet }
98*2c138ee3SJerome Brunet 
99*2c138ee3SJerome Brunet static int meson_audio_arb_deassert(struct reset_controller_dev *rcdev,
100*2c138ee3SJerome Brunet 				    unsigned long id)
101*2c138ee3SJerome Brunet {
102*2c138ee3SJerome Brunet 	return meson_audio_arb_update(rcdev, id, false);
103*2c138ee3SJerome Brunet }
104*2c138ee3SJerome Brunet 
105*2c138ee3SJerome Brunet static const struct reset_control_ops meson_audio_arb_rstc_ops = {
106*2c138ee3SJerome Brunet 	.assert = meson_audio_arb_assert,
107*2c138ee3SJerome Brunet 	.deassert = meson_audio_arb_deassert,
108*2c138ee3SJerome Brunet 	.status = meson_audio_arb_status,
109*2c138ee3SJerome Brunet };
110*2c138ee3SJerome Brunet 
111*2c138ee3SJerome Brunet static const struct of_device_id meson_audio_arb_of_match[] = {
112*2c138ee3SJerome Brunet 	{
113*2c138ee3SJerome Brunet 		.compatible = "amlogic,meson-axg-audio-arb",
114*2c138ee3SJerome Brunet 		.data = &axg_audio_arb_match,
115*2c138ee3SJerome Brunet 	}, {
116*2c138ee3SJerome Brunet 		.compatible = "amlogic,meson-sm1-audio-arb",
117*2c138ee3SJerome Brunet 		.data = &sm1_audio_arb_match,
118*2c138ee3SJerome Brunet 	},
119*2c138ee3SJerome Brunet 	{}
120*2c138ee3SJerome Brunet };
121*2c138ee3SJerome Brunet MODULE_DEVICE_TABLE(of, meson_audio_arb_of_match);
122*2c138ee3SJerome Brunet 
123*2c138ee3SJerome Brunet static void meson_audio_arb_remove(struct platform_device *pdev)
124*2c138ee3SJerome Brunet {
125*2c138ee3SJerome Brunet 	struct meson_audio_arb_data *arb = platform_get_drvdata(pdev);
126*2c138ee3SJerome Brunet 
127*2c138ee3SJerome Brunet 	/* Disable all access */
128*2c138ee3SJerome Brunet 	spin_lock(&arb->lock);
129*2c138ee3SJerome Brunet 	writel(0, arb->regs);
130*2c138ee3SJerome Brunet 	spin_unlock(&arb->lock);
131*2c138ee3SJerome Brunet }
132*2c138ee3SJerome Brunet 
133*2c138ee3SJerome Brunet static int meson_audio_arb_probe(struct platform_device *pdev)
134*2c138ee3SJerome Brunet {
135*2c138ee3SJerome Brunet 	struct device *dev = &pdev->dev;
136*2c138ee3SJerome Brunet 	const struct meson_audio_arb_match_data *data;
137*2c138ee3SJerome Brunet 	struct meson_audio_arb_data *arb;
138*2c138ee3SJerome Brunet 	int ret;
139*2c138ee3SJerome Brunet 
140*2c138ee3SJerome Brunet 	data = of_device_get_match_data(dev);
141*2c138ee3SJerome Brunet 	if (!data)
142*2c138ee3SJerome Brunet 		return -EINVAL;
143*2c138ee3SJerome Brunet 
144*2c138ee3SJerome Brunet 	arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
145*2c138ee3SJerome Brunet 	if (!arb)
146*2c138ee3SJerome Brunet 		return -ENOMEM;
147*2c138ee3SJerome Brunet 	platform_set_drvdata(pdev, arb);
148*2c138ee3SJerome Brunet 
149*2c138ee3SJerome Brunet 	arb->clk = devm_clk_get_enabled(dev, NULL);
150*2c138ee3SJerome Brunet 	if (IS_ERR(arb->clk))
151*2c138ee3SJerome Brunet 		return dev_err_probe(dev, PTR_ERR(arb->clk), "failed to get clock\n");
152*2c138ee3SJerome Brunet 
153*2c138ee3SJerome Brunet 	arb->regs = devm_platform_ioremap_resource(pdev, 0);
154*2c138ee3SJerome Brunet 	if (IS_ERR(arb->regs))
155*2c138ee3SJerome Brunet 		return PTR_ERR(arb->regs);
156*2c138ee3SJerome Brunet 
157*2c138ee3SJerome Brunet 	spin_lock_init(&arb->lock);
158*2c138ee3SJerome Brunet 	arb->reset_bits = data->reset_bits;
159*2c138ee3SJerome Brunet 	arb->rstc.nr_resets = data->reset_num;
160*2c138ee3SJerome Brunet 	arb->rstc.ops = &meson_audio_arb_rstc_ops;
161*2c138ee3SJerome Brunet 	arb->rstc.of_node = dev->of_node;
162*2c138ee3SJerome Brunet 	arb->rstc.owner = THIS_MODULE;
163*2c138ee3SJerome Brunet 
164*2c138ee3SJerome Brunet 	/*
165*2c138ee3SJerome Brunet 	 * Enable general :
166*2c138ee3SJerome Brunet 	 * In the initial state, all memory interfaces are disabled
167*2c138ee3SJerome Brunet 	 * and the general bit is on
168*2c138ee3SJerome Brunet 	 */
169*2c138ee3SJerome Brunet 	writel(BIT(ARB_GENERAL_BIT), arb->regs);
170*2c138ee3SJerome Brunet 
171*2c138ee3SJerome Brunet 	/* Register reset controller */
172*2c138ee3SJerome Brunet 	ret = devm_reset_controller_register(dev, &arb->rstc);
173*2c138ee3SJerome Brunet 	if (ret) {
174*2c138ee3SJerome Brunet 		dev_err(dev, "failed to register arb reset controller\n");
175*2c138ee3SJerome Brunet 		meson_audio_arb_remove(pdev);
176*2c138ee3SJerome Brunet 	}
177*2c138ee3SJerome Brunet 
178*2c138ee3SJerome Brunet 	return ret;
179*2c138ee3SJerome Brunet }
180*2c138ee3SJerome Brunet 
181*2c138ee3SJerome Brunet static struct platform_driver meson_audio_arb_pdrv = {
182*2c138ee3SJerome Brunet 	.probe = meson_audio_arb_probe,
183*2c138ee3SJerome Brunet 	.remove_new = meson_audio_arb_remove,
184*2c138ee3SJerome Brunet 	.driver = {
185*2c138ee3SJerome Brunet 		.name = "meson-audio-arb-reset",
186*2c138ee3SJerome Brunet 		.of_match_table = meson_audio_arb_of_match,
187*2c138ee3SJerome Brunet 	},
188*2c138ee3SJerome Brunet };
189*2c138ee3SJerome Brunet module_platform_driver(meson_audio_arb_pdrv);
190*2c138ee3SJerome Brunet 
191*2c138ee3SJerome Brunet MODULE_DESCRIPTION("Amlogic A113 Audio Memory Arbiter");
192*2c138ee3SJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
193*2c138ee3SJerome Brunet MODULE_LICENSE("GPL v2");
194