diff options
23 files changed, 181 insertions, 67 deletions
diff --git a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt index b74e4d4785ab..0725fb37a973 100644 --- a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt +++ b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt @@ -14,6 +14,7 @@ Required properties: - "renesas,r8a7793-sysc" (R-Car M2-N) - "renesas,r8a7794-sysc" (R-Car E2) - "renesas,r8a7795-sysc" (R-Car H3) + - "renesas,r8a7796-sysc" (R-Car M3-W) - reg: Address start and address range for the device. - #power-domain-cells: Must be 1. diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index c63eea0c1c8c..f5e522342ee5 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -352,6 +352,10 @@ REGULATOR devm_regulator_put() devm_regulator_register() +RESET + devm_reset_control_get() + devm_reset_controller_register() + SLAVE DMA ENGINE devm_acpi_dma_controller_register() diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index e65aa7d11b20..58b334f5f1d6 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -19,6 +19,7 @@ menuconfig ARCH_EXYNOS select EXYNOS_THERMAL select EXYNOS_PMU select EXYNOS_SROM + select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS select HAVE_ARM_SCU if SMP select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 34d29df3e006..838249d4ff5c 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.o exynos-smc.o firmware.o obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o obj-$(CONFIG_PM_SLEEP) += suspend.o -obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 0b2733db0e9e..ab37f4db9642 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -12,8 +12,12 @@ menuconfig RESET_CONTROLLER If unsure, say no. +if RESET_CONTROLLER + config RESET_OXNAS bool source "drivers/reset/sti/Kconfig" source "drivers/reset/hisilicon/Kconfig" + +endif diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 72b32bd15549..395dc9ce492e 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -93,6 +93,43 @@ void reset_controller_unregister(struct reset_controller_dev *rcdev) } EXPORT_SYMBOL_GPL(reset_controller_unregister); +static void devm_reset_controller_release(struct device *dev, void *res) +{ + reset_controller_unregister(*(struct reset_controller_dev **)res); +} + +/** + * devm_reset_controller_register - resource managed reset_controller_register() + * @dev: device that is registering this reset controller + * @rcdev: a pointer to the initialized reset controller device + * + * Managed reset_controller_register(). For reset controllers registered by + * this function, reset_controller_unregister() is automatically called on + * driver detach. See reset_controller_register() for more information. + */ +int devm_reset_controller_register(struct device *dev, + struct reset_controller_dev *rcdev) +{ + struct reset_controller_dev **rcdevp; + int ret; + + rcdevp = devres_alloc(devm_reset_controller_release, sizeof(*rcdevp), + GFP_KERNEL); + if (!rcdevp) + return -ENOMEM; + + ret = reset_controller_register(rcdev); + if (!ret) { + *rcdevp = rcdev; + devres_add(dev, rcdevp); + } else { + devres_free(rcdevp); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_reset_controller_register); + /** * reset_control_reset - reset the controlled device * @rstc: reset controller diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c index ccb940a8d9fb..16d410cd6146 100644 --- a/drivers/reset/reset-ath79.c +++ b/drivers/reset/reset-ath79.c @@ -112,7 +112,7 @@ static int ath79_reset_probe(struct platform_device *pdev) ath79_reset->rcdev.of_reset_n_cells = 1; ath79_reset->rcdev.nr_resets = 32; - err = reset_controller_register(&ath79_reset->rcdev); + err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev); if (err) return err; @@ -131,7 +131,6 @@ static int ath79_reset_remove(struct platform_device *pdev) struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); unregister_restart_handler(&ath79_reset->restart_nb); - reset_controller_unregister(&ath79_reset->rcdev); return 0; } diff --git a/drivers/reset/reset-oxnas.c b/drivers/reset/reset-oxnas.c index c60fb2dace3e..944980572f79 100644 --- a/drivers/reset/reset-oxnas.c +++ b/drivers/reset/reset-oxnas.c @@ -112,21 +112,11 @@ static int oxnas_reset_probe(struct platform_device *pdev) data->rcdev.ops = &oxnas_reset_ops; data->rcdev.of_node = pdev->dev.of_node; - return reset_controller_register(&data->rcdev); -} - -static int oxnas_reset_remove(struct platform_device *pdev) -{ - struct oxnas_reset *data = platform_get_drvdata(pdev); - - reset_controller_unregister(&data->rcdev); - - return 0; + return devm_reset_controller_register(&pdev->dev, &data->rcdev); } static struct platform_driver oxnas_reset_driver = { .probe = oxnas_reset_probe, - .remove = oxnas_reset_remove, .driver = { .name = "oxnas-reset", .of_match_table = oxnas_reset_dt_ids, diff --git a/drivers/reset/reset-pistachio.c b/drivers/reset/reset-pistachio.c index 72a97a15a4c8..bbc4c06dd33b 100644 --- a/drivers/reset/reset-pistachio.c +++ b/drivers/reset/reset-pistachio.c @@ -121,16 +121,7 @@ static int pistachio_reset_probe(struct platform_device *pdev) rd->rcdev.ops = &pistachio_reset_ops; rd->rcdev.of_node = np; - return reset_controller_register(&rd->rcdev); -} - -static int pistachio_reset_remove(struct platform_device *pdev) -{ - struct pistachio_reset_data *data = platform_get_drvdata(pdev); - - reset_controller_unregister(&data->rcdev); - - return 0; + return devm_reset_controller_register(dev, &rd->rcdev); } static const struct of_device_id pistachio_reset_dt_ids[] = { @@ -141,7 +132,6 @@ MODULE_DEVICE_TABLE(of, pistachio_reset_dt_ids); static struct platform_driver pistachio_reset_driver = { .probe = pistachio_reset_probe, - .remove = pistachio_reset_remove, .driver = { .name = "pistachio-reset", .of_match_table = pistachio_reset_dt_ids, diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index cd05a7032b17..12add9b0fa49 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -134,16 +134,7 @@ static int socfpga_reset_probe(struct platform_device *pdev) data->rcdev.ops = &socfpga_reset_ops; data->rcdev.of_node = pdev->dev.of_node; - return reset_controller_register(&data->rcdev); -} - -static int socfpga_reset_remove(struct platform_device *pdev) -{ - struct socfpga_reset_data *data = platform_get_drvdata(pdev); - - reset_controller_unregister(&data->rcdev); - - return 0; + return devm_reset_controller_register(dev, &data->rcdev); } static const struct of_device_id socfpga_reset_dt_ids[] = { @@ -153,7 +144,6 @@ static const struct of_device_id socfpga_reset_dt_ids[] = { static struct platform_driver socfpga_reset_driver = { .probe = socfpga_reset_probe, - .remove = socfpga_reset_remove, .driver = { .name = "socfpga-reset", .of_match_table = socfpga_reset_dt_ids, diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c index 677f86555212..3080190b3f90 100644 --- a/drivers/reset/reset-sunxi.c +++ b/drivers/reset/reset-sunxi.c @@ -165,21 +165,11 @@ static int sunxi_reset_probe(struct platform_device *pdev) data->rcdev.ops = &sunxi_reset_ops; data->rcdev.of_node = pdev->dev.of_node; - return reset_controller_register(&data->rcdev); -} - -static int sunxi_reset_remove(struct platform_device *pdev) -{ - struct sunxi_reset_data *data = platform_get_drvdata(pdev); - - reset_controller_unregister(&data->rcdev); - - return 0; + return devm_reset_controller_register(&pdev->dev, &data->rcdev); } static struct platform_driver sunxi_reset_driver = { .probe = sunxi_reset_probe, - .remove = sunxi_reset_remove, .driver = { .name = "sunxi-reset", .of_match_table = sunxi_reset_dt_ids, diff --git a/drivers/reset/reset-zynq.c b/drivers/reset/reset-zynq.c index a7e87bc45885..138f2f205662 100644 --- a/drivers/reset/reset-zynq.c +++ b/drivers/reset/reset-zynq.c @@ -122,16 +122,7 @@ static int zynq_reset_probe(struct platform_device *pdev) priv->rcdev.ops = &zynq_reset_ops; priv->rcdev.of_node = pdev->dev.of_node; - return reset_controller_register(&priv->rcdev); -} - -static int zynq_reset_remove(struct platform_device *pdev) -{ - struct zynq_reset_data *priv = platform_get_drvdata(pdev); - - reset_controller_unregister(&priv->rcdev); - - return 0; + return devm_reset_controller_register(&pdev->dev, &priv->rcdev); } static const struct of_device_id zynq_reset_dt_ids[] = { @@ -141,7 +132,6 @@ static const struct of_device_id zynq_reset_dt_ids[] = { static struct platform_driver zynq_reset_driver = { .probe = zynq_reset_probe, - .remove = zynq_reset_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = zynq_reset_dt_ids, diff --git a/drivers/reset/sti/Kconfig b/drivers/reset/sti/Kconfig index f8c15a37fb35..613178553612 100644 --- a/drivers/reset/sti/Kconfig +++ b/drivers/reset/sti/Kconfig @@ -2,7 +2,6 @@ if ARCH_STI config STI_RESET_SYSCFG bool - select RESET_CONTROLLER config STIH415_RESET bool diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 151fcd3f025b..cd85cd5e6a01 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o obj-$(CONFIG_ARCH_R8A7793) += rcar-sysc.o r8a7791-sysc.o obj-$(CONFIG_ARCH_R8A7794) += rcar-sysc.o r8a7794-sysc.o obj-$(CONFIG_ARCH_R8A7795) += rcar-sysc.o r8a7795-sysc.o +obj-$(CONFIG_ARCH_R8A7796) += rcar-sysc.o r8a7796-sysc.o diff --git a/drivers/soc/renesas/r8a7796-sysc.c b/drivers/soc/renesas/r8a7796-sysc.c new file mode 100644 index 000000000000..f700c842b9e1 --- /dev/null +++ b/drivers/soc/renesas/r8a7796-sysc.c @@ -0,0 +1,48 @@ +/* + * Renesas R-Car M3-W System Controller + * + * Copyright (C) 2016 Glider bvba + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include <linux/bug.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7796-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7796_areas[] __initconst = { + { "always-on", 0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A7796_PD_CA57_SCU, R8A7796_PD_ALWAYS_ON, + PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A7796_PD_CA57_CPU0, R8A7796_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A7796_PD_CA57_CPU1, R8A7796_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca53-scu", 0x140, 0, R8A7796_PD_CA53_SCU, R8A7796_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A7796_PD_CA53_CPU0, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A7796_PD_CA53_CPU1, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu2", 0x200, 2, R8A7796_PD_CA53_CPU2, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A7796_PD_CA53_CPU3, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A7796_PD_CR7, R8A7796_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A7796_PD_A3VC, R8A7796_PD_ALWAYS_ON }, + { "a2vc0", 0x3c0, 0, R8A7796_PD_A2VC0, R8A7796_PD_A3VC }, + { "a2vc1", 0x3c0, 1, R8A7796_PD_A2VC1, R8A7796_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A7796_PD_3DG_A, R8A7796_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A7796_PD_3DG_B, R8A7796_PD_3DG_A }, + { "a3ir", 0x180, 0, R8A7796_PD_A3IR, R8A7796_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7796_sysc_info __initconst = { + .areas = r8a7796_areas, + .num_areas = ARRAY_SIZE(r8a7796_areas), +}; diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 79dbc770895f..fc997d4d2a4a 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -303,6 +303,9 @@ static const struct of_device_id rcar_sysc_matches[] = { #ifdef CONFIG_ARCH_R8A7795 { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info }, #endif +#ifdef CONFIG_ARCH_R8A7796 + { .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info }, +#endif { /* sentinel */ } }; diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h index 5e766174c2f4..4ac3d7bf7f38 100644 --- a/drivers/soc/renesas/rcar-sysc.h +++ b/drivers/soc/renesas/rcar-sysc.h @@ -55,4 +55,5 @@ extern const struct rcar_sysc_info r8a7790_sysc_info; extern const struct rcar_sysc_info r8a7791_sysc_info; extern const struct rcar_sysc_info r8a7794_sysc_info; extern const struct rcar_sysc_info r8a7795_sysc_info; +extern const struct rcar_sysc_info r8a7796_sysc_info; #endif /* __SOC_RENESAS_RCAR_SYSC_H__ */ diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index d7fc123006a3..245533907d1b 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -10,4 +10,8 @@ config EXYNOS_PMU bool "Exynos PMU controller driver" if COMPILE_TEST depends on (ARM && ARCH_EXYNOS) || ((ARM || ARM64) && COMPILE_TEST) +config EXYNOS_PM_DOMAINS + bool "Exynos PM domains" if COMPILE_TEST + depends on PM_GENERIC_DOMAINS || COMPILE_TEST + endif diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index f64ac4d80564..3619f2ecddaa 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o exynos3250-pmu.o exynos4-pmu.o \ exynos5250-pmu.o exynos5420-pmu.o +obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o diff --git a/arch/arm/mach-exynos/pm_domains.c b/drivers/soc/samsung/pm_domains.c index 875a2bab64f6..f60515eefb66 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -23,9 +23,13 @@ #include <linux/of_platform.h> #include <linux/sched.h> -#define INT_LOCAL_PWR_EN 0x7 #define MAX_CLK_PER_DOMAIN 4 +struct exynos_pm_domain_config { + /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */ + u32 local_pwr_cfg; +}; + /* * Exynos specific wrapper around the generic power domain */ @@ -38,6 +42,7 @@ struct exynos_pm_domain { struct clk *clk[MAX_CLK_PER_DOMAIN]; struct clk *pclk[MAX_CLK_PER_DOMAIN]; struct clk *asb_clk[MAX_CLK_PER_DOMAIN]; + u32 local_pwr_cfg; }; static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) @@ -69,13 +74,13 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) } } - pwr = power_on ? INT_LOCAL_PWR_EN : 0; + pwr = power_on ? pd->local_pwr_cfg : 0; __raw_writel(pwr, base); /* Wait max 1ms */ timeout = 10; - while ((__raw_readl(base + 0x4) & INT_LOCAL_PWR_EN) != pwr) { + while ((__raw_readl(base + 0x4) & pd->local_pwr_cfg) != pwr) { if (!timeout) { op = (power_on) ? "enable" : "disable"; pr_err("Power domain %s %s failed\n", domain->name, op); @@ -119,14 +124,30 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) return exynos_pd_power(domain, false); } +static const struct exynos_pm_domain_config exynos4210_cfg __initconst = { + .local_pwr_cfg = 0x7, +}; + +static const struct of_device_id exynos_pm_domain_of_match[] __initconst = { + { + .compatible = "samsung,exynos4210-pd", + .data = &exynos4210_cfg, + }, + { }, +}; + static __init int exynos4_pm_init_power_domain(void) { struct device_node *np; + const struct of_device_id *match; - for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) { + const struct exynos_pm_domain_config *pm_domain_cfg; struct exynos_pm_domain *pd; int on, i; + pm_domain_cfg = match->data; + pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { pr_err("%s: failed to allocate memory for domain\n", @@ -153,6 +174,7 @@ static __init int exynos4_pm_init_power_domain(void) pd->pd.power_off = exynos_pd_power_off; pd->pd.power_on = exynos_pd_power_on; + pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { char clk_name[8]; @@ -185,14 +207,14 @@ static __init int exynos4_pm_init_power_domain(void) clk_put(pd->oscclk); no_clk: - on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN; + on = __raw_readl(pd->base + 0x4) & pd->local_pwr_cfg; pm_genpd_init(&pd->pd, NULL, !on); of_genpd_add_provider_simple(np, &pd->pd); } /* Assign the child power domains to their parents */ - for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + for_each_matching_node(np, exynos_pm_domain_of_match) { struct generic_pm_domain *child_domain, *parent_domain; struct of_phandle_args args; diff --git a/include/dt-bindings/power/r8a7796-sysc.h b/include/dt-bindings/power/r8a7796-sysc.h new file mode 100644 index 000000000000..5b4daab44daa --- /dev/null +++ b/include/dt-bindings/power/r8a7796-sysc.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 Glider bvba + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ +#ifndef __DT_BINDINGS_POWER_R8A7796_SYSC_H__ +#define __DT_BINDINGS_POWER_R8A7796_SYSC_H__ + +/* + * These power domain indices match the numbers of the interrupt bits + * representing the power areas in the various Interrupt Registers + * (e.g. SYSCISR, Interrupt Status Register) + */ + +#define R8A7796_PD_CA57_CPU0 0 +#define R8A7796_PD_CA57_CPU1 1 +#define R8A7796_PD_CA53_CPU0 5 +#define R8A7796_PD_CA53_CPU1 6 +#define R8A7796_PD_CA53_CPU2 7 +#define R8A7796_PD_CA53_CPU3 8 +#define R8A7796_PD_CA57_SCU 12 +#define R8A7796_PD_CR7 13 +#define R8A7796_PD_A3VC 14 +#define R8A7796_PD_3DG_A 17 +#define R8A7796_PD_3DG_B 18 +#define R8A7796_PD_CA53_SCU 21 +#define R8A7796_PD_A3IR 24 +#define R8A7796_PD_A2VC0 25 +#define R8A7796_PD_A2VC1 26 + +/* Always-on power area */ +#define R8A7796_PD_ALWAYS_ON 32 + +#endif /* __DT_BINDINGS_POWER_R8A7796_SYSC_H__ */ diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h index b91ba932bbd4..db1fe6772ad5 100644 --- a/include/linux/reset-controller.h +++ b/include/linux/reset-controller.h @@ -53,4 +53,8 @@ struct reset_controller_dev { int reset_controller_register(struct reset_controller_dev *rcdev); void reset_controller_unregister(struct reset_controller_dev *rcdev); +struct device; +int devm_reset_controller_register(struct device *dev, + struct reset_controller_dev *rcdev); + #endif diff --git a/include/linux/reset.h b/include/linux/reset.h index ec0306ce7b92..067db57c81dc 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -71,14 +71,14 @@ static inline struct reset_control *__of_reset_control_get( struct device_node *node, const char *id, int index, int shared) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); } static inline struct reset_control *__devm_reset_control_get( struct device *dev, const char *id, int index, int shared) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); } #endif /* CONFIG_RESET_CONTROLLER */ |