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