diff options
Diffstat (limited to 'drivers/reset/reset-imx8mp-audiomix.c')
-rw-r--r-- | drivers/reset/reset-imx8mp-audiomix.c | 78 |
1 files changed, 56 insertions, 22 deletions
diff --git a/drivers/reset/reset-imx8mp-audiomix.c b/drivers/reset/reset-imx8mp-audiomix.c index 6e3f3069f727..6b357adfe646 100644 --- a/drivers/reset/reset-imx8mp-audiomix.c +++ b/drivers/reset/reset-imx8mp-audiomix.c @@ -3,6 +3,8 @@ * Copyright 2024 NXP */ +#include <dt-bindings/reset/imx8mp-reset-audiomix.h> + #include <linux/auxiliary_bus.h> #include <linux/device.h> #include <linux/io.h> @@ -11,8 +13,36 @@ #include <linux/of_address.h> #include <linux/reset-controller.h> -#define EARC 0x200 -#define EARC_RESET_MASK 0x3 +#define IMX8MP_AUDIOMIX_EARC_RESET_OFFSET 0x200 +#define IMX8MP_AUDIOMIX_EARC_RESET_MASK BIT(1) +#define IMX8MP_AUDIOMIX_EARC_PHY_RESET_MASK BIT(2) + +#define IMX8MP_AUDIOMIX_DSP_RUNSTALL_OFFSET 0x108 +#define IMX8MP_AUDIOMIX_DSP_RUNSTALL_MASK BIT(5) + +struct imx8mp_reset_map { + unsigned int offset; + unsigned int mask; + bool active_low; +}; + +static const struct imx8mp_reset_map reset_map[] = { + [IMX8MP_AUDIOMIX_EARC_RESET] = { + .offset = IMX8MP_AUDIOMIX_EARC_RESET_OFFSET, + .mask = IMX8MP_AUDIOMIX_EARC_RESET_MASK, + .active_low = true, + }, + [IMX8MP_AUDIOMIX_EARC_PHY_RESET] = { + .offset = IMX8MP_AUDIOMIX_EARC_RESET_OFFSET, + .mask = IMX8MP_AUDIOMIX_EARC_PHY_RESET_MASK, + .active_low = true, + }, + [IMX8MP_AUDIOMIX_DSP_RUNSTALL] = { + .offset = IMX8MP_AUDIOMIX_DSP_RUNSTALL_OFFSET, + .mask = IMX8MP_AUDIOMIX_DSP_RUNSTALL_MASK, + .active_low = false, + }, +}; struct imx8mp_audiomix_reset { struct reset_controller_dev rcdev; @@ -25,38 +55,42 @@ static struct imx8mp_audiomix_reset *to_imx8mp_audiomix_reset(struct reset_contr return container_of(rcdev, struct imx8mp_audiomix_reset, rcdev); } -static int imx8mp_audiomix_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) +static int imx8mp_audiomix_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) { struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev); void __iomem *reg_addr = priv->base; - unsigned int mask, reg; - unsigned long flags; + unsigned int mask, offset, active_low; + unsigned long reg, flags; + + mask = reset_map[id].mask; + offset = reset_map[id].offset; + active_low = reset_map[id].active_low; - mask = BIT(id); spin_lock_irqsave(&priv->lock, flags); - reg = readl(reg_addr + EARC); - writel(reg & ~mask, reg_addr + EARC); + + reg = readl(reg_addr + offset); + if (active_low ^ assert) + reg |= mask; + else + reg &= ~mask; + writel(reg, reg_addr + offset); + spin_unlock_irqrestore(&priv->lock, flags); return 0; } +static int imx8mp_audiomix_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return imx8mp_audiomix_update(rcdev, id, true); +} + static int imx8mp_audiomix_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { - struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev); - void __iomem *reg_addr = priv->base; - unsigned int mask, reg; - unsigned long flags; - - mask = BIT(id); - spin_lock_irqsave(&priv->lock, flags); - reg = readl(reg_addr + EARC); - writel(reg | mask, reg_addr + EARC); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; + return imx8mp_audiomix_update(rcdev, id, false); } static const struct reset_control_ops imx8mp_audiomix_reset_ops = { @@ -78,7 +112,7 @@ static int imx8mp_audiomix_reset_probe(struct auxiliary_device *adev, spin_lock_init(&priv->lock); priv->rcdev.owner = THIS_MODULE; - priv->rcdev.nr_resets = fls(EARC_RESET_MASK); + priv->rcdev.nr_resets = ARRAY_SIZE(reset_map); priv->rcdev.ops = &imx8mp_audiomix_reset_ops; priv->rcdev.of_node = dev->parent->of_node; priv->rcdev.dev = dev; |