diff options
Diffstat (limited to 'drivers/power/reset')
-rw-r--r-- | drivers/power/reset/Kconfig | 17 | ||||
-rw-r--r-- | drivers/power/reset/Makefile | 2 | ||||
-rw-r--r-- | drivers/power/reset/brcmstb-reboot.c | 120 | ||||
-rw-r--r-- | drivers/power/reset/gpio-poweroff.c | 52 | ||||
-rw-r--r-- | drivers/power/reset/hisi-reboot.c | 67 | ||||
-rw-r--r-- | drivers/power/reset/restart-poweroff.c | 2 |
6 files changed, 226 insertions, 34 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index bdcf5173e377..ca41523bbebf 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -20,6 +20,17 @@ config POWER_RESET_AXXIA Say Y if you have an Axxia family SoC. +config POWER_RESET_BRCMSTB + bool "Broadcom STB reset driver" if COMPILE_TEST + depends on POWER_RESET && ARM + default ARCH_BRCMSTB + help + This driver provides restart support for ARM-based Broadcom STB + boards. + + Say Y here if you have an ARM-based Broadcom STB board and you wish + to have restart support. + config POWER_RESET_GPIO bool "GPIO power-off driver" depends on OF_GPIO && POWER_RESET @@ -28,6 +39,12 @@ config POWER_RESET_GPIO If your board needs a GPIO high/low to power down, say Y and create a binding in your devicetree. +config POWER_RESET_HISI + bool "Hisilicon power-off driver" + depends on POWER_RESET && ARCH_HISI + help + Reboot support for Hisilicon boards. + config POWER_RESET_MSM bool "Qualcomm MSM power-off driver" depends on POWER_RESET && ARCH_QCOM diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index dde2e8bbac53..a42e70edd037 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -1,6 +1,8 @@ obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o +obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o +obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c new file mode 100644 index 000000000000..3f236924742a --- /dev/null +++ b/drivers/power/reset/brcmstb-reboot.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/printk.h> +#include <linux/reboot.h> +#include <linux/regmap.h> +#include <linux/smp.h> +#include <linux/mfd/syscon.h> + +#include <asm/system_misc.h> + +#define RESET_SOURCE_ENABLE_REG 1 +#define SW_MASTER_RESET_REG 2 + +static struct regmap *regmap; +static u32 rst_src_en; +static u32 sw_mstr_rst; + +static void brcmstb_reboot(enum reboot_mode mode, const char *cmd) +{ + int rc; + u32 tmp; + + rc = regmap_write(regmap, rst_src_en, 1); + if (rc) { + pr_err("failed to write rst_src_en (%d)\n", rc); + return; + } + + rc = regmap_read(regmap, rst_src_en, &tmp); + if (rc) { + pr_err("failed to read rst_src_en (%d)\n", rc); + return; + } + + rc = regmap_write(regmap, sw_mstr_rst, 1); + if (rc) { + pr_err("failed to write sw_mstr_rst (%d)\n", rc); + return; + } + + rc = regmap_read(regmap, sw_mstr_rst, &tmp); + if (rc) { + pr_err("failed to read sw_mstr_rst (%d)\n", rc); + return; + } + + while (1) + ; +} + +static int brcmstb_reboot_probe(struct platform_device *pdev) +{ + int rc; + struct device_node *np = pdev->dev.of_node; + + regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(regmap)) { + pr_err("failed to get syscon phandle\n"); + return -EINVAL; + } + + rc = of_property_read_u32_index(np, "syscon", RESET_SOURCE_ENABLE_REG, + &rst_src_en); + if (rc) { + pr_err("can't get rst_src_en offset (%d)\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32_index(np, "syscon", SW_MASTER_RESET_REG, + &sw_mstr_rst); + if (rc) { + pr_err("can't get sw_mstr_rst offset (%d)\n", rc); + return -EINVAL; + } + + arm_pm_restart = brcmstb_reboot; + + return 0; +} + +static const struct of_device_id of_match[] = { + { .compatible = "brcm,brcmstb-reboot", }, + {}, +}; + +static struct platform_driver brcmstb_reboot_driver = { + .probe = brcmstb_reboot_probe, + .driver = { + .name = "brcmstb-reboot", + .owner = THIS_MODULE, + .of_match_table = of_match, + }, +}; + +static int __init brcmstb_reboot_init(void) +{ + return platform_driver_probe(&brcmstb_reboot_driver, + brcmstb_reboot_probe); +} +subsys_initcall(brcmstb_reboot_init); diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index e290d48ddd99..ce849bc9b269 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -15,31 +15,29 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/module.h> /* * Hold configuration here, cannot be more than one instance of the driver * since pm_power_off itself is global. */ -static int gpio_num = -1; -static int gpio_active_low; +static struct gpio_desc *reset_gpio; static void gpio_poweroff_do_poweroff(void) { - BUG_ON(!gpio_is_valid(gpio_num)); + BUG_ON(!reset_gpio); /* drive it active, also inactive->active edge */ - gpio_direction_output(gpio_num, !gpio_active_low); + gpiod_direction_output(reset_gpio, 1); mdelay(100); /* drive inactive, also active->inactive edge */ - gpio_set_value(gpio_num, gpio_active_low); + gpiod_set_value(reset_gpio, 0); mdelay(100); /* drive it active, also inactive->active edge */ - gpio_set_value(gpio_num, !gpio_active_low); + gpiod_set_value(reset_gpio, 1); /* give it some time */ mdelay(3000); @@ -49,54 +47,42 @@ static void gpio_poweroff_do_poweroff(void) static int gpio_poweroff_probe(struct platform_device *pdev) { - enum of_gpio_flags flags; bool input = false; - int ret; /* If a pm_power_off function has already been added, leave it alone */ if (pm_power_off != NULL) { - pr_err("%s: pm_power_off function already registered", + dev_err(&pdev->dev, + "%s: pm_power_off function already registered", __func__); return -EBUSY; } - gpio_num = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); - if (!gpio_is_valid(gpio_num)) - return gpio_num; - - gpio_active_low = flags & OF_GPIO_ACTIVE_LOW; + reset_gpio = devm_gpiod_get(&pdev->dev, NULL); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); input = of_property_read_bool(pdev->dev.of_node, "input"); - ret = gpio_request(gpio_num, "poweroff-gpio"); - if (ret) { - pr_err("%s: Could not get GPIO %d", __func__, gpio_num); - return ret; - } if (input) { - if (gpio_direction_input(gpio_num)) { - pr_err("Could not set direction of GPIO %d to input", - gpio_num); - goto err; + if (gpiod_direction_input(reset_gpio)) { + dev_err(&pdev->dev, + "Could not set direction of reset GPIO to input\n"); + return -ENODEV; } } else { - if (gpio_direction_output(gpio_num, gpio_active_low)) { - pr_err("Could not set direction of GPIO %d", gpio_num); - goto err; + if (gpiod_direction_output(reset_gpio, 0)) { + dev_err(&pdev->dev, + "Could not set direction of reset GPIO\n"); + return -ENODEV; } } pm_power_off = &gpio_poweroff_do_poweroff; return 0; - -err: - gpio_free(gpio_num); - return -ENODEV; } static int gpio_poweroff_remove(struct platform_device *pdev) { - gpio_free(gpio_num); if (pm_power_off == &gpio_poweroff_do_poweroff) pm_power_off = NULL; diff --git a/drivers/power/reset/hisi-reboot.c b/drivers/power/reset/hisi-reboot.c new file mode 100644 index 000000000000..0c91d0231d36 --- /dev/null +++ b/drivers/power/reset/hisi-reboot.c @@ -0,0 +1,67 @@ +/* + * Hisilicon SoC reset code + * + * Copyright (c) 2014 Hisilicon Ltd. + * Copyright (c) 2014 Linaro Ltd. + * + * Author: Haojian Zhuang <haojian.zhuang@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> + +#include <asm/proc-fns.h> +#include <asm/system_misc.h> + +static void __iomem *base; +static u32 reboot_offset; + +static void hisi_restart(enum reboot_mode mode, const char *cmd) +{ + writel_relaxed(0xdeadbeef, base + reboot_offset); + + while (1) + cpu_do_idle(); +} + +static int hisi_reboot_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + base = of_iomap(np, 0); + if (!base) { + WARN(1, "failed to map base address"); + return -ENODEV; + } + + if (of_property_read_u32(np, "reboot-offset", &reboot_offset) < 0) { + pr_err("failed to find reboot-offset property\n"); + return -EINVAL; + } + + arm_pm_restart = hisi_restart; + + return 0; +} + +static struct of_device_id hisi_reboot_of_match[] = { + { .compatible = "hisilicon,sysctrl" }, + {} +}; + +static struct platform_driver hisi_reboot_driver = { + .probe = hisi_reboot_probe, + .driver = { + .name = "hisi-reboot", + .of_match_table = hisi_reboot_of_match, + }, +}; +module_platform_driver(hisi_reboot_driver); diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c index 5758033e0c16..3e51f8d29bfe 100644 --- a/drivers/power/reset/restart-poweroff.c +++ b/drivers/power/reset/restart-poweroff.c @@ -62,5 +62,5 @@ module_platform_driver(restart_poweroff_driver); MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch"); MODULE_DESCRIPTION("restart poweroff driver"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:poweroff-restart"); |