1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 // Copyright (c) 2018 BayLibre, SAS.
3 // Author: Jerome Brunet <jbrunet@baylibre.com>
7 #include <linux/module.h>
8 #include <linux/of_platform.h>
9 #include <linux/reset-controller.h>
10 #include <linux/spinlock.h>
12 #include <dt-bindings/reset/amlogic,meson-axg-audio-arb.h>
14 struct meson_audio_arb_data
{
15 struct reset_controller_dev rstc
;
18 const unsigned int *reset_bits
;
22 #define ARB_GENERAL_BIT 31
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,
33 static int meson_audio_arb_update(struct reset_controller_dev
*rcdev
,
34 unsigned long id
, bool assert)
37 struct meson_audio_arb_data
*arb
=
38 container_of(rcdev
, struct meson_audio_arb_data
, rstc
);
40 spin_lock(&arb
->lock
);
41 val
= readl(arb
->regs
);
44 val
&= ~BIT(arb
->reset_bits
[id
]);
46 val
|= BIT(arb
->reset_bits
[id
]);
48 writel(val
, arb
->regs
);
49 spin_unlock(&arb
->lock
);
54 static int meson_audio_arb_status(struct reset_controller_dev
*rcdev
,
58 struct meson_audio_arb_data
*arb
=
59 container_of(rcdev
, struct meson_audio_arb_data
, rstc
);
61 val
= readl(arb
->regs
);
63 return !(val
& BIT(arb
->reset_bits
[id
]));
66 static int meson_audio_arb_assert(struct reset_controller_dev
*rcdev
,
69 return meson_audio_arb_update(rcdev
, id
, true);
72 static int meson_audio_arb_deassert(struct reset_controller_dev
*rcdev
,
75 return meson_audio_arb_update(rcdev
, id
, false);
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
,
84 static const struct of_device_id meson_audio_arb_of_match
[] = {
85 { .compatible
= "amlogic,meson-axg-audio-arb", },
88 MODULE_DEVICE_TABLE(of
, meson_audio_arb_of_match
);
90 static int meson_audio_arb_remove(struct platform_device
*pdev
)
92 struct meson_audio_arb_data
*arb
= platform_get_drvdata(pdev
);
94 /* Disable all access */
95 spin_lock(&arb
->lock
);
97 spin_unlock(&arb
->lock
);
99 clk_disable_unprepare(arb
->clk
);
104 static int meson_audio_arb_probe(struct platform_device
*pdev
)
106 struct device
*dev
= &pdev
->dev
;
107 struct meson_audio_arb_data
*arb
;
108 struct resource
*res
;
111 arb
= devm_kzalloc(dev
, sizeof(*arb
), GFP_KERNEL
);
114 platform_set_drvdata(pdev
, arb
);
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
);
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
);
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 arb
->rstc
.owner
= THIS_MODULE
;
137 * In the initial state, all memory interfaces are disabled
138 * and the general bit is on
140 ret
= clk_prepare_enable(arb
->clk
);
142 dev_err(dev
, "failed to enable arb clock\n");
145 writel(BIT(ARB_GENERAL_BIT
), arb
->regs
);
147 /* Register reset controller */
148 ret
= devm_reset_controller_register(dev
, &arb
->rstc
);
150 dev_err(dev
, "failed to register arb reset controller\n");
151 meson_audio_arb_remove(pdev
);
157 static struct platform_driver meson_audio_arb_pdrv
= {
158 .probe
= meson_audio_arb_probe
,
159 .remove
= meson_audio_arb_remove
,
161 .name
= "meson-audio-arb-reset",
162 .of_match_table
= meson_audio_arb_of_match
,
165 module_platform_driver(meson_audio_arb_pdrv
);
167 MODULE_DESCRIPTION("Amlogic A113 Audio Memory Arbiter");
168 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
169 MODULE_LICENSE("GPL v2");