Unverified Commit f42af02c authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'reset-for-v6.11' of git://git.pengutronix.de/pza/linux into soc/drivers

Reset controller updates for v6.11

Move reset controller registration to the end in rzg2l-usbphy-ctrl, to
simplify the probe error path, add a new i.MX8MP AudioMix reset driver,
allow to build some drivers under COMPILE_TEST with fewer dependencies,
and use the devm_clk_get_enabled convenience wrapper in meson-audio-arb.

The latter causes a trivial merge conflict [1] with

  b99e9c09 ("reset: meson-audio-arb: Convert to platform remove callback returning void")

because I didn't manage to send that in last round. There is no overlap
though.

[1] https://lore.kernel.org/all/Znmufb9L78FCoSSS@sirena.org.uk/

* tag 'reset-for-v6.11' of git://git.pengutronix.de/pza/linux:
  reset: RESET_IMX8MP_AUDIOMIX should depend on ARCH_MXC
  reset: zynqmp: allow building under COMPILE_TEST
  reset: imx8mp-audiomix: Add AudioMix Block Control reset driver
  reset: meson-audio-arb: Use devm_clk_get_enabled()
  reset: sti: allow building under COMPILE_TEST
  reset: rzg2l-usbphy-ctrl: Move reset controller registration

Link: https://lore.kernel.org/r/20240626163258.61222-1-p.zabel@pengutronix.de


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents a862a3f7 eb5d88b1
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -91,6 +91,14 @@ config RESET_IMX7
	help
	  This enables the reset controller driver for i.MX7 SoCs.

config RESET_IMX8MP_AUDIOMIX
	tristate "i.MX8MP AudioMix Reset Driver"
	depends on ARCH_MXC || COMPILE_TEST
	select AUXILIARY_BUS
	default CLK_IMX8MP
	help
	  This enables the reset controller driver for i.MX8MP AudioMix

config RESET_INTEL_GW
	bool "Intel Reset Controller Driver"
	depends on X86 || COMPILE_TEST
@@ -328,6 +336,12 @@ config RESET_ZYNQ
	help
	  This enables the reset controller driver for Xilinx Zynq SoCs.

config RESET_ZYNQMP
	bool "ZYNQMP Reset Driver" if COMPILE_TEST
	default ARCH_ZYNQMP
	help
	  This enables the reset controller driver for Xilinx ZynqMP SoCs.

source "drivers/reset/starfive/Kconfig"
source "drivers/reset/sti/Kconfig"
source "drivers/reset/hisilicon/Kconfig"
+3 −2
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
obj-y += core.o
obj-y += hisilicon/
obj-y += starfive/
obj-$(CONFIG_ARCH_STI) += sti/
obj-y += sti/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o
obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
@@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
obj-$(CONFIG_RESET_GPIO) += reset-gpio.o
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
obj-$(CONFIG_RESET_IMX8MP_AUDIOMIX) += reset-imx8mp-audiomix.o
obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o
obj-$(CONFIG_RESET_K210) += reset-k210.o
obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
@@ -41,4 +42,4 @@ obj-$(CONFIG_RESET_TN48M_CPLD) += reset-tn48m.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o
+128 −0
Original line number Diff line number Diff line
// 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");
+1 −8
Original line number Diff line number Diff line
@@ -129,8 +129,6 @@ static int meson_audio_arb_remove(struct platform_device *pdev)
	writel(0, arb->regs);
	spin_unlock(&arb->lock);

	clk_disable_unprepare(arb->clk);

	return 0;
}

@@ -150,7 +148,7 @@ static int meson_audio_arb_probe(struct platform_device *pdev)
		return -ENOMEM;
	platform_set_drvdata(pdev, arb);

	arb->clk = devm_clk_get(dev, NULL);
	arb->clk = devm_clk_get_enabled(dev, NULL);
	if (IS_ERR(arb->clk))
		return dev_err_probe(dev, PTR_ERR(arb->clk), "failed to get clock\n");

@@ -170,11 +168,6 @@ static int meson_audio_arb_probe(struct platform_device *pdev)
	 * In the initial state, all memory interfaces are disabled
	 * and the general bit is on
	 */
	ret = clk_prepare_enable(arb->clk);
	if (ret) {
		dev_err(dev, "failed to enable arb clock\n");
		return ret;
	}
	writel(BIT(ARB_GENERAL_BIT), arb->regs);

	/* Register reset controller */
+19 −13
Original line number Diff line number Diff line
@@ -125,25 +125,14 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
	if (error)
		return error;

	priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops;
	priv->rcdev.of_reset_n_cells = 1;
	priv->rcdev.nr_resets = NUM_PORTS;
	priv->rcdev.of_node = dev->of_node;
	priv->rcdev.dev = dev;

	error = devm_reset_controller_register(dev, &priv->rcdev);
	if (error)
		return error;

	spin_lock_init(&priv->lock);
	dev_set_drvdata(dev, priv);

	pm_runtime_enable(&pdev->dev);
	error = pm_runtime_resume_and_get(&pdev->dev);
	if (error < 0) {
		pm_runtime_disable(&pdev->dev);
		reset_control_assert(priv->rstc);
		return dev_err_probe(&pdev->dev, error, "pm_runtime_resume_and_get failed");
		dev_err_probe(&pdev->dev, error, "pm_runtime_resume_and_get failed");
		goto err_pm_disable_reset_deassert;
	}

	/* put pll and phy into reset state */
@@ -153,7 +142,24 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
	writel(val, priv->base + RESET);
	spin_unlock_irqrestore(&priv->lock, flags);

	priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops;
	priv->rcdev.of_reset_n_cells = 1;
	priv->rcdev.nr_resets = NUM_PORTS;
	priv->rcdev.of_node = dev->of_node;
	priv->rcdev.dev = dev;

	error = devm_reset_controller_register(dev, &priv->rcdev);
	if (error)
		goto err_pm_runtime_put;

	return 0;

err_pm_runtime_put:
	pm_runtime_put(&pdev->dev);
err_pm_disable_reset_deassert:
	pm_runtime_disable(&pdev->dev);
	reset_control_assert(priv->rstc);
	return error;
}

static int rzg2l_usbphy_ctrl_remove(struct platform_device *pdev)
Loading