Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jerome Brunet and committed by
Philipp Zabel
d903779b 53380735

+176
+7
drivers/reset/Kconfig
··· 73 73 help 74 74 This enables the reset driver for Amlogic Meson SoCs. 75 75 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 + 76 83 config RESET_OXNAS 77 84 bool 78 85
+1
drivers/reset/Makefile
··· 12 12 obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o 13 13 obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o 14 14 obj-$(CONFIG_RESET_MESON) += reset-meson.o 15 + obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o 15 16 obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o 16 17 obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o 17 18 obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
+168
drivers/reset/reset-meson-audio-arb.c
··· 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");