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

Configure Feed

Select the types of activity you want to include in your feed.

reset: imx8mp-audiomix: Add AudioMix Block Control reset driver

Add support for the resets on i.MX8MP Audio Block Control module,
which includes the EARC PHY software reset and EARC controller
software reset. The reset controller is created using the auxiliary
device framework and set up in the clock driver.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Abel Vesa <abel.vesa@linaro.org>
Link: https://lore.kernel.org/r/1719200345-32006-1-git-send-email-shengjiu.wang@nxp.com
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

authored by

Shengjiu Wang and committed by
Philipp Zabel
fe125601 0e8b3bca

+136
+7
drivers/reset/Kconfig
··· 91 91 help 92 92 This enables the reset controller driver for i.MX7 SoCs. 93 93 94 + config RESET_IMX8MP_AUDIOMIX 95 + tristate "i.MX8MP AudioMix Reset Driver" 96 + select AUXILIARY_BUS 97 + default CLK_IMX8MP 98 + help 99 + This enables the reset controller driver for i.MX8MP AudioMix 100 + 94 101 config RESET_INTEL_GW 95 102 bool "Intel Reset Controller Driver" 96 103 depends on X86 || COMPILE_TEST
+1
drivers/reset/Makefile
··· 14 14 obj-$(CONFIG_RESET_GPIO) += reset-gpio.o 15 15 obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o 16 16 obj-$(CONFIG_RESET_IMX7) += reset-imx7.o 17 + obj-$(CONFIG_RESET_IMX8MP_AUDIOMIX) += reset-imx8mp-audiomix.o 17 18 obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o 18 19 obj-$(CONFIG_RESET_K210) += reset-k210.o 19 20 obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
+128
drivers/reset/reset-imx8mp-audiomix.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright 2024 NXP 4 + */ 5 + 6 + #include <linux/auxiliary_bus.h> 7 + #include <linux/device.h> 8 + #include <linux/io.h> 9 + #include <linux/module.h> 10 + #include <linux/of.h> 11 + #include <linux/of_address.h> 12 + #include <linux/reset-controller.h> 13 + 14 + #define EARC 0x200 15 + #define EARC_RESET_MASK 0x3 16 + 17 + struct imx8mp_audiomix_reset { 18 + struct reset_controller_dev rcdev; 19 + spinlock_t lock; /* protect register read-modify-write cycle */ 20 + void __iomem *base; 21 + }; 22 + 23 + static struct imx8mp_audiomix_reset *to_imx8mp_audiomix_reset(struct reset_controller_dev *rcdev) 24 + { 25 + return container_of(rcdev, struct imx8mp_audiomix_reset, rcdev); 26 + } 27 + 28 + static int imx8mp_audiomix_reset_assert(struct reset_controller_dev *rcdev, 29 + unsigned long id) 30 + { 31 + struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev); 32 + void __iomem *reg_addr = priv->base; 33 + unsigned int mask, reg; 34 + unsigned long flags; 35 + 36 + mask = BIT(id); 37 + spin_lock_irqsave(&priv->lock, flags); 38 + reg = readl(reg_addr + EARC); 39 + writel(reg & ~mask, reg_addr + EARC); 40 + spin_unlock_irqrestore(&priv->lock, flags); 41 + 42 + return 0; 43 + } 44 + 45 + static int imx8mp_audiomix_reset_deassert(struct reset_controller_dev *rcdev, 46 + unsigned long id) 47 + { 48 + struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev); 49 + void __iomem *reg_addr = priv->base; 50 + unsigned int mask, reg; 51 + unsigned long flags; 52 + 53 + mask = BIT(id); 54 + spin_lock_irqsave(&priv->lock, flags); 55 + reg = readl(reg_addr + EARC); 56 + writel(reg | mask, reg_addr + EARC); 57 + spin_unlock_irqrestore(&priv->lock, flags); 58 + 59 + return 0; 60 + } 61 + 62 + static const struct reset_control_ops imx8mp_audiomix_reset_ops = { 63 + .assert = imx8mp_audiomix_reset_assert, 64 + .deassert = imx8mp_audiomix_reset_deassert, 65 + }; 66 + 67 + static int imx8mp_audiomix_reset_probe(struct auxiliary_device *adev, 68 + const struct auxiliary_device_id *id) 69 + { 70 + struct imx8mp_audiomix_reset *priv; 71 + struct device *dev = &adev->dev; 72 + int ret; 73 + 74 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 75 + if (!priv) 76 + return -ENOMEM; 77 + 78 + spin_lock_init(&priv->lock); 79 + 80 + priv->rcdev.owner = THIS_MODULE; 81 + priv->rcdev.nr_resets = fls(EARC_RESET_MASK); 82 + priv->rcdev.ops = &imx8mp_audiomix_reset_ops; 83 + priv->rcdev.of_node = dev->parent->of_node; 84 + priv->rcdev.dev = dev; 85 + priv->rcdev.of_reset_n_cells = 1; 86 + priv->base = of_iomap(dev->parent->of_node, 0); 87 + if (!priv->base) 88 + return -ENOMEM; 89 + 90 + dev_set_drvdata(dev, priv); 91 + 92 + ret = devm_reset_controller_register(dev, &priv->rcdev); 93 + if (ret) 94 + goto out_unmap; 95 + 96 + return 0; 97 + 98 + out_unmap: 99 + iounmap(priv->base); 100 + return ret; 101 + } 102 + 103 + static void imx8mp_audiomix_reset_remove(struct auxiliary_device *adev) 104 + { 105 + struct imx8mp_audiomix_reset *priv = dev_get_drvdata(&adev->dev); 106 + 107 + iounmap(priv->base); 108 + } 109 + 110 + static const struct auxiliary_device_id imx8mp_audiomix_reset_ids[] = { 111 + { 112 + .name = "clk_imx8mp_audiomix.reset", 113 + }, 114 + { } 115 + }; 116 + MODULE_DEVICE_TABLE(auxiliary, imx8mp_audiomix_reset_ids); 117 + 118 + static struct auxiliary_driver imx8mp_audiomix_reset_driver = { 119 + .probe = imx8mp_audiomix_reset_probe, 120 + .remove = imx8mp_audiomix_reset_remove, 121 + .id_table = imx8mp_audiomix_reset_ids, 122 + }; 123 + 124 + module_auxiliary_driver(imx8mp_audiomix_reset_driver); 125 + 126 + MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>"); 127 + MODULE_DESCRIPTION("Freescale i.MX8MP Audio Block Controller reset driver"); 128 + MODULE_LICENSE("GPL");