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