summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2024-11-12 15:59:53 +0100
committerArnd Bergmann <arnd@arndb.de>2024-11-12 15:59:53 +0100
commit7d6f7cfc34a2e38fc1c89f331c30d39e6dde4c18 (patch)
tree101f132982c7082d589b22366f42cffb6dded377
parentec72578ef9453f9352719b5d5d3b7c777ccb09c4 (diff)
parentcf3e10cc0e88bba51d330ef851bcffa0bce1070c (diff)
downloadlinux-7d6f7cfc34a2e38fc1c89f331c30d39e6dde4c18.tar.gz
linux-7d6f7cfc34a2e38fc1c89f331c30d39e6dde4c18.tar.bz2
linux-7d6f7cfc34a2e38fc1c89f331c30d39e6dde4c18.zip
Merge tag 'reset-for-v6.13' of git://git.pengutronix.de/pza/linux into soc/drivers
Reset controller updates for v6.13 * Split the Amlogic reset-meson driver into platform and auxiliary bus drivers. Add support for the reset controller in the G12 and SM1 audio clock controllers. * Replace the list of boolean parameters to the internal reset_control_get functions with an enum reset_flags bitfield, to make the code more self-descriptive. * Add devres helpers to request pre-deasserted (and automatically re-asserting during cleanup) reset controls. This allows reducing boilerplate in drivers that deassert resets for the lifetime of a device. * Use the new auto-deasserting devres helpers in reset-uniphier-glue as an example. * Add support for the LAN966x PCI device in drivers/misc, as a dependency for the following reset-microchip-sparx5 patches. * Add support for being used on the LAN966x PCI device to the reset-microchip-sparx5 driver. Commit 86f134941a4b ("MAINTAINERS: Add the Microchip LAN966x PCI driver entry") introduces a trivial merge conflict with commit 7280f01e79cc ("net: lan969x: add match data for lan969x") from the net-next tree [1]. [1] https://lore.kernel.org/all/20241101122505.3eacd183@canb.auug.org.au/ * tag 'reset-for-v6.13' of git://git.pengutronix.de/pza/linux: (21 commits) misc: lan966x_pci: Fix dtc warn 'Missing interrupt-parent' misc: lan966x_pci: Fix dtc warns 'missing or empty reg/ranges property' reset: mchp: sparx5: set the dev member of the reset controller reset: mchp: sparx5: Allow building as a module reset: mchp: sparx5: Add MCHP_LAN966X_PCI dependency reset: mchp: sparx5: Map cpu-syscon locally in case of LAN966x MAINTAINERS: Add the Microchip LAN966x PCI driver entry misc: Add support for LAN966x PCI device reset: uniphier-glue: Use devm_reset_control_bulk_get_shared_deasserted() reset: Add devres helpers to request pre-deasserted reset controls reset: replace boolean parameters with flags parameter reset: amlogic: Fix small whitespace issue reset: amlogic: add auxiliary reset driver support reset: amlogic: split the device core and platform probe reset: amlogic: move drivers to a dedicated directory reset: amlogic: add reset status support reset: amlogic: use reset number instead of register count reset: amlogic: add driver parameters reset: amlogic: make parameters unsigned reset: amlogic: use generic data matching function ... Link: https://lore.kernel.org/r/20241105105229.3729474-1-p.zabel@pengutronix.de Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/misc/Kconfig24
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/lan966x_pci.c215
-rw-r--r--drivers/misc/lan966x_pci.dtso177
-rw-r--r--drivers/pci/quirks.c1
-rw-r--r--drivers/reset/Kconfig19
-rw-r--r--drivers/reset/Makefile3
-rw-r--r--drivers/reset/amlogic/Kconfig27
-rw-r--r--drivers/reset/amlogic/Makefile4
-rw-r--r--drivers/reset/amlogic/reset-meson-audio-arb.c (renamed from drivers/reset/reset-meson-audio-arb.c)0
-rw-r--r--drivers/reset/amlogic/reset-meson-aux.c136
-rw-r--r--drivers/reset/amlogic/reset-meson-common.c142
-rw-r--r--drivers/reset/amlogic/reset-meson.c105
-rw-r--r--drivers/reset/amlogic/reset-meson.h28
-rw-r--r--drivers/reset/core.c119
-rw-r--r--drivers/reset/reset-meson.c159
-rw-r--r--drivers/reset/reset-microchip-sparx5.c38
-rw-r--r--drivers/reset/reset-uniphier-glue.c24
-rw-r--r--include/linux/reset.h274
-rw-r--r--include/soc/amlogic/reset-meson-aux.h23
21 files changed, 1235 insertions, 292 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 8c07a7b62bbb..aa69b7fef86d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15087,6 +15087,12 @@ S: Maintained
F: Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml
F: drivers/irqchip/irq-lan966x-oic.c
+MICROCHIP LAN966X PCI DRIVER
+M: Herve Codina <herve.codina@bootlin.com>
+S: Maintained
+F: drivers/misc/lan966x_pci.c
+F: drivers/misc/lan966x_pci.dtso
+
MICROCHIP LCDFB DRIVER
M: Nicolas Ferre <nicolas.ferre@microchip.com>
L: linux-fbdev@vger.kernel.org
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3fe7e2a9bd29..902c306bc972 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -610,6 +610,30 @@ config MARVELL_CN10K_DPI
To compile this driver as a module, choose M here: the module
will be called mrvl_cn10k_dpi.
+config MCHP_LAN966X_PCI
+ tristate "Microchip LAN966x PCIe Support"
+ depends on PCI
+ select OF
+ select OF_OVERLAY
+ select IRQ_DOMAIN
+ help
+ This enables the support for the LAN966x PCIe device.
+
+ This is used to drive the LAN966x PCIe device from the host system
+ to which it is connected. The driver uses a device tree overlay to
+ load other drivers to support for LAN966x internal components.
+
+ Even if this driver does not depend on those other drivers, in order
+ to have a fully functional board, the following drivers are needed:
+ - fixed-clock (COMMON_CLK)
+ - lan966x-oic (LAN966X_OIC)
+ - lan966x-cpu-syscon (MFD_SYSCON)
+ - lan966x-switch-reset (RESET_MCHP_SPARX5)
+ - lan966x-pinctrl (PINCTRL_OCELOT)
+ - lan966x-serdes (PHY_LAN966X_SERDES)
+ - lan966x-miim (MDIO_MSCC_MIIM)
+ - lan966x-switch (LAN966X_SWITCH)
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a9f94525e181..885b22989580 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -71,4 +71,7 @@ obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o
obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o
obj-$(CONFIG_NSM) += nsm.o
obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o
+lan966x-pci-objs := lan966x_pci.o
+lan966x-pci-objs += lan966x_pci.dtbo.o
+obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o
obj-y += keba/
diff --git a/drivers/misc/lan966x_pci.c b/drivers/misc/lan966x_pci.c
new file mode 100644
index 000000000000..9c79b58137e5
--- /dev/null
+++ b/drivers/misc/lan966x_pci.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip LAN966x PCI driver
+ *
+ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
+ *
+ * Authors:
+ * Clément Léger <clement.leger@bootlin.com>
+ * Hervé Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+
+/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */
+extern char __dtbo_lan966x_pci_begin[];
+extern char __dtbo_lan966x_pci_end[];
+
+struct pci_dev_intr_ctrl {
+ struct pci_dev *pci_dev;
+ struct irq_domain *irq_domain;
+ int irq;
+};
+
+static int pci_dev_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq);
+ return 0;
+}
+
+static const struct irq_domain_ops pci_dev_irq_domain_ops = {
+ .map = pci_dev_irq_domain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static irqreturn_t pci_dev_irq_handler(int irq, void *data)
+{
+ struct pci_dev_intr_ctrl *intr_ctrl = data;
+ int ret;
+
+ ret = generic_handle_domain_irq(intr_ctrl->irq_domain, 0);
+ return ret ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static struct pci_dev_intr_ctrl *pci_dev_create_intr_ctrl(struct pci_dev *pdev)
+{
+ struct pci_dev_intr_ctrl *intr_ctrl __free(kfree) = NULL;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ fwnode = dev_fwnode(&pdev->dev);
+ if (!fwnode)
+ return ERR_PTR(-ENODEV);
+
+ intr_ctrl = kmalloc(sizeof(*intr_ctrl), GFP_KERNEL);
+ if (!intr_ctrl)
+ return ERR_PTR(-ENOMEM);
+
+ intr_ctrl->pci_dev = pdev;
+
+ intr_ctrl->irq_domain = irq_domain_create_linear(fwnode, 1, &pci_dev_irq_domain_ops,
+ intr_ctrl);
+ if (!intr_ctrl->irq_domain) {
+ pci_err(pdev, "Failed to create irqdomain\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX);
+ if (ret < 0) {
+ pci_err(pdev, "Unable alloc irq vector (%d)\n", ret);
+ goto err_remove_domain;
+ }
+ intr_ctrl->irq = pci_irq_vector(pdev, 0);
+ ret = request_irq(intr_ctrl->irq, pci_dev_irq_handler, IRQF_SHARED,
+ pci_name(pdev), intr_ctrl);
+ if (ret) {
+ pci_err(pdev, "Unable to request irq %d (%d)\n", intr_ctrl->irq, ret);
+ goto err_free_irq_vector;
+ }
+
+ return_ptr(intr_ctrl);
+
+err_free_irq_vector:
+ pci_free_irq_vectors(pdev);
+err_remove_domain:
+ irq_domain_remove(intr_ctrl->irq_domain);
+ return ERR_PTR(ret);
+}
+
+static void pci_dev_remove_intr_ctrl(struct pci_dev_intr_ctrl *intr_ctrl)
+{
+ free_irq(intr_ctrl->irq, intr_ctrl);
+ pci_free_irq_vectors(intr_ctrl->pci_dev);
+ irq_dispose_mapping(irq_find_mapping(intr_ctrl->irq_domain, 0));
+ irq_domain_remove(intr_ctrl->irq_domain);
+ kfree(intr_ctrl);
+}
+
+static void devm_pci_dev_remove_intr_ctrl(void *intr_ctrl)
+{
+ pci_dev_remove_intr_ctrl(intr_ctrl);
+}
+
+static int devm_pci_dev_create_intr_ctrl(struct pci_dev *pdev)
+{
+ struct pci_dev_intr_ctrl *intr_ctrl;
+
+ intr_ctrl = pci_dev_create_intr_ctrl(pdev);
+ if (IS_ERR(intr_ctrl))
+ return PTR_ERR(intr_ctrl);
+
+ return devm_add_action_or_reset(&pdev->dev, devm_pci_dev_remove_intr_ctrl, intr_ctrl);
+}
+
+struct lan966x_pci {
+ struct device *dev;
+ int ovcs_id;
+};
+
+static int lan966x_pci_load_overlay(struct lan966x_pci *data)
+{
+ u32 dtbo_size = __dtbo_lan966x_pci_end - __dtbo_lan966x_pci_begin;
+ void *dtbo_start = __dtbo_lan966x_pci_begin;
+
+ return of_overlay_fdt_apply(dtbo_start, dtbo_size, &data->ovcs_id, dev_of_node(data->dev));
+}
+
+static void lan966x_pci_unload_overlay(struct lan966x_pci *data)
+{
+ of_overlay_remove(&data->ovcs_id);
+}
+
+static int lan966x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct lan966x_pci *data;
+ int ret;
+
+ /*
+ * On ACPI system, fwnode can point to the ACPI node.
+ * This driver needs an of_node to be used as the device-tree overlay
+ * target. This of_node should be set by the PCI core if it succeeds in
+ * creating it (CONFIG_PCI_DYNAMIC_OF_NODES feature).
+ * Check here for the validity of this of_node.
+ */
+ if (!dev_of_node(dev))
+ return dev_err_probe(dev, -EINVAL, "Missing of_node for device\n");
+
+ /* Need to be done before devm_pci_dev_create_intr_ctrl.
+ * It allocates an IRQ and so pdev->irq is updated.
+ */
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ ret = devm_pci_dev_create_intr_ctrl(pdev);
+ if (ret)
+ return ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, data);
+ data->dev = dev;
+
+ ret = lan966x_pci_load_overlay(data);
+ if (ret)
+ return ret;
+
+ pci_set_master(pdev);
+
+ ret = of_platform_default_populate(dev_of_node(dev), NULL, dev);
+ if (ret)
+ goto err_unload_overlay;
+
+ return 0;
+
+err_unload_overlay:
+ lan966x_pci_unload_overlay(data);
+ return ret;
+}
+
+static void lan966x_pci_remove(struct pci_dev *pdev)
+{
+ struct lan966x_pci *data = pci_get_drvdata(pdev);
+
+ of_platform_depopulate(data->dev);
+
+ lan966x_pci_unload_overlay(data);
+}
+
+static struct pci_device_id lan966x_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_EFAR, 0x9660) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, lan966x_pci_ids);
+
+static struct pci_driver lan966x_pci_driver = {
+ .name = "mchp_lan966x_pci",
+ .id_table = lan966x_pci_ids,
+ .probe = lan966x_pci_probe,
+ .remove = lan966x_pci_remove,
+};
+module_pci_driver(lan966x_pci_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("Microchip LAN966x PCI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/lan966x_pci.dtso b/drivers/misc/lan966x_pci.dtso
new file mode 100644
index 000000000000..7b196b0a0eb6
--- /dev/null
+++ b/drivers/misc/lan966x_pci.dtso
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Microchip UNG
+ */
+
+#include <dt-bindings/clock/microchip,lan966x.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+#include <dt-bindings/phy/phy-lan966x-serdes.h>
+
+/dts-v1/;
+/plugin/;
+
+/ {
+ fragment@0 {
+ target-path = "";
+
+ /*
+ * These properties allow to avoid a dtc warnings.
+ * The real interrupt controller is the PCI device itself. It
+ * is the node on which the device tree overlay will be applied.
+ * This node has those properties.
+ */
+ #interrupt-cells = <1>;
+ interrupt-controller;
+
+ __overlay__ {
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ cpu_clk: clock-600000000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <600000000>; /* CPU clock = 600MHz */
+ };
+
+ ddr_clk: clock-30000000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <30000000>; /* Fabric clock = 30MHz */
+ };
+
+ sys_clk: clock-15625000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <15625000>; /* System clock = 15.625MHz */
+ };
+
+ pci-ep-bus@0 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /*
+ * map @0xe2000000 (32MB) to BAR0 (CPU)
+ * map @0xe0000000 (16MB) to BAR1 (AMBA)
+ */
+ ranges = <0xe2000000 0x00 0x00 0x00 0x2000000
+ 0xe0000000 0x01 0x00 0x00 0x1000000>;
+
+ oic: oic@e00c0120 {
+ compatible = "microchip,lan966x-oic";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupts = <0>; /* PCI INTx assigned interrupt */
+ reg = <0xe00c0120 0x190>;
+ };
+
+ cpu_ctrl: syscon@e00c0000 {
+ compatible = "microchip,lan966x-cpu-syscon", "syscon";
+ reg = <0xe00c0000 0xa8>;
+ };
+
+ reset: reset@e200400c {
+ compatible = "microchip,lan966x-switch-reset";
+ reg = <0xe200400c 0x4>, <0xe00c0000 0xa8>;
+ reg-names = "gcb","cpu";
+ #reset-cells = <1>;
+ cpu-syscon = <&cpu_ctrl>;
+ };
+
+ gpio: pinctrl@e2004064 {
+ compatible = "microchip,lan966x-pinctrl";
+ reg = <0xe2004064 0xb4>,
+ <0xe2010024 0x138>;
+ resets = <&reset 0>;
+ reset-names = "switch";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&gpio 0 0 78>;
+ interrupt-parent = <&oic>;
+ interrupt-controller;
+ interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+ #interrupt-cells = <2>;
+
+ tod_pins: tod_pins {
+ pins = "GPIO_36";
+ function = "ptpsync_1";
+ };
+
+ fc0_a_pins: fcb4-i2c-pins {
+ /* RXD, TXD */
+ pins = "GPIO_9", "GPIO_10";
+ function = "fc0_a";
+ };
+
+ };
+
+ serdes: serdes@e202c000 {
+ compatible = "microchip,lan966x-serdes";
+ reg = <0xe202c000 0x9c>,
+ <0xe2004010 0x4>;
+ #phy-cells = <2>;
+ };
+
+ mdio1: mdio@e200413c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "microchip,lan966x-miim";
+ reg = <0xe200413c 0x24>,
+ <0xe2010020 0x4>;
+
+ resets = <&reset 0>;
+ reset-names = "switch";
+
+ lan966x_phy0: ethernet-lan966x_phy@1 {
+ reg = <1>;
+ };
+
+ lan966x_phy1: ethernet-lan966x_phy@2 {
+ reg = <2>;
+ };
+ };
+
+ switch: switch@e0000000 {
+ compatible = "microchip,lan966x-switch";
+ reg = <0xe0000000 0x0100000>,
+ <0xe2000000 0x0800000>;
+ reg-names = "cpu", "gcb";
+
+ interrupt-parent = <&oic>;
+ interrupts = <12 IRQ_TYPE_LEVEL_HIGH>,
+ <9 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "xtr", "ana";
+
+ resets = <&reset 0>;
+ reset-names = "switch";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tod_pins>;
+
+ ethernet-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port0: port@0 {
+ phy-handle = <&lan966x_phy0>;
+
+ reg = <0>;
+ phy-mode = "gmii";
+ phys = <&serdes 0 CU(0)>;
+ };
+
+ port1: port@1 {
+ phy-handle = <&lan966x_phy1>;
+
+ reg = <1>;
+ phy-mode = "gmii";
+ phys = <&serdes 1 CU(1)>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index dccb60c1d9cc..41dec625ed7b 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -6266,6 +6266,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa76e, dpc_log_size);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REDHAT, 0x0005, of_pci_make_dev_node);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, 0x9660, of_pci_make_dev_node);
/*
* Devices known to require a longer delay before first config space access
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 5484a65f66b9..18374555888d 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -146,27 +146,13 @@ config RESET_LPC18XX
This enables the reset controller driver for NXP LPC18xx/43xx SoCs.
config RESET_MCHP_SPARX5
- bool "Microchip Sparx5 reset driver"
- depends on ARCH_SPARX5 || SOC_LAN966 || COMPILE_TEST
+ tristate "Microchip Sparx5 reset driver"
+ depends on ARCH_SPARX5 || SOC_LAN966 || MCHP_LAN966X_PCI || COMPILE_TEST
default y if SPARX5_SWITCH
select MFD_SYSCON
help
This driver supports switch core reset for the Microchip Sparx5 SoC.
-config RESET_MESON
- tristate "Meson Reset Driver"
- depends on ARCH_MESON || COMPILE_TEST
- default ARCH_MESON
- help
- This enables the reset driver for Amlogic Meson SoCs.
-
-config RESET_MESON_AUDIO_ARB
- tristate "Meson Audio Memory Arbiter Reset Driver"
- depends on ARCH_MESON || COMPILE_TEST
- help
- This enables the reset driver for Audio Memory Arbiter of
- Amlogic's A113 based SoCs
-
config RESET_NPCM
bool "NPCM BMC Reset Driver" if COMPILE_TEST
default ARCH_NPCM
@@ -356,6 +342,7 @@ config RESET_ZYNQMP
help
This enables the reset controller driver for Xilinx ZynqMP SoCs.
+source "drivers/reset/amlogic/Kconfig"
source "drivers/reset/starfive/Kconfig"
source "drivers/reset/sti/Kconfig"
source "drivers/reset/hisilicon/Kconfig"
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 4411a2a124d7..677c4d1e2632 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += core.o
+obj-y += amlogic/
obj-y += hisilicon/
obj-y += starfive/
obj-y += sti/
@@ -21,8 +22,6 @@ obj-$(CONFIG_RESET_K210) += reset-k210.o
obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
-obj-$(CONFIG_RESET_MESON) += reset-meson.o
-obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
obj-$(CONFIG_RESET_NUVOTON_MA35D1) += reset-ma35d1.o
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
diff --git a/drivers/reset/amlogic/Kconfig b/drivers/reset/amlogic/Kconfig
new file mode 100644
index 000000000000..3bee9fd60269
--- /dev/null
+++ b/drivers/reset/amlogic/Kconfig
@@ -0,0 +1,27 @@
+config RESET_MESON_COMMON
+ tristate
+ select REGMAP
+
+config RESET_MESON
+ tristate "Meson Reset Driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ default ARCH_MESON
+ select REGMAP_MMIO
+ select RESET_MESON_COMMON
+ help
+ This enables the reset driver for Amlogic SoCs.
+
+config RESET_MESON_AUX
+ tristate "Meson Reset Auxiliary Driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ select AUXILIARY_BUS
+ select RESET_MESON_COMMON
+ help
+ This enables the reset auxiliary driver for Amlogic SoCs.
+
+config RESET_MESON_AUDIO_ARB
+ tristate "Meson Audio Memory Arbiter Reset Driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ help
+ This enables the reset driver for Audio Memory Arbiter of
+ Amlogic's A113 based SoCs
diff --git a/drivers/reset/amlogic/Makefile b/drivers/reset/amlogic/Makefile
new file mode 100644
index 000000000000..ca99a691282c
--- /dev/null
+++ b/drivers/reset/amlogic/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_RESET_MESON) += reset-meson.o
+obj-$(CONFIG_RESET_MESON_AUX) += reset-meson-aux.o
+obj-$(CONFIG_RESET_MESON_COMMON) += reset-meson-common.o
+obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
diff --git a/drivers/reset/reset-meson-audio-arb.c b/drivers/reset/amlogic/reset-meson-audio-arb.c
index 421ccb40da8c..421ccb40da8c 100644
--- a/drivers/reset/reset-meson-audio-arb.c
+++ b/drivers/reset/amlogic/reset-meson-audio-arb.c
diff --git a/drivers/reset/amlogic/reset-meson-aux.c b/drivers/reset/amlogic/reset-meson-aux.c
new file mode 100644
index 000000000000..dd8453001db9
--- /dev/null
+++ b/drivers/reset/amlogic/reset-meson-aux.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Amlogic Meson Reset Auxiliary driver
+ *
+ * Copyright (c) 2024 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+#include "reset-meson.h"
+#include <soc/amlogic/reset-meson-aux.h>
+
+static DEFINE_IDA(meson_rst_aux_ida);
+
+struct meson_reset_adev {
+ struct auxiliary_device adev;
+ struct regmap *map;
+};
+
+#define to_meson_reset_adev(_adev) \
+ container_of((_adev), struct meson_reset_adev, adev)
+
+static const struct meson_reset_param meson_g12a_audio_param = {
+ .reset_ops = &meson_reset_toggle_ops,
+ .reset_num = 26,
+ .level_offset = 0x24,
+};
+
+static const struct meson_reset_param meson_sm1_audio_param = {
+ .reset_ops = &meson_reset_toggle_ops,
+ .reset_num = 39,
+ .level_offset = 0x28,
+};
+
+static const struct auxiliary_device_id meson_reset_aux_ids[] = {
+ {
+ .name = "axg-audio-clkc.rst-g12a",
+ .driver_data = (kernel_ulong_t)&meson_g12a_audio_param,
+ }, {
+ .name = "axg-audio-clkc.rst-sm1",
+ .driver_data = (kernel_ulong_t)&meson_sm1_audio_param,
+ }, {}
+};
+MODULE_DEVICE_TABLE(auxiliary, meson_reset_aux_ids);
+
+static int meson_reset_aux_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ const struct meson_reset_param *param =
+ (const struct meson_reset_param *)(id->driver_data);
+ struct meson_reset_adev *raux =
+ to_meson_reset_adev(adev);
+
+ return meson_reset_controller_register(&adev->dev, raux->map, param);
+}
+
+static struct auxiliary_driver meson_reset_aux_driver = {
+ .probe = meson_reset_aux_probe,
+ .id_table = meson_reset_aux_ids,
+};
+module_auxiliary_driver(meson_reset_aux_driver);
+
+static void meson_rst_aux_release(struct device *dev)
+{
+ struct auxiliary_device *adev = to_auxiliary_dev(dev);
+ struct meson_reset_adev *raux =
+ to_meson_reset_adev(adev);
+
+ ida_free(&meson_rst_aux_ida, adev->id);
+ kfree(raux);
+}
+
+static void meson_rst_aux_unregister_adev(void *_adev)
+{
+ struct auxiliary_device *adev = _adev;
+
+ auxiliary_device_delete(adev);
+ auxiliary_device_uninit(adev);
+}
+
+int devm_meson_rst_aux_register(struct device *dev,
+ struct regmap *map,
+ const char *adev_name)
+{
+ struct meson_reset_adev *raux;
+ struct auxiliary_device *adev;
+ int ret;
+
+ raux = kzalloc(sizeof(*raux), GFP_KERNEL);
+ if (!raux)
+ return -ENOMEM;
+
+ ret = ida_alloc(&meson_rst_aux_ida, GFP_KERNEL);
+ if (ret < 0)
+ goto raux_free;
+
+ raux->map = map;
+
+ adev = &raux->adev;
+ adev->id = ret;
+ adev->name = adev_name;
+ adev->dev.parent = dev;
+ adev->dev.release = meson_rst_aux_release;
+ device_set_of_node_from_dev(&adev->dev, dev);
+
+ ret = auxiliary_device_init(adev);
+ if (ret)
+ goto ida_free;
+
+ ret = __auxiliary_device_add(adev, dev->driver->name);
+ if (ret) {
+ auxiliary_device_uninit(adev);
+ return ret;
+ }
+
+ return devm_add_action_or_reset(dev, meson_rst_aux_unregister_adev,
+ adev);
+
+ida_free:
+ ida_free(&meson_rst_aux_ida, adev->id);
+raux_free:
+ kfree(raux);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_meson_rst_aux_register);
+
+MODULE_DESCRIPTION("Amlogic Meson Reset Auxiliary driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(MESON_RESET);
diff --git a/drivers/reset/amlogic/reset-meson-common.c b/drivers/reset/amlogic/reset-meson-common.c
new file mode 100644
index 000000000000..38a767c06fc7
--- /dev/null
+++ b/drivers/reset/amlogic/reset-meson-common.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Amlogic Meson Reset core functions
+ *
+ * Copyright (c) 2016-2024 BayLibre, SAS.
+ * Authors: Neil Armstrong <narmstrong@baylibre.com>
+ * Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include "reset-meson.h"
+
+struct meson_reset {
+ const struct meson_reset_param *param;
+ struct reset_controller_dev rcdev;
+ struct regmap *map;
+};
+
+static void meson_reset_offset_and_bit(struct meson_reset *data,
+ unsigned long id,
+ unsigned int *offset,
+ unsigned int *bit)
+{
+ unsigned int stride = regmap_get_reg_stride(data->map);
+
+ *offset = (id / (stride * BITS_PER_BYTE)) * stride;
+ *bit = id % (stride * BITS_PER_BYTE);
+}
+
+static int meson_reset_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct meson_reset *data =
+ container_of(rcdev, struct meson_reset, rcdev);
+ unsigned int offset, bit;
+
+ meson_reset_offset_and_bit(data, id, &offset, &bit);
+ offset += data->param->reset_offset;
+
+ return regmap_write(data->map, offset, BIT(bit));
+}
+
+static int meson_reset_level(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct meson_reset *data =
+ container_of(rcdev, struct meson_reset, rcdev);
+ unsigned int offset, bit;
+
+ meson_reset_offset_and_bit(data, id, &offset, &bit);
+ offset += data->param->level_offset;
+ assert ^= data->param->level_low_reset;
+
+ return regmap_update_bits(data->map, offset,
+ BIT(bit), assert ? BIT(bit) : 0);
+}
+
+static int meson_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct meson_reset *data =
+ container_of(rcdev, struct meson_reset, rcdev);
+ unsigned int val, offset, bit;
+
+ meson_reset_offset_and_bit(data, id, &offset, &bit);
+ offset += data->param->level_offset;
+
+ regmap_read(data->map, offset, &val);
+ val = !!(BIT(bit) & val);
+
+ return val ^ data->param->level_low_reset;
+}
+
+static int meson_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return meson_reset_level(rcdev, id, true);
+}
+
+static int meson_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return meson_reset_level(rcdev, id, false);
+}
+
+static int meson_reset_level_toggle(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ int ret;
+
+ ret = meson_reset_assert(rcdev, id);
+ if (ret)
+ return ret;
+
+ return meson_reset_deassert(rcdev, id);
+}
+
+const struct reset_control_ops meson_reset_ops = {
+ .reset = meson_reset_reset,
+ .assert = meson_reset_assert,
+ .deassert = meson_reset_deassert,
+ .status = meson_reset_status,
+};
+EXPORT_SYMBOL_NS_GPL(meson_reset_ops, MESON_RESET);
+
+const struct reset_control_ops meson_reset_toggle_ops = {
+ .reset = meson_reset_level_toggle,
+ .assert = meson_reset_assert,
+ .deassert = meson_reset_deassert,
+ .status = meson_reset_status,
+};
+EXPORT_SYMBOL_NS_GPL(meson_reset_toggle_ops, MESON_RESET);
+
+int meson_reset_controller_register(struct device *dev, struct regmap *map,
+ const struct meson_reset_param *param)
+{
+ struct meson_reset *data;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->param = param;
+ data->map = map;
+ data->rcdev.owner = dev->driver->owner;
+ data->rcdev.nr_resets = param->reset_num;
+ data->rcdev.ops = data->param->reset_ops;
+ data->rcdev.of_node = dev->of_node;
+
+ return devm_reset_controller_register(dev, &data->rcdev);
+}
+EXPORT_SYMBOL_NS_GPL(meson_reset_controller_register, MESON_RESET);
+
+MODULE_DESCRIPTION("Amlogic Meson Reset Core function");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(MESON_RESET);
diff --git a/drivers/reset/amlogic/reset-meson.c b/drivers/reset/amlogic/reset-meson.c
new file mode 100644
index 000000000000..6ae4ed6b7f8b
--- /dev/null
+++ b/drivers/reset/amlogic/reset-meson.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Amlogic Meson Reset Controller driver
+ *
+ * Copyright (c) 2016-2024 BayLibre, SAS.
+ * Authors: Neil Armstrong <narmstrong@baylibre.com>
+ * Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include "reset-meson.h"
+
+static const struct meson_reset_param meson8b_param = {
+ .reset_ops = &meson_reset_ops,
+ .reset_num = 256,
+ .reset_offset = 0x0,
+ .level_offset = 0x7c,
+ .level_low_reset = true,
+};
+
+static const struct meson_reset_param meson_a1_param = {
+ .reset_ops = &meson_reset_ops,
+ .reset_num = 96,
+ .reset_offset = 0x0,
+ .level_offset = 0x40,
+ .level_low_reset = true,
+};
+
+static const struct meson_reset_param meson_s4_param = {
+ .reset_ops = &meson_reset_ops,
+ .reset_num = 192,
+ .reset_offset = 0x0,
+ .level_offset = 0x40,
+ .level_low_reset = true,
+};
+
+static const struct meson_reset_param t7_param = {
+ .reset_num = 224,
+ .reset_offset = 0x0,
+ .level_offset = 0x40,
+ .level_low_reset = true,
+};
+
+static const struct of_device_id meson_reset_dt_ids[] = {
+ { .compatible = "amlogic,meson8b-reset", .data = &meson8b_param},
+ { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param},
+ { .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param},
+ { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param},
+ { .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param},
+ { .compatible = "amlogic,c3-reset", .data = &meson_s4_param},
+ { .compatible = "amlogic,t7-reset", .data = &t7_param},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int meson_reset_probe(struct platform_device *pdev)
+{
+ const struct meson_reset_param *param;
+ struct device *dev = &pdev->dev;
+ struct regmap *map;
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ param = device_get_match_data(dev);
+ if (!param)
+ return -ENODEV;
+
+ map = devm_regmap_init_mmio(dev, base, &regmap_config);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map),
+ "can't init regmap mmio region\n");
+
+ return meson_reset_controller_register(dev, map, param);
+}
+
+static struct platform_driver meson_reset_driver = {
+ .probe = meson_reset_probe,
+ .driver = {
+ .name = "meson_reset",
+ .of_match_table = meson_reset_dt_ids,
+ },
+};
+module_platform_driver(meson_reset_driver);
+
+MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(MESON_RESET);
diff --git a/drivers/reset/amlogic/reset-meson.h b/drivers/reset/amlogic/reset-meson.h
new file mode 100644
index 000000000000..2051e126dc3a
--- /dev/null
+++ b/drivers/reset/amlogic/reset-meson.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (c) 2024 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_RESET_H
+#define __MESON_RESET_H
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+struct meson_reset_param {
+ const struct reset_control_ops *reset_ops;
+ unsigned int reset_num;
+ unsigned int reset_offset;
+ unsigned int level_offset;
+ bool level_low_reset;
+};
+
+int meson_reset_controller_register(struct device *dev, struct regmap *map,
+ const struct meson_reset_param *param);
+
+extern const struct reset_control_ops meson_reset_ops;
+extern const struct reset_control_ops meson_reset_toggle_ops;
+
+#endif /* __MESON_RESET_H */
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 4d509d41456a..22f67fc77ae5 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -773,12 +773,19 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_release);
static struct reset_control *
__reset_control_get_internal(struct reset_controller_dev *rcdev,
- unsigned int index, bool shared, bool acquired)
+ unsigned int index, enum reset_control_flags flags)
{
+ bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED;
+ bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED;
struct reset_control *rstc;
lockdep_assert_held(&reset_list_mutex);
+ /* Expect callers to filter out OPTIONAL and DEASSERTED bits */
+ if (WARN_ON(flags & ~(RESET_CONTROL_FLAGS_BIT_SHARED |
+ RESET_CONTROL_FLAGS_BIT_ACQUIRED)))
+ return ERR_PTR(-EINVAL);
+
list_for_each_entry(rstc, &rcdev->reset_control_head, list) {
if (rstc->id == index) {
/*
@@ -994,8 +1001,9 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a
struct reset_control *
__of_reset_control_get(struct device_node *node, const char *id, int index,
- bool shared, bool optional, bool acquired)
+ enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
bool gpio_fallback = false;
struct reset_control *rstc;
struct reset_controller_dev *rcdev;
@@ -1059,8 +1067,10 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
goto out_unlock;
}
+ flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
/* reset_list_mutex also protects the rcdev's reset_control list */
- rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired);
+ rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
out_unlock:
mutex_unlock(&reset_list_mutex);
@@ -1091,8 +1101,9 @@ __reset_controller_by_name(const char *name)
static struct reset_control *
__reset_control_get_from_lookup(struct device *dev, const char *con_id,
- bool shared, bool optional, bool acquired)
+ enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
const struct reset_control_lookup *lookup;
struct reset_controller_dev *rcdev;
const char *dev_id = dev_name(dev);
@@ -1116,9 +1127,11 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id,
return ERR_PTR(-EPROBE_DEFER);
}
+ flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
rstc = __reset_control_get_internal(rcdev,
lookup->index,
- shared, acquired);
+ flags);
mutex_unlock(&reset_list_mutex);
break;
}
@@ -1133,30 +1146,29 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id,
}
struct reset_control *__reset_control_get(struct device *dev, const char *id,
- int index, bool shared, bool optional,
- bool acquired)
+ int index, enum reset_control_flags flags)
{
+ bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED;
+ bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED;
+
if (WARN_ON(shared && acquired))
return ERR_PTR(-EINVAL);
if (dev->of_node)
- return __of_reset_control_get(dev->of_node, id, index, shared,
- optional, acquired);
+ return __of_reset_control_get(dev->of_node, id, index, flags);
- return __reset_control_get_from_lookup(dev, id, shared, optional,
- acquired);
+ return __reset_control_get_from_lookup(dev, id, flags);
}
EXPORT_SYMBOL_GPL(__reset_control_get);
int __reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
- bool shared, bool optional, bool acquired)
+ enum reset_control_flags flags)
{
int ret, i;
for (i = 0; i < num_rstcs; i++) {
- rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0,
- shared, optional, acquired);
+ rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0, flags);
if (IS_ERR(rstcs[i].rstc)) {
ret = PTR_ERR(rstcs[i].rstc);
goto err;
@@ -1224,23 +1236,46 @@ static void devm_reset_control_release(struct device *dev, void *res)
reset_control_put(*(struct reset_control **)res);
}
+static void devm_reset_control_release_deasserted(struct device *dev, void *res)
+{
+ struct reset_control *rstc = *(struct reset_control **)res;
+
+ reset_control_assert(rstc);
+ reset_control_put(rstc);
+}
+
struct reset_control *
__devm_reset_control_get(struct device *dev, const char *id, int index,
- bool shared, bool optional, bool acquired)
+ enum reset_control_flags flags)
{
struct reset_control **ptr, *rstc;
+ bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED;
- ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr),
+ ptr = devres_alloc(deasserted ? devm_reset_control_release_deasserted :
+ devm_reset_control_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
- rstc = __reset_control_get(dev, id, index, shared, optional, acquired);
+ flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED;
+
+ rstc = __reset_control_get(dev, id, index, flags);
if (IS_ERR_OR_NULL(rstc)) {
devres_free(ptr);
return rstc;
}
+ if (deasserted) {
+ int ret;
+
+ ret = reset_control_deassert(rstc);
+ if (ret) {
+ reset_control_put(rstc);
+ devres_free(ptr);
+ return ERR_PTR(ret);
+ }
+ }
+
*ptr = rstc;
devres_add(dev, ptr);
@@ -1260,24 +1295,45 @@ static void devm_reset_control_bulk_release(struct device *dev, void *res)
reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
}
+static void devm_reset_control_bulk_release_deasserted(struct device *dev, void *res)
+{
+ struct reset_control_bulk_devres *devres = res;
+
+ reset_control_bulk_assert(devres->num_rstcs, devres->rstcs);
+ reset_control_bulk_put(devres->num_rstcs, devres->rstcs);
+}
+
int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
- bool shared, bool optional, bool acquired)
+ enum reset_control_flags flags)
{
struct reset_control_bulk_devres *ptr;
+ bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED;
int ret;
- ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr),
+ ptr = devres_alloc(deasserted ? devm_reset_control_bulk_release_deasserted :
+ devm_reset_control_bulk_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;
- ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired);
+ flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED;
+
+ ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, flags);
if (ret < 0) {
devres_free(ptr);
return ret;
}
+ if (deasserted) {
+ ret = reset_control_bulk_deassert(num_rstcs, rstcs);
+ if (ret) {
+ reset_control_bulk_put(num_rstcs, rstcs);
+ devres_free(ptr);
+ return ret;
+ }
+ }
+
ptr->num_rstcs = num_rstcs;
ptr->rstcs = rstcs;
devres_add(dev, ptr);
@@ -1298,6 +1354,7 @@ EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get);
*/
int __device_reset(struct device *dev, bool optional)
{
+ enum reset_control_flags flags;
struct reset_control *rstc;
int ret;
@@ -1313,7 +1370,8 @@ int __device_reset(struct device *dev, bool optional)
}
#endif
- rstc = __reset_control_get(dev, NULL, 0, 0, optional, true);
+ flags = optional ? RESET_CONTROL_OPTIONAL_EXCLUSIVE : RESET_CONTROL_EXCLUSIVE;
+ rstc = __reset_control_get(dev, NULL, 0, flags);
if (IS_ERR(rstc))
return PTR_ERR(rstc);
@@ -1356,17 +1414,14 @@ static int of_reset_control_get_count(struct device_node *node)
* device node.
*
* @np: device node for the device that requests the reset controls array
- * @shared: whether reset controls are shared or not
- * @optional: whether it is optional to get the reset controls
- * @acquired: only one reset control may be acquired for a given controller
- * and ID
+ * @flags: whether reset controls are shared, optional, acquired
*
* Returns pointer to allocated reset_control on success or error on failure
*/
struct reset_control *
-of_reset_control_array_get(struct device_node *np, bool shared, bool optional,
- bool acquired)
+of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
struct reset_control_array *resets;
struct reset_control *rstc;
int num, i;
@@ -1381,8 +1436,7 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional,
resets->num_rstcs = num;
for (i = 0; i < num; i++) {
- rstc = __of_reset_control_get(np, NULL, i, shared, optional,
- acquired);
+ rstc = __of_reset_control_get(np, NULL, i, flags);
if (IS_ERR(rstc))
goto err_rst;
resets->rstc[i] = rstc;
@@ -1407,8 +1461,7 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get);
* devm_reset_control_array_get - Resource managed reset control array get
*
* @dev: device that requests the list of reset controls
- * @shared: whether reset controls are shared or not
- * @optional: whether it is optional to get the reset controls
+ * @flags: whether reset controls are shared, optional, acquired
*
* The reset control array APIs are intended for a list of resets
* that just have to be asserted or deasserted, without any
@@ -1417,7 +1470,7 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get);
* Returns pointer to allocated reset_control on success or error on failure
*/
struct reset_control *
-devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
+devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags)
{
struct reset_control **ptr, *rstc;
@@ -1426,7 +1479,7 @@ devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
if (!ptr)
return ERR_PTR(-ENOMEM);
- rstc = of_reset_control_array_get(dev->of_node, shared, optional, true);
+ rstc = of_reset_control_array_get(dev->of_node, flags);
if (IS_ERR_OR_NULL(rstc)) {
devres_free(ptr);
return rstc;
diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c
deleted file mode 100644
index 1e9fca3e30e8..000000000000
--- a/drivers/reset/reset-meson.c
+++ /dev/null
@@ -1,159 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
-/*
- * Amlogic Meson Reset Controller driver
- *
- * Copyright (c) 2016 BayLibre, SAS.
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- */
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/reset-controller.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#define BITS_PER_REG 32
-
-struct meson_reset_param {
- int reg_count;
- int level_offset;
-};
-
-struct meson_reset {
- void __iomem *reg_base;
- const struct meson_reset_param *param;
- struct reset_controller_dev rcdev;
- spinlock_t lock;
-};
-
-static int meson_reset_reset(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct meson_reset *data =
- container_of(rcdev, struct meson_reset, rcdev);
- unsigned int bank = id / BITS_PER_REG;
- unsigned int offset = id % BITS_PER_REG;
- void __iomem *reg_addr = data->reg_base + (bank << 2);
-
- writel(BIT(offset), reg_addr);
-
- return 0;
-}
-
-static int meson_reset_level(struct reset_controller_dev *rcdev,
- unsigned long id, bool assert)
-{
- struct meson_reset *data =
- container_of(rcdev, struct meson_reset, rcdev);
- unsigned int bank = id / BITS_PER_REG;
- unsigned int offset = id % BITS_PER_REG;
- void __iomem *reg_addr;
- unsigned long flags;
- u32 reg;
-
- reg_addr = data->reg_base + data->param->level_offset + (bank << 2);
-
- spin_lock_irqsave(&data->lock, flags);
-
- reg = readl(reg_addr);
- if (assert)
- writel(reg & ~BIT(offset), reg_addr);
- else
- writel(reg | BIT(offset), reg_addr);
-
- spin_unlock_irqrestore(&data->lock, flags);
-
- return 0;
-}
-
-static int meson_reset_assert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return meson_reset_level(rcdev, id, true);
-}
-
-static int meson_reset_deassert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return meson_reset_level(rcdev, id, false);
-}
-
-static const struct reset_control_ops meson_reset_ops = {
- .reset = meson_reset_reset,
- .assert = meson_reset_assert,
- .deassert = meson_reset_deassert,
-};
-
-static const struct meson_reset_param meson8b_param = {
- .reg_count = 8,
- .level_offset = 0x7c,
-};
-
-static const struct meson_reset_param meson_a1_param = {
- .reg_count = 3,
- .level_offset = 0x40,
-};
-
-static const struct meson_reset_param meson_s4_param = {
- .reg_count = 6,
- .level_offset = 0x40,
-};
-
-static const struct meson_reset_param t7_param = {
- .reg_count = 7,
- .level_offset = 0x40,
-};
-
-static const struct of_device_id meson_reset_dt_ids[] = {
- { .compatible = "amlogic,meson8b-reset", .data = &meson8b_param},
- { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param},
- { .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param},
- { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param},
- { .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param},
- { .compatible = "amlogic,c3-reset", .data = &meson_s4_param},
- { .compatible = "amlogic,t7-reset", .data = &t7_param},
- { /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
-
-static int meson_reset_probe(struct platform_device *pdev)
-{
- struct meson_reset *data;
-
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(data->reg_base))
- return PTR_ERR(data->reg_base);
-
- data->param = of_device_get_match_data(&pdev->dev);
- if (!data->param)
- return -ENODEV;
-
- spin_lock_init(&data->lock);
-
- data->rcdev.owner = THIS_MODULE;
- data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG;
- data->rcdev.ops = &meson_reset_ops;
- data->rcdev.of_node = pdev->dev.of_node;
-
- return devm_reset_controller_register(&pdev->dev, &data->rcdev);
-}
-
-static struct platform_driver meson_reset_driver = {
- .probe = meson_reset_probe,
- .driver = {
- .name = "meson_reset",
- .of_match_table = meson_reset_dt_ids,
- },
-};
-module_platform_driver(meson_reset_driver);
-
-MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
-MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c
index 636e85c388b0..aa5464be7053 100644
--- a/drivers/reset/reset-microchip-sparx5.c
+++ b/drivers/reset/reset-microchip-sparx5.c
@@ -62,6 +62,28 @@ static const struct reset_control_ops sparx5_reset_ops = {
.reset = sparx5_reset_noop,
};
+static const struct regmap_config mchp_lan966x_syscon_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static struct regmap *mchp_lan966x_syscon_to_regmap(struct device *dev,
+ struct device_node *syscon_np)
+{
+ struct regmap_config regmap_config = mchp_lan966x_syscon_regmap_config;
+ resource_size_t size;
+ void __iomem *base;
+
+ base = devm_of_iomap(dev, syscon_np, 0, &size);
+ if (IS_ERR(base))
+ return ERR_CAST(base);
+
+ regmap_config.max_register = size - 4;
+
+ return devm_regmap_init_mmio(dev, base, &regmap_config);
+}
+
static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name,
struct regmap **target)
{
@@ -72,7 +94,18 @@ static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name,
syscon_np = of_parse_phandle(pdev->dev.of_node, name, 0);
if (!syscon_np)
return -ENODEV;
- regmap = syscon_node_to_regmap(syscon_np);
+
+ /*
+ * The syscon API doesn't support syscon device removal.
+ * When used in LAN966x PCI device, the cpu-syscon device needs to be
+ * removed when the PCI device is removed.
+ * In case of LAN966x, map the syscon device locally to support the
+ * device removal.
+ */
+ if (of_device_is_compatible(pdev->dev.of_node, "microchip,lan966x-switch-reset"))
+ regmap = mchp_lan966x_syscon_to_regmap(&pdev->dev, syscon_np);
+ else
+ regmap = syscon_node_to_regmap(syscon_np);
of_node_put(syscon_np);
if (IS_ERR(regmap)) {
err = PTR_ERR(regmap);
@@ -121,6 +154,7 @@ static int mchp_sparx5_reset_probe(struct platform_device *pdev)
return err;
ctx->rcdev.owner = THIS_MODULE;
+ ctx->rcdev.dev = &pdev->dev;
ctx->rcdev.nr_resets = 1;
ctx->rcdev.ops = &sparx5_reset_ops;
ctx->rcdev.of_node = dn;
@@ -158,6 +192,7 @@ static const struct of_device_id mchp_sparx5_reset_of_match[] = {
},
{ }
};
+MODULE_DEVICE_TABLE(of, mchp_sparx5_reset_of_match);
static struct platform_driver mchp_sparx5_reset_driver = {
.probe = mchp_sparx5_reset_probe,
@@ -180,3 +215,4 @@ postcore_initcall(mchp_sparx5_reset_init);
MODULE_DESCRIPTION("Microchip Sparx5 switch reset driver");
MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c
index 5f9f2f7994c0..a2a262bf6bfc 100644
--- a/drivers/reset/reset-uniphier-glue.c
+++ b/drivers/reset/reset-uniphier-glue.c
@@ -35,13 +35,6 @@ static void uniphier_clk_disable(void *_priv)
clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
}
-static void uniphier_rst_assert(void *_priv)
-{
- struct uniphier_glue_reset_priv *priv = _priv;
-
- reset_control_bulk_assert(priv->data->nrsts, priv->rst);
-}
-
static int uniphier_glue_reset_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -68,13 +61,6 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev)
if (ret)
return ret;
- for (i = 0; i < priv->data->nrsts; i++)
- priv->rst[i].id = priv->data->reset_names[i];
- ret = devm_reset_control_bulk_get_shared(dev, priv->data->nrsts,
- priv->rst);
- if (ret)
- return ret;
-
ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk);
if (ret)
return ret;
@@ -83,11 +69,11 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = reset_control_bulk_deassert(priv->data->nrsts, priv->rst);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, uniphier_rst_assert, priv);
+ for (i = 0; i < priv->data->nrsts; i++)
+ priv->rst[i].id = priv->data->reset_names[i];
+ ret = devm_reset_control_bulk_get_shared_deasserted(dev,
+ priv->data->nrsts,
+ priv->rst);
if (ret)
return ret;
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 514ddf003efc..2986ced69a02 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -25,6 +25,48 @@ struct reset_control_bulk_data {
struct reset_control *rstc;
};
+#define RESET_CONTROL_FLAGS_BIT_SHARED BIT(0) /* not exclusive */
+#define RESET_CONTROL_FLAGS_BIT_OPTIONAL BIT(1)
+#define RESET_CONTROL_FLAGS_BIT_ACQUIRED BIT(2) /* iff exclusive, not released */
+#define RESET_CONTROL_FLAGS_BIT_DEASSERTED BIT(3)
+
+/**
+ * enum reset_control_flags - Flags that can be passed to the reset_control_get functions
+ * to determine the type of reset control.
+ * These values cannot be OR'd.
+ *
+ * @RESET_CONTROL_EXCLUSIVE: exclusive, acquired,
+ * @RESET_CONTROL_EXCLUSIVE_DEASSERTED: exclusive, acquired, deasserted
+ * @RESET_CONTROL_EXCLUSIVE_RELEASED: exclusive, released,
+ * @RESET_CONTROL_SHARED: shared
+ * @RESET_CONTROL_SHARED_DEASSERTED: shared, deasserted
+ * @RESET_CONTROL_OPTIONAL_EXCLUSIVE: optional, exclusive, acquired
+ * @RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED: optional, exclusive, acquired, deasserted
+ * @RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED: optional, exclusive, released
+ * @RESET_CONTROL_OPTIONAL_SHARED: optional, shared
+ * @RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED: optional, shared, deasserted
+ */
+enum reset_control_flags {
+ RESET_CONTROL_EXCLUSIVE = RESET_CONTROL_FLAGS_BIT_ACQUIRED,
+ RESET_CONTROL_EXCLUSIVE_DEASSERTED = RESET_CONTROL_FLAGS_BIT_ACQUIRED |
+ RESET_CONTROL_FLAGS_BIT_DEASSERTED,
+ RESET_CONTROL_EXCLUSIVE_RELEASED = 0,
+ RESET_CONTROL_SHARED = RESET_CONTROL_FLAGS_BIT_SHARED,
+ RESET_CONTROL_SHARED_DEASSERTED = RESET_CONTROL_FLAGS_BIT_SHARED |
+ RESET_CONTROL_FLAGS_BIT_DEASSERTED,
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE = RESET_CONTROL_FLAGS_BIT_OPTIONAL |
+ RESET_CONTROL_FLAGS_BIT_ACQUIRED,
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED = RESET_CONTROL_FLAGS_BIT_OPTIONAL |
+ RESET_CONTROL_FLAGS_BIT_ACQUIRED |
+ RESET_CONTROL_FLAGS_BIT_DEASSERTED,
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED = RESET_CONTROL_FLAGS_BIT_OPTIONAL,
+ RESET_CONTROL_OPTIONAL_SHARED = RESET_CONTROL_FLAGS_BIT_OPTIONAL |
+ RESET_CONTROL_FLAGS_BIT_SHARED,
+ RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED = RESET_CONTROL_FLAGS_BIT_OPTIONAL |
+ RESET_CONTROL_FLAGS_BIT_SHARED |
+ RESET_CONTROL_FLAGS_BIT_DEASSERTED,
+};
+
#ifdef CONFIG_RESET_CONTROLLER
int reset_control_reset(struct reset_control *rstc);
@@ -42,30 +84,25 @@ int reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rs
void reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs);
struct reset_control *__of_reset_control_get(struct device_node *node,
- const char *id, int index, bool shared,
- bool optional, bool acquired);
+ const char *id, int index, enum reset_control_flags flags);
struct reset_control *__reset_control_get(struct device *dev, const char *id,
- int index, bool shared,
- bool optional, bool acquired);
+ int index, enum reset_control_flags flags);
void reset_control_put(struct reset_control *rstc);
int __reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
- bool shared, bool optional, bool acquired);
+ enum reset_control_flags flags);
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs);
int __device_reset(struct device *dev, bool optional);
struct reset_control *__devm_reset_control_get(struct device *dev,
- const char *id, int index, bool shared,
- bool optional, bool acquired);
+ const char *id, int index, enum reset_control_flags flags);
int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
- bool shared, bool optional, bool acquired);
+ enum reset_control_flags flags);
struct reset_control *devm_reset_control_array_get(struct device *dev,
- bool shared, bool optional);
-struct reset_control *of_reset_control_array_get(struct device_node *np,
- bool shared, bool optional,
- bool acquired);
+ enum reset_control_flags flags);
+struct reset_control *of_reset_control_array_get(struct device_node *np, enum reset_control_flags);
int reset_control_get_count(struct device *dev);
@@ -116,17 +153,19 @@ static inline int __device_reset(struct device *dev, bool optional)
static inline struct reset_control *__of_reset_control_get(
struct device_node *node,
- const char *id, int index, bool shared,
- bool optional, bool acquired)
+ const char *id, int index, enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
static inline struct reset_control *__reset_control_get(
struct device *dev, const char *id,
- int index, bool shared, bool optional,
- bool acquired)
+ int index, enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
@@ -162,8 +201,10 @@ reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs)
static inline int
__reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
- bool shared, bool optional, bool acquired)
+ enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
return optional ? 0 : -EOPNOTSUPP;
}
@@ -174,30 +215,36 @@ reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
static inline struct reset_control *__devm_reset_control_get(
struct device *dev, const char *id,
- int index, bool shared, bool optional,
- bool acquired)
+ int index, enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
static inline int
__devm_reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
- bool shared, bool optional, bool acquired)
+ enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
return optional ? 0 : -EOPNOTSUPP;
}
static inline struct reset_control *
-devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
+devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
static inline struct reset_control *
-of_reset_control_array_get(struct device_node *np, bool shared, bool optional,
- bool acquired)
+of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags)
{
+ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
@@ -236,7 +283,7 @@ static inline int device_reset_optional(struct device *dev)
static inline struct reset_control *
__must_check reset_control_get_exclusive(struct device *dev, const char *id)
{
- return __reset_control_get(dev, id, 0, false, false, true);
+ return __reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -253,7 +300,7 @@ static inline int __must_check
reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
+ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -274,7 +321,7 @@ static inline struct reset_control *
__must_check reset_control_get_exclusive_released(struct device *dev,
const char *id)
{
- return __reset_control_get(dev, id, 0, false, false, false);
+ return __reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE_RELEASED);
}
/**
@@ -295,7 +342,7 @@ static inline int __must_check
reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
+ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_EXCLUSIVE_RELEASED);
}
/**
@@ -316,7 +363,8 @@ static inline int __must_check
reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
+ return __reset_control_bulk_get(dev, num_rstcs, rstcs,
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED);
}
/**
@@ -344,7 +392,7 @@ reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_r
static inline struct reset_control *reset_control_get_shared(
struct device *dev, const char *id)
{
- return __reset_control_get(dev, id, 0, true, false, false);
+ return __reset_control_get(dev, id, 0, RESET_CONTROL_SHARED);
}
/**
@@ -361,7 +409,7 @@ static inline int __must_check
reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
+ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_SHARED);
}
/**
@@ -378,7 +426,7 @@ reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
static inline struct reset_control *reset_control_get_optional_exclusive(
struct device *dev, const char *id)
{
- return __reset_control_get(dev, id, 0, false, true, true);
+ return __reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
/**
@@ -398,7 +446,7 @@ static inline int __must_check
reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
+ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
/**
@@ -415,7 +463,7 @@ reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
static inline struct reset_control *reset_control_get_optional_shared(
struct device *dev, const char *id)
{
- return __reset_control_get(dev, id, 0, true, true, false);
+ return __reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED);
}
/**
@@ -435,7 +483,7 @@ static inline int __must_check
reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
+ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_OPTIONAL_SHARED);
}
/**
@@ -451,7 +499,7 @@ reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
static inline struct reset_control *of_reset_control_get_exclusive(
struct device_node *node, const char *id)
{
- return __of_reset_control_get(node, id, 0, false, false, true);
+ return __of_reset_control_get(node, id, 0, RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -471,7 +519,7 @@ static inline struct reset_control *of_reset_control_get_exclusive(
static inline struct reset_control *of_reset_control_get_optional_exclusive(
struct device_node *node, const char *id)
{
- return __of_reset_control_get(node, id, 0, false, true, true);
+ return __of_reset_control_get(node, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
/**
@@ -496,7 +544,7 @@ static inline struct reset_control *of_reset_control_get_optional_exclusive(
static inline struct reset_control *of_reset_control_get_shared(
struct device_node *node, const char *id)
{
- return __of_reset_control_get(node, id, 0, true, false, false);
+ return __of_reset_control_get(node, id, 0, RESET_CONTROL_SHARED);
}
/**
@@ -513,7 +561,7 @@ static inline struct reset_control *of_reset_control_get_shared(
static inline struct reset_control *of_reset_control_get_exclusive_by_index(
struct device_node *node, int index)
{
- return __of_reset_control_get(node, NULL, index, false, false, true);
+ return __of_reset_control_get(node, NULL, index, RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -541,7 +589,7 @@ static inline struct reset_control *of_reset_control_get_exclusive_by_index(
static inline struct reset_control *of_reset_control_get_shared_by_index(
struct device_node *node, int index)
{
- return __of_reset_control_get(node, NULL, index, true, false, false);
+ return __of_reset_control_get(node, NULL, index, RESET_CONTROL_SHARED);
}
/**
@@ -560,7 +608,26 @@ static inline struct reset_control *
__must_check devm_reset_control_get_exclusive(struct device *dev,
const char *id)
{
- return __devm_reset_control_get(dev, id, 0, false, false, true);
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE);
+}
+
+/**
+ * devm_reset_control_get_exclusive_deasserted - resource managed
+ * reset_control_get_exclusive() +
+ * reset_control_deassert()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get_exclusive() + reset_control_deassert(). For reset
+ * controllers returned from this function, reset_control_assert() +
+ * reset_control_put() is called automatically on driver detach.
+ *
+ * See reset_control_get_exclusive() for more information.
+ */
+static inline struct reset_control * __must_check
+devm_reset_control_get_exclusive_deasserted(struct device *dev, const char *id)
+{
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE_DEASSERTED);
}
/**
@@ -580,7 +647,8 @@ static inline int __must_check
devm_reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true);
+ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs,
+ RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -599,7 +667,7 @@ static inline struct reset_control *
__must_check devm_reset_control_get_exclusive_released(struct device *dev,
const char *id)
{
- return __devm_reset_control_get(dev, id, 0, false, false, false);
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE_RELEASED);
}
/**
@@ -619,7 +687,8 @@ static inline int __must_check
devm_reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false);
+ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs,
+ RESET_CONTROL_EXCLUSIVE_RELEASED);
}
/**
@@ -638,7 +707,7 @@ static inline struct reset_control *
__must_check devm_reset_control_get_optional_exclusive_released(struct device *dev,
const char *id)
{
- return __devm_reset_control_get(dev, id, 0, false, true, false);
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED);
}
/**
@@ -658,7 +727,8 @@ static inline int __must_check
devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false);
+ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs,
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED);
}
/**
@@ -673,7 +743,26 @@ devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int
static inline struct reset_control *devm_reset_control_get_shared(
struct device *dev, const char *id)
{
- return __devm_reset_control_get(dev, id, 0, true, false, false);
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_SHARED);
+}
+
+/**
+ * devm_reset_control_get_shared_deasserted - resource managed
+ * reset_control_get_shared() +
+ * reset_control_deassert()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get_shared() + reset_control_deassert(). For reset
+ * controllers returned from this function, reset_control_assert() +
+ * reset_control_put() is called automatically on driver detach.
+ *
+ * See devm_reset_control_get_shared() for more information.
+ */
+static inline struct reset_control * __must_check
+devm_reset_control_get_shared_deasserted(struct device *dev, const char *id)
+{
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_SHARED_DEASSERTED);
}
/**
@@ -693,7 +782,29 @@ static inline int __must_check
devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false);
+ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_SHARED);
+}
+
+/**
+ * devm_reset_control_bulk_get_shared_deasserted - resource managed
+ * reset_control_bulk_get_shared() +
+ * reset_control_bulk_deassert()
+ * @dev: device to be reset by the controller
+ * @num_rstcs: number of entries in rstcs array
+ * @rstcs: array of struct reset_control_bulk_data with reset line names set
+ *
+ * Managed reset_control_bulk_get_shared() + reset_control_bulk_deassert(). For
+ * reset controllers returned from this function, reset_control_bulk_assert() +
+ * reset_control_bulk_put() are called automatically on driver detach.
+ *
+ * See devm_reset_control_bulk_get_shared() for more information.
+ */
+static inline int __must_check
+devm_reset_control_bulk_get_shared_deasserted(struct device *dev, int num_rstcs,
+ struct reset_control_bulk_data *rstcs)
+{
+ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs,
+ RESET_CONTROL_SHARED_DEASSERTED);
}
/**
@@ -711,7 +822,26 @@ devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs,
static inline struct reset_control *devm_reset_control_get_optional_exclusive(
struct device *dev, const char *id)
{
- return __devm_reset_control_get(dev, id, 0, false, true, true);
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
+}
+
+/**
+ * devm_reset_control_get_optional_exclusive_deasserted - resource managed
+ * reset_control_get_optional_exclusive() +
+ * reset_control_deassert()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get_optional_exclusive() + reset_control_deassert().
+ * For reset controllers returned from this function, reset_control_assert() +
+ * reset_control_put() is called automatically on driver detach.
+ *
+ * See devm_reset_control_get_optional_exclusive() for more information.
+ */
+static inline struct reset_control *
+devm_reset_control_get_optional_exclusive_deasserted(struct device *dev, const char *id)
+{
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED);
}
/**
@@ -731,7 +861,8 @@ static inline int __must_check
devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
+ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs,
+ RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
/**
@@ -749,7 +880,26 @@ devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs
static inline struct reset_control *devm_reset_control_get_optional_shared(
struct device *dev, const char *id)
{
- return __devm_reset_control_get(dev, id, 0, true, true, false);
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED);
+}
+
+/**
+ * devm_reset_control_get_optional_shared_deasserted - resource managed
+ * reset_control_get_optional_shared() +
+ * reset_control_deassert()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get_optional_shared() + reset_control_deassert(). For
+ * reset controllers returned from this function, reset_control_assert() +
+ * reset_control_put() is called automatically on driver detach.
+ *
+ * See devm_reset_control_get_optional_shared() for more information.
+ */
+static inline struct reset_control *
+devm_reset_control_get_optional_shared_deasserted(struct device *dev, const char *id)
+{
+ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED);
}
/**
@@ -769,7 +919,7 @@ static inline int __must_check
devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs)
{
- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false);
+ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_OPTIONAL_SHARED);
}
/**
@@ -787,7 +937,7 @@ devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs,
static inline struct reset_control *
devm_reset_control_get_exclusive_by_index(struct device *dev, int index)
{
- return __devm_reset_control_get(dev, NULL, index, false, false, true);
+ return __devm_reset_control_get(dev, NULL, index, RESET_CONTROL_EXCLUSIVE);
}
/**
@@ -803,7 +953,7 @@ devm_reset_control_get_exclusive_by_index(struct device *dev, int index)
static inline struct reset_control *
devm_reset_control_get_shared_by_index(struct device *dev, int index)
{
- return __devm_reset_control_get(dev, NULL, index, true, false, false);
+ return __devm_reset_control_get(dev, NULL, index, RESET_CONTROL_SHARED);
}
/*
@@ -851,54 +1001,54 @@ static inline struct reset_control *devm_reset_control_get_by_index(
static inline struct reset_control *
devm_reset_control_array_get_exclusive(struct device *dev)
{
- return devm_reset_control_array_get(dev, false, false);
+ return devm_reset_control_array_get(dev, RESET_CONTROL_EXCLUSIVE);
}
static inline struct reset_control *
devm_reset_control_array_get_shared(struct device *dev)
{
- return devm_reset_control_array_get(dev, true, false);
+ return devm_reset_control_array_get(dev, RESET_CONTROL_SHARED);
}
static inline struct reset_control *
devm_reset_control_array_get_optional_exclusive(struct device *dev)
{
- return devm_reset_control_array_get(dev, false, true);
+ return devm_reset_control_array_get(dev, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
static inline struct reset_control *
devm_reset_control_array_get_optional_shared(struct device *dev)
{
- return devm_reset_control_array_get(dev, true, true);
+ return devm_reset_control_array_get(dev, RESET_CONTROL_OPTIONAL_SHARED);
}
static inline struct reset_control *
of_reset_control_array_get_exclusive(struct device_node *node)
{
- return of_reset_control_array_get(node, false, false, true);
+ return of_reset_control_array_get(node, RESET_CONTROL_EXCLUSIVE);
}
static inline struct reset_control *
of_reset_control_array_get_exclusive_released(struct device_node *node)
{
- return of_reset_control_array_get(node, false, false, false);
+ return of_reset_control_array_get(node, RESET_CONTROL_EXCLUSIVE_RELEASED);
}
static inline struct reset_control *
of_reset_control_array_get_shared(struct device_node *node)
{
- return of_reset_control_array_get(node, true, false, true);
+ return of_reset_control_array_get(node, RESET_CONTROL_SHARED);
}
static inline struct reset_control *
of_reset_control_array_get_optional_exclusive(struct device_node *node)
{
- return of_reset_control_array_get(node, false, true, true);
+ return of_reset_control_array_get(node, RESET_CONTROL_OPTIONAL_EXCLUSIVE);
}
static inline struct reset_control *
of_reset_control_array_get_optional_shared(struct device_node *node)
{
- return of_reset_control_array_get(node, true, true, true);
+ return of_reset_control_array_get(node, RESET_CONTROL_OPTIONAL_SHARED);
}
#endif
diff --git a/include/soc/amlogic/reset-meson-aux.h b/include/soc/amlogic/reset-meson-aux.h
new file mode 100644
index 000000000000..d8a15d48c984
--- /dev/null
+++ b/include/soc/amlogic/reset-meson-aux.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __SOC_RESET_MESON_AUX_H
+#define __SOC_RESET_MESON_AUX_H
+
+#include <linux/err.h>
+
+struct device;
+struct regmap;
+
+#if IS_ENABLED(CONFIG_RESET_MESON_AUX)
+int devm_meson_rst_aux_register(struct device *dev,
+ struct regmap *map,
+ const char *adev_name);
+#else
+static inline int devm_meson_rst_aux_register(struct device *dev,
+ struct regmap *map,
+ const char *adev_name)
+{
+ return 0;
+}
+#endif
+
+#endif /* __SOC_RESET_MESON_AUX_H */