Browse Source

ITE drivers/kscan: add keyboard scan driver for it8xxx2_evb

Add keyboard scan driver for board it8xxx2_evb.

Signed-off-by: Ruibin Chang <ruibin.chang@ite.com.tw>
pull/38672/head
Ruibin Chang 5 years ago committed by Christopher Friedt
parent
commit
d16ae76d30
  1. 4
      boards/riscv/it8xxx2_evb/it8xxx2_evb.dts
  2. 2
      boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig
  3. 1
      drivers/kscan/CMakeLists.txt
  4. 1
      drivers/kscan/Kconfig
  5. 46
      drivers/kscan/Kconfig.it8xxx2
  6. 572
      drivers/kscan/kscan_ite_it8xxx2.c
  7. 25
      dts/bindings/kscan/ite,it8xxx2-kscan.yaml
  8. 8
      dts/riscv/it8xxx2-alts-map.dtsi
  9. 15
      dts/riscv/it8xxx2.dtsi
  10. 1
      include/dt-bindings/interrupt-controller/ite-intc.h
  11. 8
      soc/riscv/riscv-ite/common/check_regs.c
  12. 154
      soc/riscv/riscv-ite/common/chip_chipregs.h

4
boards/riscv/it8xxx2_evb/it8xxx2_evb.dts

@ -25,6 +25,7 @@
zephyr,flash = &flash0; zephyr,flash = &flash0;
zephyr,flash-controller = &flashctrl; zephyr,flash-controller = &flashctrl;
zephyr,code-partition = &slot0_partition; zephyr,code-partition = &slot0_partition;
zephyr,keyboard-scan = &kscan0;
}; };
pwmleds { pwmleds {
@ -91,6 +92,9 @@
prescaler-cx = <PWM_PRESCALER_C4>; prescaler-cx = <PWM_PRESCALER_C4>;
pwm-output-frequency = <30000>; pwm-output-frequency = <30000>;
}; };
&kscan0 {
status = "okay";
};
&flash0 { &flash0 {
partitions { partitions {
compatible = "fixed-partitions"; compatible = "fixed-partitions";

2
boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig

@ -17,6 +17,8 @@ CONFIG_UART_CONSOLE=y
CONFIG_UART_NS16550=y CONFIG_UART_NS16550=y
CONFIG_WATCHDOG=y CONFIG_WATCHDOG=y
CONFIG_WDT_ITE_IT8XXX2=y CONFIG_WDT_ITE_IT8XXX2=y
CONFIG_KSCAN=y
CONFIG_KSCAN_ITE_IT8XXX2=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=32768 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=32768

1
drivers/kscan/CMakeLists.txt

@ -3,6 +3,7 @@
zephyr_library() zephyr_library()
zephyr_library_sources_ifdef(CONFIG_KSCAN_FT5336 kscan_ft5336.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_FT5336 kscan_ft5336.c)
zephyr_library_sources_ifdef(CONFIG_KSCAN_ITE_IT8XXX2 kscan_ite_it8xxx2.c)
zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_KSCAN_SDL kscan_sdl.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_SDL kscan_sdl.c)
zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c)

1
drivers/kscan/Kconfig

@ -11,6 +11,7 @@ menuconfig KSCAN
if KSCAN if KSCAN
source "drivers/kscan/Kconfig.ft5336" source "drivers/kscan/Kconfig.ft5336"
source "drivers/kscan/Kconfig.it8xxx2"
source "drivers/kscan/Kconfig.xec" source "drivers/kscan/Kconfig.xec"
source "drivers/kscan/Kconfig.sdl" source "drivers/kscan/Kconfig.sdl"
source "drivers/kscan/Kconfig.ht16k33" source "drivers/kscan/Kconfig.ht16k33"

46
drivers/kscan/Kconfig.it8xxx2

@ -0,0 +1,46 @@
# Copyright (c) 2021 ITE Corporation. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
menuconfig KSCAN_ITE_IT8XXX2
bool "ITE KSCAN driver"
depends on SOC_IT8XXX2 && KSCAN
select MULTITHREADING
help
This option enables the ITE keyboard scan driver.
if KSCAN_ITE_IT8XXX2
config KSCAN_ITE_IT8XXX2_COLUMN_SIZE
int "KSCAN_ITE_IT8XXX2_COLUMN_SIZE"
range 16 18
default 16
help
Adjust the value to your keyboard columns. The maximum
column size for the ITE family is 18.
config KSCAN_ITE_IT8XXX2_ROW_SIZE
int "KSCAN_ITE_IT8XXX2_ROW_SIZE"
default 8
help
Adjust the value to your keyboard rows. The maximum
row size for the ITE family is 8.
config KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN
int "KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN"
default 9
help
Determines the time in msecs for debouncing a key press.
config KSCAN_ITE_IT8XXX2_DEBOUNCE_UP
int "KSCAN_ITE_IT8XXX2_DEBOUNCE_UP"
default 30
help
Determines the time in msecs for debouncing a key release.
config KSCAN_ITE_IT8XXX2_POLL_PERIOD
int "KSCAN_ITE_IT8XXX2_POLL_PERIOD"
default 3
help
Defines the poll period in msecs between matrix scans.
endif # KSCAN_ITE_IT8XXX2

572
drivers/kscan/kscan_ite_it8xxx2.c

@ -0,0 +1,572 @@
/*
* Copyright (c) 2021 ITE Corporation. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ite_it8xxx2_kscan
#include <device.h>
#include <drivers/gpio.h>
#include <drivers/kscan.h>
#include <drivers/pinmux.h>
#include <errno.h>
#include <kernel.h>
#include <soc.h>
#include <soc_dt.h>
#include <sys/atomic.h>
#include <logging/log.h>
#define LOG_LEVEL CONFIG_KSCAN_LOG_LEVEL
LOG_MODULE_REGISTER(kscan_ite_it8xxx2);
#define KEYBOARD_COLUMN_DRIVE_ALL -2
#define KEYBOARD_COLUMN_DRIVE_NONE -1
/* Free run timer counts transform to micro-seconds (clock source is 32768Hz) */
#define CLOCK_32K_HW_CYCLES_TO_US(X) \
(uint32_t)((((uint64_t)(X) * 1000000U) / \
sys_clock_hw_cycles_per_sec()))
/* Milli-second transform to micro-second */
#define MS_TO_US 1000U
/* Number of tracked scan times */
#define SCAN_OCURRENCES 30U
/* Thread stack size */
#define TASK_STACK_SIZE 1024
/* Device config */
enum kscan_pin_func {
KSO16 = 0,
KSO17,
};
struct kscan_alt_cfg {
/* Pinmux control device structure */
const struct device *pinctrls;
/* GPIO pin */
uint8_t pin;
/* Alternate function */
uint8_t alt_fun;
};
struct kscan_it8xxx2_config {
/* Keyboard scan controller base address */
uintptr_t base;
/* KSI[7:0] wake-up edge mode register */
uintptr_t reg_wuemr3;
/* KSI[7:0] wake-up edge sense register */
uintptr_t reg_wuesr3;
/* KSI[7:0] wake-up enable register */
uintptr_t reg_wuenr3;
/* Keyboard scan input (KSI) wake-up irq */
int irq;
/* GPIO control device structure */
const struct device *gpio_dev;
/* Keyboard scan alternate configuration list */
const struct kscan_alt_cfg *alt_list;
};
/* Device data */
struct kscan_it8xxx2_data {
/* Variables in usec units */
uint32_t deb_time_press;
uint32_t deb_time_rel;
int32_t poll_timeout;
uint32_t poll_period;
uint8_t matrix_stable_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE];
uint8_t matrix_unstable_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE];
uint8_t matrix_previous_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE];
/* Index in to the scan_clock_cycle to indicate start of debouncing */
uint8_t scan_cycle_idx[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE]
[CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE];
/*
* Track previous "elapsed clock cycles" per matrix scan. This
* is used to calculate the debouncing time for every key
*/
uint8_t scan_clk_cycle[SCAN_OCURRENCES];
struct k_sem poll_lock;
uint8_t scan_cycles_idx;
kscan_callback_t callback;
struct k_thread thread;
atomic_t enable_scan;
K_KERNEL_STACK_MEMBER(thread_stack, TASK_STACK_SIZE);
};
/* Driver convenience defines */
#define DRV_CONFIG(dev) ((const struct kscan_it8xxx2_config *)(dev)->config)
#define DRV_DATA(dev) ((struct kscan_it8xxx2_data *)(dev)->data)
#define DRV_REG(dev) (struct kscan_it8xxx2_regs *)(DRV_CONFIG(dev)->base)
static void drive_keyboard_column(const struct device *dev, int col)
{
struct kscan_it8xxx2_regs *const inst = DRV_REG(dev);
int mask;
/* Tri-state all outputs */
if (col == KEYBOARD_COLUMN_DRIVE_NONE)
mask = 0x3ffff;
/* Assert all outputs */
else if (col == KEYBOARD_COLUMN_DRIVE_ALL)
mask = 0;
/* Assert a single output */
else
mask = 0x3ffff ^ BIT(col);
/* Set KSO[17:0] output data */
inst->KBS_KSOL = (uint8_t) (mask & 0xff);
inst->KBS_KSOH1 = (uint8_t) ((mask >> 8) & 0xff);
#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16)
inst->KBS_KSOH2 = (uint8_t) ((mask >> 16) & 0xff);
#endif
}
static uint8_t read_keyboard_row(const struct device *dev)
{
struct kscan_it8xxx2_regs *const inst = DRV_REG(dev);
/* Bits are active-low, so toggle it (return 1 means key pressed) */
return (inst->KBS_KSI ^ 0xff);
}
static bool is_matrix_ghosting(const uint8_t *state)
{
/*
* Matrix keyboard designs are suceptible to ghosting.
* An extra key appears to be pressed when 3 keys
* belonging to the same block are pressed.
* for example, in the following block
*
* . . w . q .
* . . . . . .
* . . . . . .
* . . m . a .
*
* the key m would look as pressed if the user pressed keys
* w, q and a simultaneously. A block can also be formed,
* with not adjacent columns.
*/
for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) {
if (!state[c])
continue;
for (int c_n = c + 1; c_n < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c_n++) {
/*
* We AND the columns to detect a "block".
* this is an indication of ghosting, due to current
* flowing from a key which was never pressed. in our
* case, current flowing is a bit set to 1 as we
* flipped the bits when the matrix was scanned.
* now we OR the columns using z&(z-1) which is
* non-zero only if z has more than one bit set.
*/
uint8_t common_row_bits = state[c] & state[c_n];
if (common_row_bits & (common_row_bits - 1))
return true;
}
}
return false;
}
static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state)
{
uint8_t row;
uint8_t key_event = 0U;
for (int col = 0; col < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; col++) {
/* Drive specific column low and others high */
drive_keyboard_column(dev, col);
/* Allow the matrix to stabilize before reading it */
k_busy_wait(50U);
row = read_keyboard_row(dev);
new_state[col] = row;
key_event |= row;
}
drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_NONE);
return key_event != 0U ? true : false;
}
static void keyboard_raw_interrupt(const struct device *dev)
{
const struct kscan_it8xxx2_config *const config = DRV_CONFIG(dev);
volatile uint8_t *reg_wuesr3 = (uint8_t *)config->reg_wuesr3;
struct kscan_it8xxx2_data *data = DRV_DATA(dev);
/* W/C wakeup interrupt status of KSI[0:7] pins */
*reg_wuesr3 = 0xFF;
/* W/C interrupt status of KSI[7:0] pins */
ite_intc_isr_clear(config->irq);
/* Release poll lock semaphore */
k_sem_give(&data->poll_lock);
}
void keyboard_raw_enable_interrupt(const struct device *dev, int enable)
{
const struct kscan_it8xxx2_config *const config = DRV_CONFIG(dev);
volatile uint8_t *reg_wuesr3 = (uint8_t *)config->reg_wuesr3;
if (enable) {
/* W/C wakeup interrupt status of KSI[0:7] pins */
*reg_wuesr3 = 0xFF;
/* W/C interrupt status of KSI[7:0] pins */
ite_intc_isr_clear(config->irq);
irq_enable(config->irq);
} else {
irq_disable(config->irq);
}
}
static bool check_key_events(const struct device *dev)
{
struct kscan_it8xxx2_data *data = DRV_DATA(dev);
uint8_t matrix_new_state[CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE] = {0U};
bool key_pressed = false;
uint32_t cycles_now = k_cycle_get_32();
uint8_t row_changed = 0U;
uint8_t deb_col;
if (++data->scan_cycles_idx >= SCAN_OCURRENCES)
data->scan_cycles_idx = 0U;
data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now;
/* Scan the matrix */
key_pressed = read_keyboard_matrix(dev, matrix_new_state);
/* Abort if ghosting is detected */
if (is_matrix_ghosting(matrix_new_state)) {
return false;
}
/*
* The intent of this loop is to gather information related to key
* changes
*/
for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) {
/* Check if there was an update from the previous scan */
row_changed = matrix_new_state[c] ^
data->matrix_previous_state[c];
if (!row_changed)
continue;
for (int r = 0; r < CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE; r++) {
/*
* Index all they keys that changed for each row
* in order to debounce each key in terms of it
*/
if (row_changed & BIT(r))
data->scan_cycle_idx[c][r] =
data->scan_cycles_idx;
}
data->matrix_unstable_state[c] |= row_changed;
data->matrix_previous_state[c] = matrix_new_state[c];
}
for (int c = 0; c < CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE; c++) {
deb_col = data->matrix_unstable_state[c];
if (!deb_col)
continue;
/* Debouncing for each row key occurs here */
for (int r = 0; r < CONFIG_KSCAN_ITE_IT8XXX2_ROW_SIZE; r++) {
uint8_t mask = BIT(r);
uint8_t row_bit = matrix_new_state[c] & mask;
/* Continue if we already debounce a key */
if (!(deb_col & mask))
continue;
/* Convert the clock cycle differences to usec */
uint32_t debt = CLOCK_32K_HW_CYCLES_TO_US(cycles_now -
data->scan_clk_cycle[data->scan_cycle_idx[c][r]]);
/* Does the key requires more time to be debounced ? */
if (debt < (row_bit ? data->deb_time_press :
data->deb_time_rel)) {
/* Need more time to debounce */
continue;
}
data->matrix_unstable_state[c] &= ~row_bit;
/* Check if there was a change in the stable state */
if ((data->matrix_stable_state[c] & mask) == row_bit) {
/* Key state did not change */
continue;
}
/*
* The current row has been debounced, therefore update
* the stable state. Then, proceed to notify the
* application about the keys pressed.
*/
data->matrix_stable_state[c] ^= mask;
if ((atomic_get(&data->enable_scan) == 1U) &&
(data->callback != NULL)) {
data->callback(dev, r, c,
row_bit ? true : false);
}
}
}
return key_pressed;
}
/**
* @brief Determine if a timer is expired.
*
* @param start_cycles The starting time of HW cycle.
* @param timeout Pointer to the period time.
*
* @retval true If timer is expired;
* false If timer isn't expired.
*/
static bool poll_expired(uint32_t start_cycles, int32_t *timeout)
{
uint32_t now_cycles;
uint32_t microsecs_spent;
now_cycles = k_cycle_get_32();
microsecs_spent = CLOCK_32K_HW_CYCLES_TO_US(now_cycles - start_cycles);
/* Update the timeout value */
*timeout -= microsecs_spent;
return !(*timeout >= 0);
}
void polling_task(const struct device *dev, void *dummy2, void *dummy3)
{
struct kscan_it8xxx2_data *data = DRV_DATA(dev);
int32_t local_poll_timeout = data->poll_timeout;
uint32_t current_cycles;
uint32_t cycles_delta;
uint32_t wait_period;
ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3);
while (true) {
/* Init all KSO output low */
drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_ALL);
/* Enable wakeup and interrupt of KSI pins */
keyboard_raw_enable_interrupt(dev, 1);
/* Wait poll lock semaphore */
k_sem_take(&data->poll_lock, K_FOREVER);
/* Disable wakeup and interrupt of KSI pins after fired */
keyboard_raw_enable_interrupt(dev, 0);
uint32_t start_poll_cycles = k_cycle_get_32();
while (atomic_get(&data->enable_scan) == 1U) {
uint32_t start_period_cycles = k_cycle_get_32();
if (check_key_events(dev)) {
start_poll_cycles = k_cycle_get_32();
} else if (poll_expired(start_poll_cycles,
&local_poll_timeout)) {
break;
}
/*
* Subtract the time invested from the sleep period
* in order to compensate for the time invested
* in debouncing a key
*/
current_cycles = k_cycle_get_32();
cycles_delta = current_cycles - start_period_cycles;
wait_period = data->poll_period -
CLOCK_32K_HW_CYCLES_TO_US(cycles_delta);
/* Override wait_period in case it's less than 1000 us */
if (wait_period < MS_TO_US)
wait_period = MS_TO_US;
/*
* Wait period results in a larger number when
* current cycles counter wrap. In this case, the
* whole poll period is used
*/
if (wait_period > data->poll_period) {
LOG_DBG("wait_period : %u", wait_period);
wait_period = data->poll_period;
}
/* Allow other threads to run while we sleep */
k_usleep(wait_period);
}
}
}
static int kscan_it8xxx2_init(const struct device *dev)
{
const struct kscan_it8xxx2_config *const config = DRV_CONFIG(dev);
volatile uint8_t *reg_wuemr3 = (uint8_t *)config->reg_wuemr3;
volatile uint8_t *reg_wuesr3 = (uint8_t *)config->reg_wuesr3;
volatile uint8_t *reg_wuenr3 = (uint8_t *)config->reg_wuenr3;
struct kscan_it8xxx2_data *data = DRV_DATA(dev);
struct kscan_it8xxx2_regs *const inst = DRV_REG(dev);
/* Disable wakeup and interrupt of KSI pins before configuring */
keyboard_raw_enable_interrupt(dev, 0);
/*
* Bit[2] = 1: Enable the internal pull-up of KSO[15:0] pins
* Bit[0] = 1: Enable the open-drain mode of KSO[17:0] pins
*/
inst->KBS_KSOCTRL = (IT8XXX2_KBS_KSOOD | IT8XXX2_KBS_KSOPU);
#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16)
/*
* For KSO[16] and KSO[17]:
* 1.GPOTRC:
* Bit[x] = 1b: Enable the open-drain mode of KSO pin
* 2.GPCRCx:
* Bit[7:6] = 00b: Select alternate KSO function
* Bit[2] = 1b: Enable the internal pull-up of KSO pin
*
* NOTE: Set input temporarily for gpio_pin_configure(), after that
* pinmux_pin_set() set to alternate function immediately.
*/
gpio_pin_configure(config->gpio_dev,
config->alt_list[KSO16].pin,
(GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_UP));
gpio_pin_configure(config->gpio_dev,
config->alt_list[KSO17].pin,
(GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_UP));
pinmux_pin_set(config->alt_list[KSO16].pinctrls,
config->alt_list[KSO16].pin,
config->alt_list[KSO16].alt_fun);
pinmux_pin_set(config->alt_list[KSO17].pinctrls,
config->alt_list[KSO17].pin,
config->alt_list[KSO17].alt_fun);
#endif
/* Bit[2] = 1: Enable the internal pull-up of KSI[7:0] pins */
inst->KBS_KSICTRL = IT8XXX2_KBS_KSIPU;
/* KSO[17:0] pins output low */
inst->KBS_KSOL = 0x00;
inst->KBS_KSOH1 = 0x00;
#if (CONFIG_KSCAN_ITE_IT8XXX2_COLUMN_SIZE > 16)
inst->KBS_KSOH2 = 0x00;
#endif
/* Select wakeup interrupt falling-edge triggered of KSI[7:0] pins */
*reg_wuemr3 = 0xFF;
/* W/C wakeup interrupt status of KSI[7:0] pins */
*reg_wuesr3 = 0xFF;
/* W/C interrupt status of KSI[7:0] pins */
ite_intc_isr_clear(config->irq);
/* Enable wakeup interrupt of KSI[7:0] pins */
*reg_wuenr3 = 0xFF;
/* Kconfig.it8xxx2 time figures are transformed from msec to usec */
data->deb_time_press =
(uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_DEBOUNCE_DOWN * MS_TO_US);
data->deb_time_rel =
(uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_DEBOUNCE_UP * MS_TO_US);
data->poll_period =
(uint32_t) (CONFIG_KSCAN_ITE_IT8XXX2_POLL_PERIOD * MS_TO_US);
data->poll_timeout = 100 * MS_TO_US;
/* Init null for callback function */
data->callback = NULL;
/* Create poll lock semaphore */
k_sem_init(&data->poll_lock, 0, 1);
/* Enable keyboard scan loop */
atomic_set(&data->enable_scan, 1);
/* Create keyboard scan task */
k_thread_create(&data->thread, data->thread_stack,
TASK_STACK_SIZE,
(void (*)(void *, void *, void *))polling_task,
(void *)dev, NULL, NULL,
K_PRIO_COOP(4), 0, K_NO_WAIT);
irq_connect_dynamic(DT_INST_IRQN(0), 0,
(void (*)(const void *))keyboard_raw_interrupt,
(const void *)dev, 0);
return 0;
}
static int kscan_it8xxx2_configure(const struct device *dev,
kscan_callback_t callback)
{
struct kscan_it8xxx2_data *data = DRV_DATA(dev);
if (!callback) {
return -EINVAL;
}
/* Setup callback function */
data->callback = callback;
return 0;
}
static int kscan_it8xxx2_disable_callback(const struct device *dev)
{
struct kscan_it8xxx2_data *data = DRV_DATA(dev);
/* Disable keyboard scan loop */
atomic_set(&data->enable_scan, 0);
return 0;
}
static int kscan_it8xxx2_enable_callback(const struct device *dev)
{
struct kscan_it8xxx2_data *data = DRV_DATA(dev);
/* Enable keyboard scan loop */
atomic_set(&data->enable_scan, 1);
return 0;
}
static const struct kscan_driver_api kscan_it8xxx2_driver_api = {
.config = kscan_it8xxx2_configure,
.disable_callback = kscan_it8xxx2_disable_callback,
.enable_callback = kscan_it8xxx2_enable_callback,
};
static const struct kscan_alt_cfg kscan_alt_0[DT_INST_NUM_PINCTRLS_BY_IDX(0, 0)] =
IT8XXX2_DT_ALT_ITEMS_LIST(0);
static const struct kscan_it8xxx2_config kscan_it8xxx2_cfg_0 = {
.base = DT_INST_REG_ADDR_BY_IDX(0, 0),
.reg_wuemr3 = DT_INST_REG_ADDR_BY_IDX(0, 1),
.reg_wuesr3 = DT_INST_REG_ADDR_BY_IDX(0, 2),
.reg_wuenr3 = DT_INST_REG_ADDR_BY_IDX(0, 3),
.irq = DT_INST_IRQN(0),
.gpio_dev = DEVICE_DT_GET(DT_PHANDLE_BY_IDX(DT_DRV_INST(0), gpio_dev, 0)),
.alt_list = kscan_alt_0,
};
static struct kscan_it8xxx2_data kscan_it8xxx2_kbd_data;
DEVICE_DT_INST_DEFINE(0,
&kscan_it8xxx2_init,
NULL,
&kscan_it8xxx2_kbd_data,
&kscan_it8xxx2_cfg_0,
POST_KERNEL,
CONFIG_KSCAN_INIT_PRIORITY,
&kscan_it8xxx2_driver_api);

25
dts/bindings/kscan/ite,it8xxx2-kscan.yaml

@ -0,0 +1,25 @@
# Copyright (c) 2021 ITE Corporation. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
description: ITE it8xxx2 keyboard matrix controller
compatible: "ite,it8xxx2-kscan"
include: kscan.yaml
properties:
reg:
required: true
interrupts:
required: true
gpio-dev:
type: phandle
required: true
description: configure GPIO controller
pinctrl-0:
type: phandles
required: true
description: configure KSO pinmux controller

8
dts/riscv/it8xxx2-alts-map.dtsi

@ -113,5 +113,13 @@
pinctrl_shi_cs: shi_cs { pinctrl_shi_cs: shi_cs {
pinctrls = <&pinmuxm 5 IT8XXX2_PINMUX_FUNC_1>; pinctrls = <&pinmuxm 5 IT8XXX2_PINMUX_FUNC_1>;
}; };
/* Keyboard alternate function */
pinctrl_kso16: kso16 {
pinctrls = <&pinmuxc 3 IT8XXX2_PINMUX_FUNC_1>;
};
pinctrl_kso17: kso17 {
pinctrls = <&pinmuxc 5 IT8XXX2_PINMUX_FUNC_1>;
};
}; };
}; };

15
dts/riscv/it8xxx2.dtsi

@ -805,5 +805,20 @@
reg = <0x00f02000 0x100>; reg = <0x00f02000 0x100>;
label = "GCTRL"; label = "GCTRL";
}; };
kscan0: kscan@f01d00 {
compatible = "ite,it8xxx2-kscan";
reg = <0x00f01d00 0x29
0x00f01b02 0x01 /* WUEMR3 */
0x00f01b06 0x01 /* WUESR3 */
0x00f01b0a 0x01>; /* WUENR3 */
label = "KSCAN";
interrupt-parent = <&intc>;
interrupts = <IT8XXX2_IRQ_WKINTC IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
gpio-dev = <&gpioc>;
pinctrl-0 = <&pinctrl_kso16 /* GPC3 */
&pinctrl_kso17>; /* GPC5 */
};
}; };
}; };

1
include/dt-bindings/interrupt-controller/ite-intc.h

@ -19,6 +19,7 @@
#define IT8XXX2_IRQ_WU23 6 #define IT8XXX2_IRQ_WU23 6
/* Group 1 */ /* Group 1 */
#define IT8XXX2_IRQ_WU26 12 #define IT8XXX2_IRQ_WU26 12
#define IT8XXX2_IRQ_WKINTC 13
#define IT8XXX2_IRQ_WU25 14 #define IT8XXX2_IRQ_WU25 14
/* Group 2 */ /* Group 2 */
#define IT8XXX2_IRQ_WU24 17 #define IT8XXX2_IRQ_WU24 17

8
soc/riscv/riscv-ite/common/check_regs.c

@ -14,3 +14,11 @@ IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_SPCTRL4, 0x1c);
IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_RSTC5, 0x21); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_RSTC5, 0x21);
IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_MCCR2, 0x44); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_MCCR2, 0x44);
IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_ECHIPID2, 0x86); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_ECHIPID2, 0x86);
/* KSCAN register structure check */
IT8XXX2_REG_SIZE_CHECK(kscan_it8xxx2_regs, 0x0F);
IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSOL, 0x00);
IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSOCTRL, 0x02);
IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSI, 0x04);
IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSIGDAT, 0x08);
IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSOLGOEN, 0x0e);

154
soc/riscv/riscv-ite/common/chip_chipregs.h

@ -1,4 +1,4 @@
/* /*
* Copyright (c) 2020 ITE Corporation. All Rights Reserved. * Copyright (c) 2020 ITE Corporation. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -995,114 +995,54 @@ struct pwm_it8xxx2_regs {
/** /**
* *
* (1Dxxh) Keyboard Matrix Scan control (KBS) * (1Dxxh) Keyboard Matrix Scan control (KSCAN)
* *
*/ */
#define KSOL ECREG(EC_REG_BASE_ADDR + 0x1D00) #ifndef __ASSEMBLER__
#define KSOH1 ECREG(EC_REG_BASE_ADDR + 0x1D01) struct kscan_it8xxx2_regs {
#define KSOCTRL ECREG(EC_REG_BASE_ADDR + 0x1D02) /* 0x000: Keyboard Scan Out */
#define KSOH2 ECREG(EC_REG_BASE_ADDR + 0x1D03) volatile uint8_t KBS_KSOL;
#define KSI ECREG(EC_REG_BASE_ADDR + 0x1D04) /* 0x001: Keyboard Scan Out */
#define KSICTRL ECREG(EC_REG_BASE_ADDR + 0x1D05) volatile uint8_t KBS_KSOH1;
#define KSIGCTRL ECREG(EC_REG_BASE_ADDR + 0x1D06) /* 0x002: Keyboard Scan Out Control */
#define KSIGOEN ECREG(EC_REG_BASE_ADDR + 0x1D07) volatile uint8_t KBS_KSOCTRL;
#define KSIGDAT ECREG(EC_REG_BASE_ADDR + 0x1D08) /* 0x003: Keyboard Scan Out */
#define KSIGDMRR ECREG(EC_REG_BASE_ADDR + 0x1D09) volatile uint8_t KBS_KSOH2;
#define KSOHGCTRL ECREG(EC_REG_BASE_ADDR + 0x1D0A) /* 0x004: Keyboard Scan In */
#define KSOHGOEN ECREG(EC_REG_BASE_ADDR + 0x1D0B) volatile uint8_t KBS_KSI;
#define KSOHGDMRR ECREG(EC_REG_BASE_ADDR + 0x1D0C) /* 0x005: Keyboard Scan In Control */
#define KSOLGCTRL ECREG(EC_REG_BASE_ADDR + 0x1D0D) volatile uint8_t KBS_KSICTRL;
#define KSOLGOEN ECREG(EC_REG_BASE_ADDR + 0x1D0E) /* 0x006: Keyboard Scan In [7:0] GPIO Control */
#define KSOLGDMRR ECREG(EC_REG_BASE_ADDR + 0x1D0F) volatile uint8_t KBS_KSIGCTRL;
#define KSO0LSDR ECREG(EC_REG_BASE_ADDR + 0x1D10) /* 0x007: Keyboard Scan In [7:0] GPIO Output Enable */
#define KSO1LSDR ECREG(EC_REG_BASE_ADDR + 0x1D11) volatile uint8_t KBS_KSIGOEN;
#define KSO2LSDR ECREG(EC_REG_BASE_ADDR + 0x1D12) /* 0x008: Keyboard Scan In [7:0] GPIO Data */
#define KSO3LSDR ECREG(EC_REG_BASE_ADDR + 0x1D13) volatile uint8_t KBS_KSIGDAT;
#define KSO4LSDR ECREG(EC_REG_BASE_ADDR + 0x1D14) /* 0x009: Keyboard Scan In [7:0] GPIO Data Mirror */
#define KSO5LSDR ECREG(EC_REG_BASE_ADDR + 0x1D15) volatile uint8_t KBS_KSIGDMRR;
#define KSO6LSDR ECREG(EC_REG_BASE_ADDR + 0x1D16) /* 0x00A: Keyboard Scan Out [15:8] GPIO Control */
#define KSO7LSDR ECREG(EC_REG_BASE_ADDR + 0x1D17) volatile uint8_t KBS_KSOHGCTRL;
#define KSO8LSDR ECREG(EC_REG_BASE_ADDR + 0x1D18) /* 0x00B: Keyboard Scan Out [15:8] GPIO Output Enable */
#define KSO9LSDR ECREG(EC_REG_BASE_ADDR + 0x1D19) volatile uint8_t KBS_KSOHGOEN;
#define KSO10LSDR ECREG(EC_REG_BASE_ADDR + 0x1D1A) /* 0x00C: Keyboard Scan Out [15:8] GPIO Data Mirror */
#define KSO11LSDR ECREG(EC_REG_BASE_ADDR + 0x1D1B) volatile uint8_t KBS_KSOHGDMRR;
#define KSO12LSDR ECREG(EC_REG_BASE_ADDR + 0x1D1C) /* 0x00D: Keyboard Scan Out [7:0] GPIO Control */
#define KSO13LSDR ECREG(EC_REG_BASE_ADDR + 0x1D1D) volatile uint8_t KBS_KSOLGCTRL;
#define KSO14LSDR ECREG(EC_REG_BASE_ADDR + 0x1D1E) /* 0x00E: Keyboard Scan Out [7:0] GPIO Output Enable */
#define KSO15LSDR ECREG(EC_REG_BASE_ADDR + 0x1D1F) volatile uint8_t KBS_KSOLGOEN;
#define KSO16LSDR ECREG(EC_REG_BASE_ADDR + 0x1D20) };
#define KSO17LSDR ECREG(EC_REG_BASE_ADDR + 0x1D21) #endif /* !__ASSEMBLER__ */
#define SDC1R ECREG(EC_REG_BASE_ADDR + 0x1D22)
#define SDEN BIT(7) /* KBS register fields */
#define INTSDVEN BIT(5) /* 0x002: Keyboard Scan Out Control */
#define IT8XXX2_KBS_KSOPU BIT(2)
/* BIT2 ~ BIT0 Scan loop select */ #define IT8XXX2_KBS_KSOOD BIT(0)
#define SLS_00_ROUND 0x00 /* 0x005: Keyboard Scan In Control */
#define SLS_02_ROUND 0x01 #define IT8XXX2_KBS_KSIPU BIT(2)
#define SLS_03_ROUND 0x02 /* 0x00D: Keyboard Scan Out [7:0] GPIO Control */
#define SLS_04_ROUND 0x03 #define IT8XXX2_KBS_KSO2GCTRL BIT(2)
#define SLS_05_ROUND 0x04 /* 0x00E: Keyboard Scan Out [7:0] GPIO Output Enable */
#define SLS_06_ROUND 0x05 #define IT8XXX2_KBS_KSO2GOEN BIT(2)
#define SLS_07_ROUND 0x06
#define SLS_08_ROUND 0x07
#define SDC2R ECREG(EC_REG_BASE_ADDR + 0x1D23)
#define KSOPCS1 BIT(7)
#define KSOPCS0 BIT(6)
/* BIT3 ~ BIT0 Wait KSO high delay */
#define WKSOHDLY_23US 0x00
#define WKSOHDLY_31US 0x01
#define WKSOHDLY_39US 0x02
#define WKSOHDLY_47US 0x03
#define WKSOHDLY_55US 0x04
#define WKSOHDLY_63US 0x05
#define WKSOHDLY_71US 0x06
#define WKSOHDLY_79US 0x07
#define WKSOHDLY_87US 0x08
#define WKSOHDLY_95US 0x09
#define SDC3R ECREG(EC_REG_BASE_ADDR + 0x1D24)
/* BIT7 ~ BIT4 Wait KSO low delay */
#define WKSOLDLY_11US (0x00 << 4)
#define WKSOLDLY_13US (0x01 << 4)
#define WKSOLDLY_15US (0x02 << 4)
#define WKSOLDLY_17US (0x03 << 4)
#define WKSOLDLY_19US (0x04 << 4)
#define WKSOLDLY_21US (0x05 << 4)
#define WKSOLDLY_23US (0x06 << 4)
#define WKSOLDLY_25US (0x07 << 4)
#define WKSOLDLY_27US (0x08 << 4)
#define WKSOLDLY_29US (0x09 << 4)
/* BIT3 ~ BIT0 Spacing delay between rounds */
#define SDLYBR_00MS 0x00
#define SDLYBR_01MS 0x01
#define SDLYBR_02MS 0x02
#define SDLYBR_03MS 0x03
#define SDLYBR_04MS 0x04
#define SDLYBR_05MS 0x05
#define SDLYBR_06MS 0x06
#define SDLYBR_07MS 0x07
#define SDLYBR_08MS 0x08
#define SDLYBR_09MS 0x09
#define SDLYBR_10MS 0x0A
#define SDLYBR_11MS 0x0B
#define SDLYBR_12MS 0x0C
#define SDLYBR_13MS 0x0D
#define SDLYBR_14MS 0x0E
#define SDLYBR_15MS 0x0F
#define SDSR ECREG(EC_REG_BASE_ADDR + 0x1D25)
#define SDV BIT(0)
/* Keyboard Scan Out Control Register */
#define KSOPU BIT(2)
#define KSOOD BIT(0)
/* Keyboard Scan In Control Register */
#define KSIPU BIT(2)
/** /**
* *

Loading…
Cancel
Save