summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/damu/board.c28
-rw-r--r--board/damu/board.h8
-rw-r--r--board/damu/ec.tasklist1
-rw-r--r--board/damu/gpio.inc3
-rw-r--r--board/jacuzzi/board.c8
-rw-r--r--board/jacuzzi/board.h6
-rw-r--r--board/kappa/board.c8
-rw-r--r--board/kappa/board.h6
-rw-r--r--driver/ioexpander/it8801.c221
-rw-r--r--driver/ioexpander/it8801.h16
10 files changed, 283 insertions, 22 deletions
diff --git a/board/damu/board.c b/board/damu/board.c
index 4639a23e50..0fd5487f95 100644
--- a/board/damu/board.c
+++ b/board/damu/board.c
@@ -27,6 +27,8 @@
#include "hooks.h"
#include "host_command.h"
#include "i2c.h"
+#include "it8801.h"
+#include "keyboard_scan.h"
#include "lid_switch.h"
#include "power.h"
#include "power_button.h"
@@ -79,6 +81,32 @@ const struct power_signal_info power_signal_list[] = {
};
BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
+/* Keyboard scan setting */
+struct keyboard_scan_config keyscan_config = {
+ /*
+ * TODO(b/133200075): Tune this once we have the final performance
+ * out of the driver and the i2c bus.
+ */
+ .output_settle_us = 35,
+ .debounce_down_us = 5 * MSEC,
+ .debounce_up_us = 40 * MSEC,
+ .scan_period_us = 3 * MSEC,
+ .min_post_scan_delay_us = 1000,
+ .poll_timeout_us = 100 * MSEC,
+ .actual_key_mask = {
+ 0x14, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff,
+ 0xa4, 0xff, 0xfe, 0x55, 0xfa, 0xca /* full set */
+ },
+};
+
+struct ioexpander_config_t ioex_config[CONFIG_IO_EXPANDER_PORT_COUNT] = {
+ [0] = {
+ .i2c_host_port = I2C_PORT_IO_EXPANDER_IT8801,
+ .i2c_slave_addr = IT8801_I2C_ADDR,
+ .drv = &it8801_ioexpander_drv,
+ },
+};
+
/******************************************************************************/
/* SPI devices */
/* TODO: to be added once sensors land via CL:1714436 */
diff --git a/board/damu/board.h b/board/damu/board.h
index 8399a19b81..8e45ebc3e6 100644
--- a/board/damu/board.h
+++ b/board/damu/board.h
@@ -81,6 +81,14 @@
(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) |\
EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON))
+#define CONFIG_IO_EXPANDER
+#define CONFIG_IO_EXPANDER_IT8801
+#define CONFIG_IO_EXPANDER_PORT_COUNT 1
+#define CONFIG_KEYBOARD_DEBUG
+#define CONFIG_KEYBOARD_NOT_RAW
+#define CONFIG_KEYBOARD_BOARD_CONFIG
+#define CONFIG_KEYBOARD_COL2_INVERTED
+
#define PD_OPERATING_POWER_MW 30000
#ifndef __ASSEMBLER__
diff --git a/board/damu/ec.tasklist b/board/damu/ec.tasklist
index f4fb8670ea..4b7574652e 100644
--- a/board/damu/ec.tasklist
+++ b/board/damu/ec.tasklist
@@ -15,6 +15,7 @@
TASK_NOTEST(PDCMD, pd_command_task, NULL, 1024) \
TASK_ALWAYS(HOSTCMD, host_command_task, NULL, 1024) \
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(PD_C0, pd_task, NULL, 1280) \
TASK_ALWAYS(PD_INT_C0, pd_interrupt_handler_task, 0, 1024) \
TASK_ALWAYS_RO(EMMC, emmc_task, NULL, LARGER_TASK_STACK_SIZE)
diff --git a/board/damu/gpio.inc b/board/damu/gpio.inc
index 16daee88ee..90f6edd908 100644
--- a/board/damu/gpio.inc
+++ b/board/damu/gpio.inc
@@ -33,11 +33,12 @@ GPIO_INT(AC_PRESENT, PIN(A, 6), GPIO_INT_BOTH,
extpower_interrupt) /* ACOK_OD */
GPIO_INT(BC12_EC_INT_ODL, PIN(C, 9), GPIO_INT_FALLING,
bc12_interrupt)
+GPIO_INT(IT8801_SMB_INT, PIN(A, 8), GPIO_INT_FALLING | GPIO_PULL_UP,
+ io_expander_it8801_interrupt) /* KB_INT_ODL */
GPIO_INT(AP_EC_WATCHDOG_L, PIN(D, 2), GPIO_INT_FALLING,
chipset_watchdog_interrupt)
/* Unimplemented interrupts */
-GPIO(KB_INT_ODL, PIN(A, 8), GPIO_INPUT)
GPIO(ALS_RGB_INT_ODL, PIN(C, 10), GPIO_INPUT)
GPIO(TABLET_MODE_L, PIN(B, 11), GPIO_INPUT)
diff --git a/board/jacuzzi/board.c b/board/jacuzzi/board.c
index 8becdc3328..9029fa764b 100644
--- a/board/jacuzzi/board.c
+++ b/board/jacuzzi/board.c
@@ -107,6 +107,14 @@ struct keyboard_scan_config keyscan_config = {
},
};
+struct ioexpander_config_t ioex_config[CONFIG_IO_EXPANDER_PORT_COUNT] = {
+ [0] = {
+ .i2c_host_port = I2C_PORT_IO_EXPANDER_IT8801,
+ .i2c_slave_addr = IT8801_I2C_ADDR,
+ .drv = &it8801_ioexpander_drv,
+ },
+};
+
/******************************************************************************/
/* SPI devices */
const struct spi_device_t spi_devices[] = {
diff --git a/board/jacuzzi/board.h b/board/jacuzzi/board.h
index faab414edd..a3ca10e276 100644
--- a/board/jacuzzi/board.h
+++ b/board/jacuzzi/board.h
@@ -91,13 +91,15 @@
(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) |\
EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON))
-#define CONFIG_EC_KEYBOARD
+#define CONFIG_IO_EXPANDER
+#define CONFIG_IO_EXPANDER_IT8801
+#define CONFIG_IO_EXPANDER_PORT_COUNT 1
#define CONFIG_KEYBOARD_DEBUG
#define CONFIG_KEYBOARD_NOT_RAW
-#define CONFIG_IO_EXPANDER_IT8801
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_COL2_INVERTED
+
#define PD_OPERATING_POWER_MW 30000
#define CONFIG_LED_PWM
diff --git a/board/kappa/board.c b/board/kappa/board.c
index 97644e78d8..fcf1707528 100644
--- a/board/kappa/board.c
+++ b/board/kappa/board.c
@@ -103,6 +103,14 @@ struct keyboard_scan_config keyscan_config = {
},
};
+struct ioexpander_config_t ioex_config[CONFIG_IO_EXPANDER_PORT_COUNT] = {
+ [0] = {
+ .i2c_host_port = I2C_PORT_IO_EXPANDER_IT8801,
+ .i2c_slave_addr = IT8801_I2C_ADDR,
+ .drv = &it8801_ioexpander_drv,
+ },
+};
+
/******************************************************************************/
/* SPI devices */
/* TODO: to be added once sensors land via CL:1714436 */
diff --git a/board/kappa/board.h b/board/kappa/board.h
index 3e594dc7d9..8687c7a89b 100644
--- a/board/kappa/board.h
+++ b/board/kappa/board.h
@@ -82,13 +82,15 @@
(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) |\
EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON))
-#define CONFIG_EC_KEYBOARD
+#define CONFIG_IO_EXPANDER
+#define CONFIG_IO_EXPANDER_IT8801
+#define CONFIG_IO_EXPANDER_PORT_COUNT 1
#define CONFIG_KEYBOARD_DEBUG
#define CONFIG_KEYBOARD_NOT_RAW
-#define CONFIG_IO_EXPANDER_IT8801
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_COL2_INVERTED
+
#define PD_OPERATING_POWER_MW 30000
#undef CONFIG_LED_PWM_NEAR_FULL_COLOR
diff --git a/driver/ioexpander/it8801.c b/driver/ioexpander/it8801.c
index 00e40e12ed..1226378c9a 100644
--- a/driver/ioexpander/it8801.c
+++ b/driver/ioexpander/it8801.c
@@ -7,6 +7,7 @@
#include "console.h"
#include "gpio.h"
#include "i2c.h"
+#include "ioexpander.h"
#include "it8801.h"
#include "keyboard_raw.h"
#include "keyboard_scan.h"
@@ -16,6 +17,8 @@
#define CPRINTS(format, args...) cprints(CC_KEYSCAN, format, ## args)
+static int it8801_ioex_set_level(int ioex, int port, int mask, int value);
+
static int it8801_read(int reg, int *data)
{
return i2c_read8(I2C_PORT_IO_EXPANDER_IT8801, IT8801_I2C_ADDR,
@@ -58,7 +61,7 @@ static int it8801_check_vendor_id(void)
void keyboard_raw_init(void)
{
- int ret, val;
+ int ret;
/* Verify Vendor ID registers. */
ret = it8801_check_vendor_id();
@@ -84,8 +87,7 @@ void keyboard_raw_init(void)
it8801_write(IT8801_REG_GPIO23_KSO20, IT8801_REG_MASK_GPIODIR);
/* Start with KEYBOARD_COLUMN_ALL, output high(so selected). */
- it8801_read(IT8801_REG_GPIOG2SOVR, &val);
- it8801_write(IT8801_REG_GPIOG2SOVR, val | IT8801_REG_GPIO23SOV);
+ it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 1);
}
/* Keyboard scan in interrupt enable register */
@@ -113,7 +115,7 @@ BUILD_ASSERT(ARRAY_SIZE(kso_mapping) == KEYBOARD_COLS_MAX);
test_mockable void keyboard_raw_drive_column(int col)
{
- int kso_val, val;
+ int kso_val;
/* Tri-state all outputs */
if (col == KEYBOARD_COLUMN_NONE) {
@@ -122,9 +124,7 @@ test_mockable void keyboard_raw_drive_column(int col)
if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) {
/* Output low(so not selected). */
- it8801_read(IT8801_REG_GPIOG2SOVR, &val);
- it8801_write(IT8801_REG_GPIOG2SOVR, val &
- ~IT8801_REG_GPIO23SOV);
+ it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 0);
}
}
/* Assert all outputs */
@@ -134,9 +134,7 @@ test_mockable void keyboard_raw_drive_column(int col)
if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) {
/* Output high(so selected). */
- it8801_read(IT8801_REG_GPIOG2SOVR, &val);
- it8801_write(IT8801_REG_GPIOG2SOVR, val |
- IT8801_REG_GPIO23SOV);
+ it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 1);
}
} else {
/* To check if column is valid or not. */
@@ -152,14 +150,12 @@ test_mockable void keyboard_raw_drive_column(int col)
/* GPIO23 is inverted. */
if (col == IT8801_REG_MASK_SELKSO2) {
/* Output high(so selected). */
- it8801_read(IT8801_REG_GPIOG2SOVR, &val);
- it8801_write(IT8801_REG_GPIOG2SOVR, val |
- IT8801_REG_GPIO23SOV);
+ it8801_ioex_set_level(0, 2,
+ IT8801_REG_GPIO23SOV, 1);
} else {
/* Output low(so not selected). */
- it8801_read(IT8801_REG_GPIOG2SOVR, &val);
- it8801_write(IT8801_REG_GPIOG2SOVR, val &
- ~IT8801_REG_GPIO23SOV);
+ it8801_ioex_set_level(0, 2,
+ IT8801_REG_GPIO23SOV, 0);
}
}
}
@@ -199,6 +195,199 @@ void io_expander_it8801_interrupt(enum gpio_signal signal)
task_wake(TASK_ID_KEYSCAN);
}
+static int it8801_ioex_read(int ioex, int reg, int *data)
+{
+ struct ioexpander_config_t *ioex_p = &ioex_config[ioex];
+
+ return i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_slave_addr,
+ reg, data);
+}
+
+static int it8801_ioex_write(int ioex, int reg, int data)
+{
+ struct ioexpander_config_t *ioex_p = &ioex_config[ioex];
+
+ return i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_slave_addr,
+ reg, data);
+}
+
+/*
+ * Initialize the general purpose I/O port(GPIO)
+ */
+static int it8801_ioex_init(int ioex)
+{
+ int ret;
+
+ /* Verify Vendor ID registers. */
+ ret = it8801_check_vendor_id();
+ if (ret) {
+ CPRINTS("Failed to read IT8801 vendor id %x", ret);
+ return ret;
+ }
+
+ return EC_SUCCESS;
+}
+
+static const int it8801_valid_gpio_group[] = {
+ IT8801_VALID_GPIO_G0_MASK,
+ IT8801_VALID_GPIO_G1_MASK,
+ IT8801_VALID_GPIO_G2_MASK,
+};
+
+/* Mutexes */
+static struct mutex ioex_mutex;
+
+static uint8_t it8801_gpio_sov[ARRAY_SIZE(it8801_valid_gpio_group)];
+
+static int ioex_check_is_not_valid(int port, int mask)
+{
+ if (port >= ARRAY_SIZE(it8801_valid_gpio_group)) {
+ CPRINTS("Port%d is not support in IT8801", port);
+ return EC_ERROR_INVAL;
+ }
+
+ if (mask & ~it8801_valid_gpio_group[port]) {
+ CPRINTS("GPIO%d-%d is not support in IT8801", port,
+ __fls(mask & ~it8801_valid_gpio_group[port]));
+ return EC_ERROR_INVAL;
+ }
+
+ return EC_SUCCESS;
+}
+
+static int it8801_ioex_get_level(int ioex, int port, int mask, int *val)
+{
+ int rv;
+
+ if (ioex_check_is_not_valid(port, mask))
+ return EC_ERROR_INVAL;
+
+ rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_IPSR(port), val);
+
+ *val = !!(*val & mask);
+
+ return rv;
+}
+
+static int it8801_ioex_set_level(int ioex, int port, int mask, int value)
+{
+ int rv = EC_SUCCESS;
+
+ if (ioex_check_is_not_valid(port, mask))
+ return EC_ERROR_INVAL;
+
+ mutex_lock(&ioex_mutex);
+ /*
+ * The bit of output value in SOV is different than
+ * the one we were about to set it to.
+ */
+ if (!!(it8801_gpio_sov[port] & mask) ^ value) {
+ if (value)
+ it8801_gpio_sov[port] |= mask;
+ else
+ it8801_gpio_sov[port] &= ~mask;
+
+ rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_SOVR(port),
+ it8801_gpio_sov[port]);
+ }
+ mutex_unlock(&ioex_mutex);
+
+ return rv;
+}
+
+static int it8801_ioex_get_flags_by_mask(int ioex, int port,
+ int mask, int *flags)
+{
+ int rv, val;
+
+ if (ioex_check_is_not_valid(port, mask))
+ return EC_ERROR_INVAL;
+
+ rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_CR(port, mask), &val);
+ if (rv)
+ return rv;
+
+ *flags = 0;
+
+ /* Get GPIO direction */
+ *flags |= (val & IT8801_GPIODIR) ? GPIO_OUTPUT : GPIO_INPUT;
+
+ /* Get GPIO type, 0:push-pull 1:open-drain */
+ if (val & IT8801_GPIOIOT)
+ *flags |= GPIO_OPEN_DRAIN;
+
+ rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_IPSR(port), &val);
+ if (rv)
+ return rv;
+
+ /* Get GPIO output level */
+ *flags |= (val & mask) ? GPIO_HIGH : GPIO_LOW;
+
+ return EC_SUCCESS;
+}
+
+static int it8801_ioex_set_flags_by_mask(int ioex, int port,
+ int mask, int flags)
+{
+ int rv, val;
+
+ if (ioex_check_is_not_valid(port, mask))
+ return EC_ERROR_INVAL;
+
+ if (flags & ~IT8801_SUPPORT_GPIO_FLAGS) {
+ CPRINTS("Flag 0x%08x is not supported at port %d, mask %d",
+ flags, port, mask);
+ return EC_ERROR_INVAL;
+ }
+
+ /* GPIO alternate function switching(GPIO[00, 12:15, 20:23]). */
+ it8801_ioex_write(ioex, IT8801_REG_GPIO_CR(port, mask),
+ IT8801_REG_MASK_GPIOAFS_FUNC1);
+
+ mutex_lock(&ioex_mutex);
+ rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_CR(port, mask), &val);
+ if (rv) {
+ mutex_unlock(&ioex_mutex);
+ return rv;
+ }
+ /* Select open drain 0:push-pull 1:open-drain */
+ if (flags & GPIO_OPEN_DRAIN)
+ val |= IT8801_GPIOIOT;
+ else
+ val &= ~IT8801_GPIOIOT;
+
+ /* Select GPIO direction */
+ if (flags & GPIO_OUTPUT) {
+ /* Configure the output level */
+ if (flags & GPIO_HIGH)
+ it8801_gpio_sov[port] |= mask;
+ else
+ it8801_gpio_sov[port] &= ~mask;
+
+ rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_SOVR(port),
+ it8801_gpio_sov[port]);
+ if (rv) {
+ mutex_unlock(&ioex_mutex);
+ return rv;
+ }
+ val |= IT8801_GPIODIR;
+ } else
+ val &= ~IT8801_GPIODIR;
+
+ rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_CR(port, mask), val);
+ mutex_unlock(&ioex_mutex);
+
+ return rv;
+}
+
+const struct ioexpander_drv it8801_ioexpander_drv = {
+ .init = &it8801_ioex_init,
+ .get_level = &it8801_ioex_get_level,
+ .set_level = &it8801_ioex_set_level,
+ .get_flags_by_mask = &it8801_ioex_get_flags_by_mask,
+ .set_flags_by_mask = &it8801_ioex_set_flags_by_mask,
+};
+
static void dump_register(int reg)
{
int rv;
diff --git a/driver/ioexpander/it8801.h b/driver/ioexpander/it8801.h
index b7e661effa..016412ca22 100644
--- a/driver/ioexpander/it8801.h
+++ b/driver/ioexpander/it8801.h
@@ -33,13 +33,25 @@
#define IT8801_REG_MASK_GPIOAFS_FUNC2 BIT(6)
#define IT8801_REG_MASK_GPIODIR BIT(5)
#define IT8801_REG_MASK_GPIOPUE BIT(0)
-#define IT8801_REG_GPIOG2SOVR 0x07
#define IT8801_REG_GPIO23SOV BIT(3)
#define IT8801_REG_MASK_SELKSO2 0x02
#define IT8801_REG_LBVIDR 0xFE
#define IT8801_REG_HBVIDR 0xFF
#define IT8801_KSO_COUNT 18
+/* General Purpose I/O Port (GPIO) */
+#define IT8801_SUPPORT_GPIO_FLAGS (GPIO_OPEN_DRAIN | GPIO_INPUT | \
+ GPIO_OUTPUT | GPIO_LOW | GPIO_HIGH)
+
+#define IT8801_REG_MASK_GPIOAFS_FUNC1 (0x00 << 7)
+
+/* IT8801 only supports GPIO 0/1/2 */
+#define IT8801_VALID_GPIO_G0_MASK 0xD9
+#define IT8801_VALID_GPIO_G1_MASK 0x3F
+#define IT8801_VALID_GPIO_G2_MASK 0x0F
+
+extern const struct ioexpander_drv it8801_ioexpander_drv;
+
/* GPIO Register map */
/* Input pin status register */
#define IT8801_REG_GPIO_IPSR(port) (0x00 + (port))
@@ -66,6 +78,8 @@
#define IT8801_GPIOIOT_INT_EDGE 3 /* = RISING + FALLING */
#define IT8801_GPIOIOT_OPEN_DRAIN 2
+#define IT8801_GPIODIR BIT(5)
+#define IT8801_GPIOIOT BIT(4)
#define IT8801_GPIOPOL BIT(2) /* polarity */
#define IT8801_GPIOPDE BIT(1) /* pull-down enable */
#define IT8801_GPIOPUE BIT(0) /* pull-up enable */