diff options
author | Joy Cho <joy.cho@hardkernel.com> | 2018-12-04 17:08:44 +0900 |
---|---|---|
committer | Dongjin Kim <tobetter@gmail.com> | 2020-02-13 17:13:40 +0900 |
commit | 17799f47c2542f6baccfd5fd88c4d12afef542be (patch) | |
tree | d5538382216303c4e098076844ed35ed0f9aaec2 | |
parent | c699a267dbc23e6a02459284d633c62d41bface4 (diff) | |
download | u-boot-odroid-c1-17799f47c2542f6baccfd5fd88c4d12afef542be.tar.gz |
ODROID-C4: scp_task: add gpio wake-up function
Change-Id: Idaa9f5738b02d7815762aba6a1513fefcc4deda6
5 files changed, 318 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c new file mode 100644 index 0000000000..833ba5fdc6 --- /dev/null +++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c @@ -0,0 +1,259 @@ +/* + * arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.c + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <gpio.h> +#include <aml_gpio.h> + +#define PK(reg, bit) ((reg << 8) | bit) +#define PK_REG(value) (value >> 8) + +#define EE_OFFSET 12 +#define GPIOAO(x) (x) +#define GPIOEE(x) (EE_OFFSET + x) + +#define KERNEL_GPIO_OFFSET 399 + +static unsigned int g_bankindex; +static unsigned int g_offset; +static unsigned int g_active; + +unsigned int gpio_wakeup_keyno; + +/* + * Support only default pull-up ports + * on this version + */ +static struct gpio_array { + unsigned int pin; + unsigned int function; +} gpio_to_pin[] = { + { + .pin = (GPIOA_14 + EE_OFFSET), + .function = PK(0xe, 14), + }, + { + .pin = (GPIOX_0 + EE_OFFSET), + .function = PK(3, 0), + }, + { + .pin = (GPIOX_1 + EE_OFFSET), + .function = PK(3, 1), + }, + { + .pin = (GPIOX_2 + EE_OFFSET), + .function = PK(3, 2), + }, + { + .pin = (GPIOX_3 + EE_OFFSET), + .function = PK(3, 3), + }, + { + .pin = (GPIOX_4 + EE_OFFSET), + .function = PK(3, 4), + }, + { + .pin = (GPIOX_5 + EE_OFFSET), + .function = PK(3, 5), + }, + { + .pin = (GPIOX_7 + EE_OFFSET), + .function = PK(3, 7), + }, + { + .pin = (GPIOX_8 + EE_OFFSET), + .function = PK(4, 8), + }, + { + .pin = (GPIOX_9 + EE_OFFSET), + .function = PK(4, 9), + }, + { + .pin = (GPIOX_10 + EE_OFFSET), + .function = PK(4, 10), + }, + { + .pin = (GPIOX_11 + EE_OFFSET), + .function = PK(4, 11), + }, + { + .pin = (GPIOX_12 + EE_OFFSET), + .function = PK(4, 12), + }, + { + .pin = (GPIOX_13 + EE_OFFSET), + .function = PK(4, 13), + }, + { + .pin = (GPIOX_14 + EE_OFFSET), + .function = PK(4, 14), + }, + { + .pin = (GPIOX_15 + EE_OFFSET), + .function = PK(4, 15), + }, + { + .pin = (GPIOX_16 + EE_OFFSET), + .function = PK(5, 16), + }, + { + .pin = (GPIOX_18 + EE_OFFSET), + .function = PK(5, 18), + }, +}; + +#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ +{ \ + .name = n, \ + .first = f, \ + .last = l, \ + .regs = { \ + [REG_PULLEN] = { (0xff634520 + (per<<2)), peb }, \ + [REG_PULL] = { (0xff6344e8 + (pr<<2)), pb }, \ + [REG_DIR] = { (0xff634440 + (dr<<2)), db }, \ + [REG_OUT] = { (0xff634440 + (or<<2)), ob }, \ + [REG_IN] = { (0xff634440 + (ir<<2)), ib }, \ + }, \ + } + +static struct meson_bank mesong12b_banks[] = { + /* name first last + * pullen pull dir out in */ + BANK("GPIOA_", GPIOEE(GPIOA_0), GPIOEE(GPIOA_15), + 5, 0, 5, 0, 16, 0, 17, 0, 18, 0), + BANK("GPIOX_", GPIOEE(GPIOX_0), GPIOEE(GPIOX_19), + 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), +}; + +/* GPIOEE pin mux registers */ +static unsigned long domain = 0xff6346c0; + +/* active level - 0 : active low, 1 : active high */ +static unsigned long active_tbl[] = { + [0] = 0x00003FFF, /* GPIOA */ + [1] = 0x000A0040, /* GPIOX */ +}; + +int clear_pinmux(unsigned int pin) +{ + unsigned int i; + unsigned int reg = 0; + unsigned int bit = 0; + + for (i = 0; i < ARRAY_SIZE(gpio_to_pin); i++) { + if (gpio_to_pin[i].pin == pin) { + reg = (PK_REG(gpio_to_pin[i].function) & 0xf); + g_offset = (gpio_to_pin[i].function & 0xff); + bit = ((g_offset % 8) * 4); + aml_update_bits((domain + (reg << 2)), (0xf << bit), 0); + break; + } + } + + if (i >= ARRAY_SIZE(gpio_to_pin)) + return 0; + else + return 1; +} + +int init_gpio_key(void) +{ + unsigned int key_index; + unsigned int reg, bit; + struct meson_bank bank; + + key_index = gpio_wakeup_keyno - KERNEL_GPIO_OFFSET; + if ((key_index >= (GPIOA_0 + EE_OFFSET)) + && (key_index < (GPIOA_15 + EE_OFFSET))) { + g_bankindex = 0; + } else if ((key_index >= GPIOX_0 + EE_OFFSET) + && (key_index < (GPIOX_19 + EE_OFFSET))) { + g_bankindex = 1; + } else { + uart_puts("WAKEUP GPIO FAIL - invalid key \n"); + uart_put_hex(key_index, 32); + uart_puts("\n"); + return 0; + } + + /* clear_pinmux */ + if (!clear_pinmux(key_index)) + return 0; + + /* active level */ + g_active = ((active_tbl[g_bankindex] >> g_offset) & 0x1); + + /* set as input port */ + bank = mesong12b_banks[g_bankindex]; + reg = bank.regs[REG_DIR].reg; + bit = bank.regs[REG_DIR].bit + g_offset; + aml_update_bits(reg, BIT(bit), BIT(bit)); + + return 1; +} + +int key_chattering(void) +{ + unsigned int count = 0; + unsigned int key_pressed = 1; + unsigned int reg, bit; + unsigned int active_value; + struct meson_bank bank = mesong12b_banks[g_bankindex]; + + reg = bank.regs[REG_IN].reg; + bit = bank.regs[REG_IN].bit + g_offset; + + if (g_active) + active_value = (1 << bit); + else + active_value = 0; + + while (key_pressed) { + _udelay(1000); + + if ((readl(reg) & (1 << bit)) == active_value) + count++; + else + key_pressed = 0; + + if (count == 300) + return 1; + } + + return 0; +} + +int gpio_detect_key(void) +{ + unsigned int reg, bit; + unsigned int active_value; + struct meson_bank bank = mesong12b_banks[g_bankindex]; + + reg = bank.regs[REG_IN].reg; + bit = bank.regs[REG_IN].bit + g_offset; + + if (g_active) + active_value = (1 << bit); + else + active_value = 0; + + if ((readl(reg) & (1 << bit)) == active_value) + if (key_chattering()) + return 1; + + return 0; +} diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h new file mode 100644 index 0000000000..8adaae81a6 --- /dev/null +++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h @@ -0,0 +1,29 @@ +/* + * arch/arm/cpu/armv8/g12a/firmware/scp_task/gpio_key.h + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __ARCH_G12B_GPIO_KEY_H__ +#define __ARCH_G12B_GPIO_KEY_H__ + +#ifdef CONFIG_GPIO_WAKEUP +int gpio_detect_key(void); +int init_gpio_key(void); + +unsigned int gpio_wakeup_keyno; +#endif + +#endif /* __ARCH_G12B_GPIO_KEY_H__ */ diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c index 7274ada541..7f89610722 100644 --- a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c +++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.c @@ -29,6 +29,7 @@ unsigned int time; #include <scp_adc.c> #include <pwr_ctrl.c> #include <hdmi_cec_arc.c> +#include <gpio_key.c> static struct pwr_op pwr_op_d; static struct pwr_op *p_pwr_op; @@ -62,6 +63,16 @@ void enter_suspend(unsigned int suspend_from) uart_put_hex(hdmi_cec_func_config, 16); uart_puts("\n"); #endif + + #ifdef CONFIG_GPIO_WAKEUP + gpio_wakeup_keyno = ((readl(P_AO_DEBUG_REG0) & 0xfff0000) >> 16); + wait_uart_empty(); + uart_puts("WAKEUP GPIO cfg:0x"); + uart_put_hex(gpio_wakeup_keyno, 32); + uart_puts("\n"); + wait_uart_empty(); + #endif + if (p_pwr_op->power_off_at_24M) p_pwr_op->power_off_at_24M(suspend_from); diff --git a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h index cc1fc5f8e9..a3c270ad92 100644 --- a/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h +++ b/arch/arm/cpu/armv8/g12a/firmware/scp_task/suspend.h @@ -38,6 +38,7 @@ typedef unsigned int uint32_t; #define ETH_PMT_WAKEUP 10 #define CECB_WAKEUP 11 #define ETH_PHY_GPIO 12 +#define GPIO_WAKEUP 13 /* wake up source*/ #define UDEFINED_WAKEUP_SRC (1<<0) #define CHARGING_WAKEUP_SRC (1<<1) @@ -51,6 +52,7 @@ typedef unsigned int uint32_t; #define ETH_PMT_WAKEUP_SRC (1<<9) #define CECB_WAKEUP_SRC (1<<10) #define ETH_PHY_GPIO_SRC (1<<12) +#define GPIO_WAKEUP_SRC (1<<13) struct pwr_op { void (*power_off_at_24M)(unsigned int); diff --git a/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c b/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c index 8e8c5a37ca..51e784c4f0 100644 --- a/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c +++ b/board/hardkernel/odroidc4/firmware/scp_task/pwr_ctrl.c @@ -23,6 +23,9 @@ #ifdef CONFIG_CEC_WAKEUP #include <cec_tx_reg.h> #endif +#ifdef CONFIG_GPIO_WAKEUP +#include <gpio_key.h> +#endif #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -132,6 +135,10 @@ static unsigned int detect_key(unsigned int suspend_from) unsigned char adc_key_cnt = 0; saradc_enable(); #endif +#ifdef CONFIG_GPIO_WAKEUP + unsigned int is_gpiokey = 0; +#endif + init_remote(); #ifdef CONFIG_CEC_WAKEUP if (hdmi_cec_func_config & 0x1) { @@ -140,6 +147,10 @@ static unsigned int detect_key(unsigned int suspend_from) } #endif +#ifdef CONFIG_GPIO_WAKEUP + is_gpiokey = init_gpio_key(); +#endif + do { #ifdef CONFIG_CEC_WAKEUP if (!cec_msg.log_addr) @@ -187,6 +198,12 @@ static unsigned int detect_key(unsigned int suspend_from) exit_reason = ETH_PHY_GPIO; } +#ifdef CONFIG_GPIO_WAKEUP + if (is_gpiokey) { + if (gpio_detect_key()) + exit_reason = GPIO_WAKEUP; + } +#endif if (exit_reason) break; else |