diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-07-16 20:35:27 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-07-16 20:35:27 +0200 |
commit | cc0f7c3f97bc6e888bf4be28a9da9dbd3735d2b4 (patch) | |
tree | ec328d17e2b9ddff11579e8759b9922b4e7a7f48 /drivers/reset/reset-imx8mp-audiomix.c | |
parent | Merge tag 'm68k-for-v6.11-tag1' of git://git.kernel.org/pub/scm/linux/kernel/... (diff) | |
parent | firmware: turris-mox-rwtm: Initialize completion before mailbox (diff) | |
download | linux-cc0f7c3f97bc6e888bf4be28a9da9dbd3735d2b4.tar.xz linux-cc0f7c3f97bc6e888bf4be28a9da9dbd3735d2b4.zip |
Merge tag 'soc-drivers-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC driver updates from Arnd Bergmann:
"The updates to the mediatek, allwinner, ti, tegra, microchip, stm32,
samsung, imx, zynq and amlogic platoforms are fairly small maintenance
changes, either addressing minor mistakes or enabling additional
hardware.
The qualcomm platform changes add a number of features and are larger
than the other ones combined, introducing the use of linux/cleanup.h
across several drivers, adding support for Snapdragon X1E and other
SoCs in platform drivers, a new "protection domain mapper" driver, and
a "shared memory bridge" driver.
The cznic "turris omnia" router based on Marvell Armada gets a
platform driver that talks to the board specific microcontroller.
The reset and cache subsystems get a few minor updates to SoC specific
drivers, while the ff-a, scmi and optee firmware drivers get some code
refactoring and new features"
* tag 'soc-drivers-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (122 commits)
firmware: turris-mox-rwtm: Initialize completion before mailbox
firmware: turris-mox-rwtm: Fix checking return value of wait_for_completion_timeout()
firmware: turris-mox-rwtm: Do not complete if there are no waiters
MAINTAINERS: drop riscv list from cache controllers
platform: cznic: turris-omnia-mcu: fix Kconfig dependencies
bus: sunxi-rsb: Constify struct regmap_bus
soc: sunxi: sram: Constify struct regmap_config
platform: cznic: turris-omnia-mcu: Depend on WATCHDOG
platform: cznic: turris-omnia-mcu: Depend on OF
soc: samsung: exynos-pmu: add support for PMU_ALIVE non atomic registers
arm64: stm32: enable scmi regulator for stm32
firmware: qcom: tzmem: blacklist more platforms for SHM Bridge
soc: qcom: wcnss: simplify with cleanup.h
soc: qcom: pdr: simplify with cleanup.h
soc: qcom: ocmem: simplify with cleanup.h
soc: qcom: mdt_loader: simplify with cleanup.h
soc: qcom: llcc: simplify with cleanup.h
firmware: qcom: tzmem: simplify returning pointer without cleanup
soc: qcom: socinfo: Add PM6350 PMIC
arm64: dts: renesas: rz-smarc: Replace fixed regulator for USB VBUS
...
Diffstat (limited to 'drivers/reset/reset-imx8mp-audiomix.c')
-rw-r--r-- | drivers/reset/reset-imx8mp-audiomix.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/drivers/reset/reset-imx8mp-audiomix.c b/drivers/reset/reset-imx8mp-audiomix.c new file mode 100644 index 000000000000..6e3f3069f727 --- /dev/null +++ b/drivers/reset/reset-imx8mp-audiomix.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2024 NXP + */ + +#include <linux/auxiliary_bus.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/reset-controller.h> + +#define EARC 0x200 +#define EARC_RESET_MASK 0x3 + +struct imx8mp_audiomix_reset { + struct reset_controller_dev rcdev; + spinlock_t lock; /* protect register read-modify-write cycle */ + void __iomem *base; +}; + +static struct imx8mp_audiomix_reset *to_imx8mp_audiomix_reset(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct imx8mp_audiomix_reset, rcdev); +} + +static int imx8mp_audiomix_reset_assert(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; +} + +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; +} + +static const struct reset_control_ops imx8mp_audiomix_reset_ops = { + .assert = imx8mp_audiomix_reset_assert, + .deassert = imx8mp_audiomix_reset_deassert, +}; + +static int imx8mp_audiomix_reset_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct imx8mp_audiomix_reset *priv; + struct device *dev = &adev->dev; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + + priv->rcdev.owner = THIS_MODULE; + priv->rcdev.nr_resets = fls(EARC_RESET_MASK); + priv->rcdev.ops = &imx8mp_audiomix_reset_ops; + priv->rcdev.of_node = dev->parent->of_node; + priv->rcdev.dev = dev; + priv->rcdev.of_reset_n_cells = 1; + priv->base = of_iomap(dev->parent->of_node, 0); + if (!priv->base) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + ret = devm_reset_controller_register(dev, &priv->rcdev); + if (ret) + goto out_unmap; + + return 0; + +out_unmap: + iounmap(priv->base); + return ret; +} + +static void imx8mp_audiomix_reset_remove(struct auxiliary_device *adev) +{ + struct imx8mp_audiomix_reset *priv = dev_get_drvdata(&adev->dev); + + iounmap(priv->base); +} + +static const struct auxiliary_device_id imx8mp_audiomix_reset_ids[] = { + { + .name = "clk_imx8mp_audiomix.reset", + }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, imx8mp_audiomix_reset_ids); + +static struct auxiliary_driver imx8mp_audiomix_reset_driver = { + .probe = imx8mp_audiomix_reset_probe, + .remove = imx8mp_audiomix_reset_remove, + .id_table = imx8mp_audiomix_reset_ids, +}; + +module_auxiliary_driver(imx8mp_audiomix_reset_driver); + +MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>"); +MODULE_DESCRIPTION("Freescale i.MX8MP Audio Block Controller reset driver"); +MODULE_LICENSE("GPL"); |