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 86f134941a ("MAINTAINERS: Add the Microchip LAN966x PCI driver
 entry") introduces a trivial merge conflict with commit 7280f01e79
 ("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/
 -----BEGIN PGP SIGNATURE-----
 
 iI0EABYIADUWIQRRO6F6WdpH1R0vGibVhaclGDdiwAUCZyn4gxcccC56YWJlbEBw
 ZW5ndXRyb25peC5kZQAKCRDVhaclGDdiwFJZAP0fjXG07qnGp1Sgai/pmCesg5xJ
 PAEL5/hKaYwQsAQHhwEAwaJg+kVeb74ez3ae4akyvngasJJT9LLDmqWEdxPIcw0=
 =cyUW
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmczbWkACgkQYKtH/8kJ
 UifcZQ/+O0Mek2EdY0VB0nFe3HIzFJU2RAdzAE2ivcwRwzsnpXz21UtYWnDjrIn7
 eTPS6oOTKPbukP/fKwz/u7G7iXdM6VcrVJHfE58z5DqBNGGuou/+sRdTNU01XCrw
 y/TmWwsppGbzpRZ6Wd3aAl6+PldLSNUIKSuDUZ87rpKw8XYzXSvFpd7FhJ8ZQ+sh
 0U8E9o9bj0jwJoCT2azx4peiMnsJbFZON9a5DII/3BCEG/mYc+uO1Q0xJeaalawn
 UCLDEsYi8+zNRYwoH7zBxLSDac2S/3k4KpzFXSWmY4JsCiRRh2x7/HFkt5+Mn27L
 W4grUYsy1c2h3SvZAcs5KKSOZlJT3UtYtKRErVaruHAVkeBw7Cgg4pjm4qjOWdmv
 ke4IOOl6VBgJS55ptFuWJdvCUY62IZfnchjlDcAfMy7BxsB7zxXlP4UaO2DzVLCv
 KokE7dEB30jlwqfOMZQNMqw9OaGYQXv58FN6bXp5Te49oyEWuWoPTaQgQSbcUMf6
 97wyTn8hDF1LwFRnHqued6lfv2BmZoX8ej4BDQ51wKU+ppgFOuFODD367rXJrka2
 73fpbMf5WMHiIH2063d/ShXiwvowggbb7SeAprZFI9ZWCdj6YUSHKYTCDvgRVV9W
 D/HjuoTHf4Y7ueD0oQSsOKycSqkEVjYpsOOD++rRzc7xnUmNBww=
 =rxJh
 -----END PGP SIGNATURE-----

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 86f134941a ("MAINTAINERS: Add the Microchip LAN966x PCI driver
entry") introduces a trivial merge conflict with commit 7280f01e79
("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>
This commit is contained in:
Arnd Bergmann 2024-11-12 15:59:53 +01:00
commit 7d6f7cfc34
21 changed files with 1235 additions and 292 deletions

View File

@ -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

View File

@ -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"

View File

@ -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/

215
drivers/misc/lan966x_pci.c Normal file
View File

@ -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");

View File

@ -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)>;
};
};
};
};
};
};
};

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View File

@ -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");

View File

@ -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");

View File

@ -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;

View File

@ -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

View File

@ -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 */