Skip to content

Commit d903779

Browse files
jbrun3tpH5
authored andcommitted
reset: meson: add meson audio arb driver
The Amlogic Audio ARB is a simple device which enables or disables the access of Audio FIFOs to DDR on AXG based SoC. Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
1 parent 5338073 commit d903779

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed

drivers/reset/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ config RESET_MESON
7373
help
7474
This enables the reset driver for Amlogic Meson SoCs.
7575

76+
config RESET_MESON_AUDIO_ARB
77+
tristate "Meson Audio Memory Arbiter Reset Driver"
78+
depends on ARCH_MESON || COMPILE_TEST
79+
help
80+
This enables the reset driver for Audio Memory Arbiter of
81+
Amlogic's A113 based SoCs
82+
7683
config RESET_OXNAS
7784
bool
7885

drivers/reset/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
1212
obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
1313
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
1414
obj-$(CONFIG_RESET_MESON) += reset-meson.o
15+
obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
1516
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
1617
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
1718
obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o

drivers/reset/reset-meson-audio-arb.c

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

0 commit comments

Comments
 (0)