Skip to content
Snippets Groups Projects
Commit 7de1d5d9 authored by yuri's avatar yuri Committed by Davide Cardillo
Browse files

[IMX6][PWR] add poweroff and reboot system with kill power GPIO

	this feature allow the cpu to turn off the power of the board on poweroff using a GPIO;
	the kill power GPIO have to be specified in the device tree with a power_signal node:

	power_signal: power_signal {
		power-gpio = <&gpio2 4 0>;
	};

	modified:   arch/arm/include/asm/mach/arch.h
	modified:   arch/arm/include/asm/system_misc.h
	modified:   arch/arm/kernel/reboot.c
	modified:   arch/arm/kernel/setup.c
	modified:   arch/arm/mach-imx/mach-imx6q.c
parent 9436e90a
No related branches found
No related tags found
1 merge request!84[IMX6][PWR] add poweroff and reboot system with kill power GPIO
...@@ -60,6 +60,7 @@ struct machine_desc { ...@@ -60,6 +60,7 @@ struct machine_desc {
void (*handle_irq)(struct pt_regs *); void (*handle_irq)(struct pt_regs *);
#endif #endif
void (*restart)(enum reboot_mode, const char *); void (*restart)(enum reboot_mode, const char *);
void (*pwroff)(void);
}; };
/* /*
......
...@@ -15,6 +15,8 @@ extern void cpu_init(void); ...@@ -15,6 +15,8 @@ extern void cpu_init(void);
void soft_restart(unsigned long); void soft_restart(unsigned long);
extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
extern void (*arm_pm_idle)(void); extern void (*arm_pm_idle)(void);
extern void (*arm_pm_poweroff)(void);
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
typedef void (*harden_branch_predictor_fn_t)(void); typedef void (*harden_branch_predictor_fn_t)(void);
......
...@@ -19,6 +19,7 @@ typedef void (*phys_reset_t)(unsigned long, bool); ...@@ -19,6 +19,7 @@ typedef void (*phys_reset_t)(unsigned long, bool);
* Function pointers to optional machine specific functions * Function pointers to optional machine specific functions
*/ */
void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
void (*arm_pm_poweroff)(void);
void (*pm_power_off)(void); void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(pm_power_off);
...@@ -104,6 +105,10 @@ void machine_halt(void) ...@@ -104,6 +105,10 @@ void machine_halt(void)
{ {
local_irq_disable(); local_irq_disable();
smp_send_stop(); smp_send_stop();
if ( arm_pm_poweroff )
arm_pm_poweroff ();
while (1); while (1);
} }
......
...@@ -1152,6 +1152,9 @@ void __init setup_arch(char **cmdline_p) ...@@ -1152,6 +1152,9 @@ void __init setup_arch(char **cmdline_p)
if (mdesc->restart) if (mdesc->restart)
arm_pm_restart = mdesc->restart; arm_pm_restart = mdesc->restart;
if (mdesc->pwroff)
arm_pm_poweroff = mdesc->pwroff;
unflatten_device_tree(); unflatten_device_tree();
arm_dt_init_cpu_maps(); arm_dt_init_cpu_maps();
......
...@@ -7,12 +7,14 @@ ...@@ -7,12 +7,14 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/micrel_phy.h> #include <linux/micrel_phy.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_gpio.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
...@@ -20,6 +22,10 @@ ...@@ -20,6 +22,10 @@
#include "cpuidle.h" #include "cpuidle.h"
#include "hardware.h" #include "hardware.h"
static int power_gpio = -1;
static int power_gpio_pol = 0;
static int only_for_poweroff = 0;
/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
static int ksz9021rn_phy_fixup(struct phy_device *phydev) static int ksz9021rn_phy_fixup(struct phy_device *phydev)
{ {
...@@ -324,8 +330,45 @@ static void __init imx6q_init_machine(void) ...@@ -324,8 +330,45 @@ static void __init imx6q_init_machine(void)
imx6q_axi_init(); imx6q_axi_init();
} }
static void imx6q_poweroff (void) {
int ret;
if ( power_gpio_pol )
ret = gpio_request_one (power_gpio, GPIOF_OUT_INIT_HIGH, "power_gpio");
else
ret = gpio_request_one (power_gpio, GPIOF_OUT_INIT_LOW, "power_gpio");
if ( ret < 0)
printk (KERN_ERR "(%d) Unable to get kill power GPIO (%d)\n", ret, power_gpio);
};
void imx6q_restart (enum reboot_mode reboot_mode, const char *cmd) {
int ret = 0;
int ectrl_signed = 0;
if ( !only_for_poweroff ) {
if ( power_gpio_pol )
ret = gpio_request_one (power_gpio, GPIOF_OUT_INIT_HIGH, "power_gpio");
else
ret = gpio_request_one (power_gpio, GPIOF_OUT_INIT_LOW, "power_gpio");
if ( ret < 0)
printk (KERN_ERR "Unable to get kill power GPIO\n");
else {
ectrl_signed = 1;
}
}
if ( !ectrl_signed )
mxc_restart (reboot_mode, cmd);
}
static void __init imx6q_init_late(void) static void __init imx6q_init_late(void)
{ {
struct device_node *np;
/* /*
* WAIT mode is broken on imx6 Dual/Quad revision 1.0 and 1.1 so * WAIT mode is broken on imx6 Dual/Quad revision 1.0 and 1.1 so
* there is no point to run cpuidle on them. * there is no point to run cpuidle on them.
...@@ -338,6 +381,19 @@ static void __init imx6q_init_late(void) ...@@ -338,6 +381,19 @@ static void __init imx6q_init_late(void)
if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
np = of_find_node_by_path ("/power_signal");
if ( np ) {
power_gpio = of_get_named_gpio (np, "power-gpio", 0);
if ( gpio_is_valid (power_gpio) ) {
pm_power_off = imx6q_poweroff;
printk (KERN_WARNING "kill power GPIO %d ok\n", power_gpio);
}
else
printk (KERN_WARNING "Unable to get kill power GPIO\n");
power_gpio_pol = of_property_read_bool(np, "set_high");
only_for_poweroff = of_property_read_bool(np, "only_for_poweroff");
np = NULL;
}
} }
static void __init imx6q_map_io(void) static void __init imx6q_map_io(void)
...@@ -374,4 +430,6 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)") ...@@ -374,4 +430,6 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")
.init_machine = imx6q_init_machine, .init_machine = imx6q_init_machine,
.init_late = imx6q_init_late, .init_late = imx6q_init_late,
.dt_compat = imx6q_dt_compat, .dt_compat = imx6q_dt_compat,
.restart = imx6q_restart,
.pwroff = imx6q_poweroff,
MACHINE_END MACHINE_END
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment