summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorRuibin Chang <ruibin.chang@ite.com.tw>2020-06-03 14:08:42 +0800
committerCommit Bot <commit-bot@chromium.org>2020-10-14 06:10:48 +0000
commita57076ce03b3aa43d5cf62371649a7e9a28667e2 (patch)
tree3de7bcd25f17068b0b58fa0667f188a5a806542f /chip
parent11053f40043229b98ab7cb6be0325ab483a5d9e5 (diff)
downloadchrome-ec-a57076ce03b3aa43d5cf62371649a7e9a28667e2.tar.gz
it83xx/KB/GPIO: support keyboard GPIO output mode
These pins could be used as GPIO input, and they can be configured as GPIO output as well. So we made this patch to support it. BRANCH=none BUG=b:170699805 TEST=On board it8xxx2_evb 1.GPIO only: set/get level properly at GPIO mode. 2.GPIO and alternate mix: KSI input low and KSO GPIO level not change On board reef_it8320 1.keyboard scan function still work fine. Change-Id: I2098812649f2e3ee9a8718d0d75e541ce3f14338 Signed-off-by: Dino Li <Dino.Li@ite.com.tw> Signed-off-by: Ruibin Chang <ruibin.chang@ite.com.tw> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2182128 Tested-by: Ruibin Chang <Ruibin.Chang@ite.com.tw> Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Ruibin Chang <Ruibin.Chang@ite.com.tw>
Diffstat (limited to 'chip')
-rw-r--r--chip/it83xx/gpio.c81
-rw-r--r--chip/it83xx/keyboard_raw.c32
-rw-r--r--chip/it83xx/registers.h26
3 files changed, 122 insertions, 17 deletions
diff --git a/chip/it83xx/gpio.c b/chip/it83xx/gpio.c
index 90d8b717b7..f15adb431a 100644
--- a/chip/it83xx/gpio.c
+++ b/chip/it83xx/gpio.c
@@ -19,6 +19,23 @@
#include "timer.h"
#include "util.h"
+/* Data structure to define KSI/KSO GPIO mode control registers. */
+struct kbs_gpio_ctrl_t {
+ /* GPIO mode control register. */
+ volatile uint8_t *gpio_mode;
+ /* GPIO output enable register. */
+ volatile uint8_t *gpio_out;
+};
+
+static const struct kbs_gpio_ctrl_t kbs_gpio_ctrl_regs[] = {
+ /* KSI pins 7:0 */
+ {&IT83XX_KBS_KSIGCTRL, &IT83XX_KBS_KSIGOEN},
+ /* KSO pins 15:8 */
+ {&IT83XX_KBS_KSOHGCTRL, &IT83XX_KBS_KSOHGOEN},
+ /* KSO pins 7:0 */
+ {&IT83XX_KBS_KSOLGCTRL, &IT83XX_KBS_KSOLGOEN},
+};
+
/**
* Convert wake-up controller (WUC) group to the corresponding wake-up edge
* sense register (WUESR). Return pointer to the register.
@@ -425,6 +442,25 @@ void gpio_set_alternate_function(uint32_t port, uint32_t mask,
{
uint32_t pin = 0;
+ /* Alternate function configuration for KSI/KSO pins */
+ if (port > GPIO_PORT_COUNT) {
+ port -= GPIO_KSI;
+ /*
+ * If func is non-negative, set for keyboard scan function.
+ * Otherwise, turn the pin into a GPIO input.
+ */
+ if (func >= GPIO_ALT_FUNC_DEFAULT) {
+ /* KBS mode */
+ *kbs_gpio_ctrl_regs[port].gpio_mode &= ~mask;
+ } else {
+ /* input */
+ *kbs_gpio_ctrl_regs[port].gpio_out &= ~mask;
+ /* GPIO mode */
+ *kbs_gpio_ctrl_regs[port].gpio_mode |= mask;
+ }
+ return;
+ }
+
/* For each bit high in the mask, set that pin to use alt. func. */
while (mask > 0) {
if (mask & 1)
@@ -457,12 +493,43 @@ void gpio_set_level(enum gpio_signal signal, int value)
void gpio_kbs_pin_gpio_mode(uint32_t port, uint32_t mask, uint32_t flags)
{
- if (port == GPIO_KSO_H)
- IT83XX_KBS_KSOHGCTRL |= mask;
- else if (port == GPIO_KSO_L)
- IT83XX_KBS_KSOLGCTRL |= mask;
- else if (port == GPIO_KSI)
- IT83XX_KBS_KSIGCTRL |= mask;
+ uint32_t idx = port - GPIO_KSI;
+
+ /* Set GPIO mode */
+ *kbs_gpio_ctrl_regs[idx].gpio_mode |= mask;
+
+ /* Set input or output */
+ if (flags & GPIO_OUTPUT) {
+ /*
+ * Select open drain first, so that we don't glitch the signal
+ * when changing the line to an output.
+ */
+ if (flags & GPIO_OPEN_DRAIN)
+ /*
+ * it83xx: need external pullup for output data high
+ * it8xxx2: this pin is always internal pullup
+ */
+ IT83XX_GPIO_GPOT(port) |= mask;
+ else
+ /*
+ * it8xxx2: this pin is not internal pullup
+ */
+ IT83XX_GPIO_GPOT(port) &= ~mask;
+
+ /* Set level before change to output. */
+ if (flags & GPIO_HIGH)
+ IT83XX_GPIO_DATA(port) |= mask;
+ else if (flags & GPIO_LOW)
+ IT83XX_GPIO_DATA(port) &= ~mask;
+ *kbs_gpio_ctrl_regs[idx].gpio_out |= mask;
+ } else {
+ *kbs_gpio_ctrl_regs[idx].gpio_out &= ~mask;
+ if (flags & GPIO_PULL_UP)
+ IT83XX_GPIO_GPOT(port) |= mask;
+ else
+ /* No internal pullup and pulldown */
+ IT83XX_GPIO_GPOT(port) &= ~mask;
+ }
}
#ifndef IT83XX_GPIO_INT_FLEXIBLE
@@ -495,8 +562,8 @@ void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
uint32_t pin = 0;
uint32_t mask_copy = mask;
+ /* Set GPIO mode for KSI/KSO pins */
if (port > GPIO_PORT_COUNT) {
- /* set up GPIO of KSO/KSI pins (support input only). */
gpio_kbs_pin_gpio_mode(port, mask, flags);
return;
}
diff --git a/chip/it83xx/keyboard_raw.c b/chip/it83xx/keyboard_raw.c
index 5f44670576..25f2b49c00 100644
--- a/chip/it83xx/keyboard_raw.c
+++ b/chip/it83xx/keyboard_raw.c
@@ -10,11 +10,15 @@
#include "task.h"
#include "irq_chip.h"
+#define KSOH_PIN_MASK (((1 << (KEYBOARD_COLS_MAX - 8)) - 1) & 0xff)
+
/*
* Initialize the raw keyboard interface.
*/
void keyboard_raw_init(void)
{
+ uint32_t int_mask;
+
/* Ensure top-level interrupt is disabled */
keyboard_raw_enable_interrupt(0);
@@ -40,8 +44,17 @@ void keyboard_raw_init(void)
IT83XX_KBS_KSOL = 0x00;
#endif
- /* KSO[15:8] pins low. */
- IT83XX_KBS_KSOH1 = 0x00;
+ /* critical section with interrupts off */
+ int_mask = read_clear_int_mask();
+ /*
+ * KSO[COLS_MAX:8] pins low.
+ * NOTE: KSO[15:8] pins can part be enabled for keyboard function and
+ * rest be configured as GPIO output mode. In this case that we
+ * disable the ISR in critical section to avoid race condition.
+ */
+ IT83XX_KBS_KSOH1 &= ~KSOH_PIN_MASK;
+ /* restore interrupts */
+ set_int_mask(int_mask);
/* KSI[0-7] falling-edge triggered is selected */
IT83XX_WUC_WUEMR3 = 0xFF;
@@ -71,6 +84,7 @@ void keyboard_raw_task_start(void)
test_mockable void keyboard_raw_drive_column(int col)
{
int mask;
+ uint32_t int_mask;
/* Tri-state all outputs */
if (col == KEYBOARD_COLUMN_NONE)
@@ -87,7 +101,19 @@ test_mockable void keyboard_raw_drive_column(int col)
mask ^= BIT(2);
#endif
IT83XX_KBS_KSOL = mask & 0xff;
- IT83XX_KBS_KSOH1 = (mask >> 8) & 0xff;
+
+ /* critical section with interrupts off */
+ int_mask = read_clear_int_mask();
+ /*
+ * Because IT83XX_KBS_KSOH1 register is shared by keyboard scan
+ * out and GPIO output mode, so we don't drive all KSOH pins
+ * here (this depends on how many keyboard matrix output pin
+ * we are using).
+ */
+ IT83XX_KBS_KSOH1 = (IT83XX_KBS_KSOH1 & ~KSOH_PIN_MASK) |
+ ((mask >> 8) & KSOH_PIN_MASK);
+ /* restore interrupts */
+ set_int_mask(int_mask);
}
/*
diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h
index f8e73f8887..ea344b35ec 100644
--- a/chip/it83xx/registers.h
+++ b/chip/it83xx/registers.h
@@ -805,7 +805,16 @@ enum {
#endif
GPIO_PORT_COUNT,
- /* NOTE: Support GPIO input only if KSO/KSI pins are used as GPIO. */
+ /*
+ * NOTE: support flags when KSI/KSO are configured as GPIO
+ * 1) it8320bx:
+ * output: GPIO_OUTPUT, GPIO_OPEN_DRAIN, GPIO_HIGH, GPIO_LOW
+ * input: GPIO_INPUT
+ * 2) it8320dx, it8xxx1, and it8xxx2:
+ * output: GPIO_OUTPUT, GPIO_OPEN_DRAIN(always internal pullup),
+ * GPIO_HIGH, GPIO_LOW
+ * input: GPIO_INPUT, GPIO_PULL_UP
+ */
/* KSI[7-0] GPIO data mirror register. */
GPIO_KSI,
/* KSO[15-8] GPIO data mirror register. */
@@ -817,11 +826,11 @@ enum {
};
struct gpio_reg_t {
- /* GPIO port data register (bit mapping to pin) */
+ /* GPIO and KSI/KSO port data register (bit mapping to pin) */
uint32_t reg_gpdr;
- /* GPIO port data mirror register (bit mapping to pin) */
+ /* GPIO and KSI/KSO port data mirror register (bit mapping to pin) */
uint32_t reg_gpdmr;
- /* GPIO port output type register (bit mapping to pin) */
+ /* GPIO and KSI/KSO port output type register (bit mapping to pin) */
uint32_t reg_gpotr;
/* GPIO port control register (byte mapping to pin) */
uint32_t reg_gpcr;
@@ -849,9 +858,9 @@ static const struct gpio_reg_t gpio_group_to_reg[] = {
[GPIO_Q] = { 0x00F03E03, 0x00F03E63, 0x00F03E73, 0x00F03E20 },
[GPIO_R] = { 0x00F03E04, 0x00F03E64, 0x00F03E74, 0x00F03E28 },
#endif
- [GPIO_KSI] = { 0x00F01D09, 0x00F01D09, -1, -1 },
- [GPIO_KSO_H] = { 0x00F01D0C, 0x00F01D0C, -1, -1 },
- [GPIO_KSO_L] = { 0x00F01D0F, 0x00F01D0F, -1, -1 },
+ [GPIO_KSI] = { 0x00F01D08, 0x00F01D09, 0x00F01D26, -1 },
+ [GPIO_KSO_H] = { 0x00F01D01, 0x00F01D0C, 0x00F01D27, -1 },
+ [GPIO_KSO_L] = { 0x00F01D00, 0x00F01D0F, 0x00F01D28, -1 },
};
BUILD_ASSERT(ARRAY_SIZE(gpio_group_to_reg) == (COUNT));
@@ -1248,6 +1257,9 @@ REG8(IT83XX_PMC_BASE + (ch > LPC_PM2 ? 5 : 8) + (ch << 4))
#define IT83XX_KBS_SDC2R REG8(IT83XX_KBS_BASE+0x23)
#define IT83XX_KBS_SDC3R REG8(IT83XX_KBS_BASE+0x24)
#define IT83XX_KBS_SDSR REG8(IT83XX_KBS_BASE+0x25)
+#define IT83XX_KBS_KSIGPODR REG8(IT83XX_KBS_BASE+0x26)
+#define IT83XX_KBS_KSOHGPODR REG8(IT83XX_KBS_BASE+0x27)
+#define IT83XX_KBS_KSOLGPODR REG8(IT83XX_KBS_BASE+0x28)
/* Shared Memory Flash Interface Bridge (SMFI) */
#define IT83XX_SMFI_BASE 0x00F01000