Microchip: MEC172x: kscan driver

Update keyscan driver to support MEC172x device

Signed-off-by: Jay Vasanth <jay.vasanth@microchip.com>
This commit is contained in:
Jay Vasanth 2021-11-22 14:41:23 -05:00 committed by Anas Nashif
commit f6394e0d54
6 changed files with 250 additions and 96 deletions

View file

@ -148,3 +148,7 @@
lines = <4>; lines = <4>;
chip-select = <0>; chip-select = <0>;
}; };
&kscan0 {
status = "okay";
};

View file

@ -74,6 +74,36 @@ const struct pin_info espi_pin_table[] = {
#endif #endif
}; };
/* kscan: KSCAN KSO & KSI */
const struct pin_info kscan_pin_table[] = {
#if defined(CONFIG_KSCAN_XEC) && DT_NODE_HAS_STATUS(DT_NODELABEL(kscan0), okay)
{ port_040_076, MCHP_GPIO_040, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_045, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_046, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_125, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_126, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_047, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_107, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_112, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_113, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_140_176, MCHP_GPIO_152, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_140_176, MCHP_GPIO_151, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_120, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_121, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_122, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_123, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_100_136, MCHP_GPIO_124, MCHP_GPIO_CTRL_MUX_F2 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_017, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_020, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_021, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_026, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_027, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_030, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_031, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
{ port_040_076, MCHP_GPIO_032, MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_PUD_PU },
#endif
};
static void brd_init_pinmux_ports(struct pinmux_ports_t *pp) static void brd_init_pinmux_ports(struct pinmux_ports_t *pp)
{ {
ARG_UNUSED(pp); ARG_UNUSED(pp);
@ -167,6 +197,7 @@ static int board_pinmux_init(const struct device *dev)
brd_init_pinmux_ports(&pp); brd_init_pinmux_ports(&pp);
brd_pin_table_init(&pp, uart_pin_table, ARRAY_SIZE(uart_pin_table)); brd_pin_table_init(&pp, uart_pin_table, ARRAY_SIZE(uart_pin_table));
brd_pin_table_init(&pp, espi_pin_table, ARRAY_SIZE(espi_pin_table)); brd_pin_table_init(&pp, espi_pin_table, ARRAY_SIZE(espi_pin_table));
brd_pin_table_init(&pp, kscan_pin_table, ARRAY_SIZE(kscan_pin_table));
return 0; return 0;
} }

View file

@ -3,9 +3,12 @@
# Copyright (c) 2019 Intel Corporation # Copyright (c) 2019 Intel Corporation
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
DT_COMPAT_ST_KSCAN_XEC := microchip,xec-kscan
menuconfig KSCAN_XEC menuconfig KSCAN_XEC
bool "XEC Microchip KSCAN driver" bool "Microchip XEC series KSCAN driver"
depends on SOC_FAMILY_MEC depends on SOC_FAMILY_MEC
default $(dt_compat_enabled,$(DT_COMPAT_ST_KSCAN_XEC))
select MULTITHREADING select MULTITHREADING
help help
Enable the Microchip XEC Kscan IO driver. Enable the Microchip XEC Kscan IO driver.
@ -13,33 +16,33 @@ menuconfig KSCAN_XEC
if KSCAN_XEC if KSCAN_XEC
config KSCAN_XEC_COLUMN_SIZE config KSCAN_XEC_COLUMN_SIZE
int "KSCAN_XEC_COLUMN_SIZE" int "Keyscan XEC Column Size"
default 16 default 16
help help
Adjust the value to your keyboard columns. The maximum Adjust the value to your keyboard columns. The maximum
column size for the Microchip XEC family is 18 (from 0 to 17). column size for the Microchip XEC family is 18 (from 0 to 17).
config KSCAN_XEC_ROW_SIZE config KSCAN_XEC_ROW_SIZE
int "KSCAN_XEC_ROW_SIZE" int "Keyscan XEC Row Size"
default 8 default 8
help help
Adjust the value to your keyboard rows. The maximum Adjust the value to your keyboard rows. The maximum
column size for the Microchip XEC family is 8 (from 0 to 7). column size for the Microchip XEC family is 8 (from 0 to 7).
config KSCAN_XEC_DEBOUNCE_DOWN config KSCAN_XEC_DEBOUNCE_DOWN
int "KSCAN_XEC_DEBOUNCE_DOWN" int "Keyscan XEC Debounce Down"
default 10 default 10
help help
Determines the time in msecs for debouncing a key press. Determines the time in msecs for debouncing a key press.
config KSCAN_XEC_DEBOUNCE_UP config KSCAN_XEC_DEBOUNCE_UP
int "KSCAN_XEC_DEBOUNCE_UP" int "Keyscan XEC Debounce Up"
default 20 default 20
help help
Determines the time in msecs for debouncing a key release. Determines the time in msecs for debouncing a key release.
config KSCAN_XEC_POLL_PERIOD config KSCAN_XEC_POLL_PERIOD
int "KSCAN_XEC_POLL_PERIOD" int "Keyscan XEC Poll Period"
default 5 default 5
help help
Defines the poll period in msecs between between matrix scans. Defines the poll period in msecs between between matrix scans.

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2019 Intel Corporation * Copyright (c) 2019 Intel Corporation
* * Copyright (c) 2022 Microchip Technology Inc.
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -8,11 +8,14 @@
#include <errno.h> #include <errno.h>
#include <device.h> #include <device.h>
#include <drivers/clock_control/mchp_xec_clock_control.h>
#include <drivers/interrupt_controller/intc_mchp_xec_ecia.h>
#include <drivers/kscan.h> #include <drivers/kscan.h>
#include <kernel.h> #include <kernel.h>
#include <soc.h> #include <soc.h>
#include <sys/atomic.h> #include <sys/atomic.h>
#include <logging/log.h> #include <logging/log.h>
#include <arch/arm/aarch32/cortex_m/cmsis.h>
#define LOG_LEVEL CONFIG_KSCAN_LOG_LEVEL #define LOG_LEVEL CONFIG_KSCAN_LOG_LEVEL
LOG_MODULE_REGISTER(kscan_mchp_xec); LOG_MODULE_REGISTER(kscan_mchp_xec);
@ -33,6 +36,16 @@ LOG_MODULE_REGISTER(kscan_mchp_xec);
/* Thread stack size */ /* Thread stack size */
#define TASK_STACK_SIZE 1024 #define TASK_STACK_SIZE 1024
struct kscan_xec_config {
struct kscan_regs *regs;
uint8_t girq;
uint8_t girq_pos;
uint8_t irq_pri;
uint8_t pcr_idx;
uint8_t pcr_pos;
uint8_t rsvd[3];
};
struct kscan_xec_data { struct kscan_xec_data {
/* variables in usec units */ /* variables in usec units */
uint32_t deb_time_press; uint32_t deb_time_press;
@ -57,31 +70,84 @@ struct kscan_xec_data {
K_KERNEL_STACK_MEMBER(thread_stack, TASK_STACK_SIZE); K_KERNEL_STACK_MEMBER(thread_stack, TASK_STACK_SIZE);
}; };
static KSCAN_Type *base = (KSCAN_Type *) #ifdef CONFIG_SOC_SERIES_MEC172X
(DT_INST_REG_ADDR(0)); static void kscan_clear_girq_status(const struct device *dev)
static struct kscan_xec_data kbd_data;
static void drive_keyboard_column(int data)
{ {
struct kscan_xec_config const *cfg = dev->config;
mchp_xec_ecia_girq_src_clr(cfg->girq, cfg->girq_pos);
}
static void kscan_configure_girq(const struct device *dev, bool enable)
{
struct kscan_xec_config const *cfg = dev->config;
if (enable) {
mchp_xec_ecia_enable(cfg->girq, cfg->girq_pos);
} else {
mchp_xec_ecia_disable(cfg->girq, cfg->girq_pos);
}
}
static void kscan_clr_slp_en(const struct device *dev)
{
struct kscan_xec_config const *cfg = dev->config;
z_mchp_xec_pcr_periph_sleep(cfg->pcr_idx, cfg->pcr_pos, 0);
}
#else
static void kscan_clear_girq_status(const struct device *dev)
{
ARG_UNUSED(dev);
MCHP_GIRQ_SRC(MCHP_KSCAN_GIRQ) = BIT(MCHP_KSCAN_GIRQ_POS);
}
static void kscan_configure_girq(const struct device *dev, bool enable)
{
if (enable) {
MCHP_GIRQ_ENSET(MCHP_KSCAN_GIRQ) = BIT(MCHP_KSCAN_GIRQ_POS);
} else {
MCHP_GIRQ_ENCLR(MCHP_KSCAN_GIRQ) = BIT(MCHP_KSCAN_GIRQ_POS);
}
}
static void kscan_clr_slp_en(const struct device *dev)
{
ARG_UNUSED(dev);
mchp_pcr_periph_slp_ctrl(PCR_KEYSCAN, 0);
}
#endif
static void drive_keyboard_column(const struct device *dev, int data)
{
struct kscan_xec_config const *cfg = dev->config;
struct kscan_regs *regs = cfg->regs;
if (data == KEYBOARD_COLUMN_DRIVE_ALL) { if (data == KEYBOARD_COLUMN_DRIVE_ALL) {
/* KSO output controlled by the KSO_SELECT field */ /* KSO output controlled by the KSO_SELECT field */
base->KSO_SEL = MCHP_KSCAN_KSO_ALL; regs->KSO_SEL = MCHP_KSCAN_KSO_ALL;
} else if (data == KEYBOARD_COLUMN_DRIVE_NONE) { } else if (data == KEYBOARD_COLUMN_DRIVE_NONE) {
/* Keyboard scan disabled. All KSO output buffers disabled */ /* Keyboard scan disabled. All KSO output buffers disabled */
base->KSO_SEL = MCHP_KSCAN_KSO_EN; regs->KSO_SEL = MCHP_KSCAN_KSO_EN;
} else { } else {
/* It is assumed, KEYBOARD_COLUMN_DRIVE_ALL was /* It is assumed, KEYBOARD_COLUMN_DRIVE_ALL was
* previously set * previously set
*/ */
base->KSO_SEL = data; regs->KSO_SEL = data;
} }
} }
static uint8_t read_keyboard_row(void) static uint8_t read_keyboard_row(const struct device *dev)
{ {
struct kscan_xec_config const *cfg = dev->config;
struct kscan_regs *regs = cfg->regs;
/* In this implementation a 1 means key pressed */ /* In this implementation a 1 means key pressed */
return ~(base->KSI_IN & 0xFF); return ~(regs->KSI_IN & 0xFF);
} }
static bool is_matrix_ghosting(const uint8_t *state) static bool is_matrix_ghosting(const uint8_t *state)
@ -123,49 +189,51 @@ static bool is_matrix_ghosting(const uint8_t *state)
return false; return false;
} }
static bool read_keyboard_matrix(uint8_t *new_state) static bool read_keyboard_matrix(const struct device *dev, uint8_t *new_state)
{ {
uint8_t row; uint8_t row;
uint8_t key_event = 0U; uint8_t key_event = 0U;
for (int col = 0; col < MAX_MATRIX_KEY_COLS; col++) { for (int col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
drive_keyboard_column(col); drive_keyboard_column(dev, col);
/* Allow the matrix to stabilize before reading it */ /* Allow the matrix to stabilize before reading it */
k_busy_wait(50U); k_busy_wait(50U);
row = read_keyboard_row(); row = read_keyboard_row(dev);
new_state[col] = row; new_state[col] = row;
key_event |= row; key_event |= row;
} }
drive_keyboard_column(KEYBOARD_COLUMN_DRIVE_NONE); drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_NONE);
return key_event != 0U ? true : false; return key_event != 0U ? true : false;
} }
static void scan_matrix_xec_isr(const void *arg) static void scan_matrix_xec_isr(const struct device *dev)
{ {
ARG_UNUSED(arg); struct kscan_xec_data *const data = dev->data;
MCHP_GIRQ_SRC(MCHP_KSCAN_GIRQ) = BIT(MCHP_KSCAN_GIRQ_POS); kscan_clear_girq_status(dev);
irq_disable(DT_INST_IRQN(0)); irq_disable(DT_INST_IRQN(0));
k_sem_give(&kbd_data.poll_lock); k_sem_give(&data->poll_lock);
LOG_DBG(" "); LOG_DBG(" ");
} }
static bool check_key_events(const struct device *dev) static bool check_key_events(const struct device *dev)
{ {
struct kscan_xec_data *const data = dev->data;
uint8_t matrix_new_state[MAX_MATRIX_KEY_COLS] = {0U}; uint8_t matrix_new_state[MAX_MATRIX_KEY_COLS] = {0U};
bool key_pressed = false; bool key_pressed = false;
uint32_t cycles_now = k_cycle_get_32(); uint32_t cycles_now = k_cycle_get_32();
if (++kbd_data.scan_cycles_idx >= SCAN_OCURRENCES) if (++data->scan_cycles_idx >= SCAN_OCURRENCES) {
kbd_data.scan_cycles_idx = 0U; data->scan_cycles_idx = 0U;
}
kbd_data.scan_clk_cycle[kbd_data.scan_cycles_idx] = cycles_now; data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now;
/* Scan the matrix */ /* Scan the matrix */
key_pressed = read_keyboard_matrix(matrix_new_state); key_pressed = read_keyboard_matrix(dev, matrix_new_state);
/* Abort if ghosting is detected */ /* Abort if ghosting is detected */
if (is_matrix_ghosting(matrix_new_state)) { if (is_matrix_ghosting(matrix_new_state)) {
@ -181,29 +249,32 @@ static bool check_key_events(const struct device *dev)
for (int c = 0; c < MAX_MATRIX_KEY_COLS; c++) { for (int c = 0; c < MAX_MATRIX_KEY_COLS; c++) {
/* Check if there was an update from the previous scan */ /* Check if there was an update from the previous scan */
row_changed = matrix_new_state[c] ^ row_changed = matrix_new_state[c] ^
kbd_data.matrix_previous_state[c]; data->matrix_previous_state[c];
if (!row_changed) if (!row_changed) {
continue; continue;
}
for (int r = 0; r < MAX_MATRIX_KEY_ROWS; r++) { for (int r = 0; r < MAX_MATRIX_KEY_ROWS; r++) {
/* Index all they keys that changed for each row /* Index all they keys that changed for each row
* in order to debounce each key in terms of it * in order to debounce each key in terms of it
*/ */
if (row_changed & BIT(r)) if (row_changed & BIT(r)) {
kbd_data.scan_cycle_idx[c][r] = data->scan_cycle_idx[c][r] =
kbd_data.scan_cycles_idx; data->scan_cycles_idx;
}
} }
kbd_data.matrix_unstable_state[c] |= row_changed; data->matrix_unstable_state[c] |= row_changed;
kbd_data.matrix_previous_state[c] = matrix_new_state[c]; data->matrix_previous_state[c] = matrix_new_state[c];
} }
for (int c = 0; c < MAX_MATRIX_KEY_COLS; c++) { for (int c = 0; c < MAX_MATRIX_KEY_COLS; c++) {
deb_col = kbd_data.matrix_unstable_state[c]; deb_col = data->matrix_unstable_state[c];
if (!deb_col) if (!deb_col) {
continue; continue;
}
/* Debouncing for each row key occurs here */ /* Debouncing for each row key occurs here */
for (int r = 0; r < MAX_MATRIX_KEY_ROWS; r++) { for (int r = 0; r < MAX_MATRIX_KEY_ROWS; r++) {
@ -211,24 +282,25 @@ static bool check_key_events(const struct device *dev)
uint8_t row_bit = matrix_new_state[c] & mask; uint8_t row_bit = matrix_new_state[c] & mask;
/* Continue if we already debounce a key */ /* Continue if we already debounce a key */
if (!(deb_col & mask)) if (!(deb_col & mask)) {
continue; continue;
}
/* Convert the clock cycle differences to usec */ /* Convert the clock cycle differences to usec */
uint32_t debt = CLOCK_32K_HW_CYCLES_TO_US(cycles_now - uint32_t debt = CLOCK_32K_HW_CYCLES_TO_US(cycles_now -
kbd_data.scan_clk_cycle[kbd_data.scan_cycle_idx[c][r]]); data->scan_clk_cycle[data->scan_cycle_idx[c][r]]);
/* Does the key requires more time to be debounced? */ /* Does the key requires more time to be debounced? */
if (debt < (row_bit ? kbd_data.deb_time_press : if (debt < (row_bit ? data->deb_time_press :
kbd_data.deb_time_rel)) { data->deb_time_rel)) {
/* Need more time to debounce */ /* Need more time to debounce */
continue; continue;
} }
kbd_data.matrix_unstable_state[c] &= ~row_bit; data->matrix_unstable_state[c] &= ~row_bit;
/* Check if there was a change in the stable state */ /* Check if there was a change in the stable state */
if ((kbd_data.matrix_stable_state[c] & mask) if ((data->matrix_stable_state[c] & mask)
== row_bit) { == row_bit) {
/* Key state did not change */ /* Key state did not change */
continue; continue;
@ -239,10 +311,10 @@ static bool check_key_events(const struct device *dev)
* the stable state. Then, proceed to notify the * the stable state. Then, proceed to notify the
* application about the keys pressed. * application about the keys pressed.
*/ */
kbd_data.matrix_stable_state[c] ^= mask; data->matrix_stable_state[c] ^= mask;
if (atomic_get(&kbd_data.enable_scan) == 1U) { if (atomic_get(&data->enable_scan) == 1U) {
kbd_data.callback(dev, r, c, data->callback(dev, r, c,
row_bit ? true : false); row_bit ? true : false);
} }
} }
} }
@ -267,34 +339,38 @@ static bool poll_expired(uint32_t start_cycles, int64_t *timeout)
} }
void polling_task(void *dummy1, void *dummy2, void *dummy3) void polling_task(const struct device *dev, void *dummy2, void *dummy3)
{ {
struct kscan_xec_config const *cfg = dev->config;
struct kscan_xec_data *const data = dev->data;
struct kscan_regs *regs = cfg->regs;
uint32_t current_cycles; uint32_t current_cycles;
uint32_t cycles_diff; uint32_t cycles_diff;
uint32_t wait_period; uint32_t wait_period;
int64_t local_poll_timeout = kbd_data.poll_timeout; int64_t local_poll_timeout = data->poll_timeout;
ARG_UNUSED(dummy1);
ARG_UNUSED(dummy2); ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3); ARG_UNUSED(dummy3);
while (true) { while (true) {
base->KSI_STS = MCHP_KSCAN_KSO_SEL_REG_MASK; regs->KSI_STS = MCHP_KSCAN_KSO_SEL_REG_MASK;
/* Ignore isr when releasing a key as we are polling */ /* Ignore isr when releasing a key as we are polling */
MCHP_GIRQ_SRC(MCHP_KSCAN_GIRQ) = BIT(MCHP_KSCAN_GIRQ_POS); kscan_clear_girq_status(dev);
NVIC_ClearPendingIRQ(MCHP_KSAN_NVIC); NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
irq_enable(MCHP_KSAN_NVIC); irq_enable(DT_INST_IRQN(0));
drive_keyboard_column(KEYBOARD_COLUMN_DRIVE_ALL);
k_sem_take(&kbd_data.poll_lock, K_FOREVER); drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_ALL);
k_sem_take(&data->poll_lock, K_FOREVER);
uint32_t start_poll_cycles = k_cycle_get_32(); uint32_t start_poll_cycles = k_cycle_get_32();
while (atomic_get(&kbd_data.enable_scan) == 1U) { while (atomic_get(&data->enable_scan) == 1U) {
uint32_t start_period_cycles = k_cycle_get_32(); uint32_t start_period_cycles = k_cycle_get_32();
if (check_key_events(DEVICE_DT_INST_GET(0))) { if (check_key_events(DEVICE_DT_INST_GET(0))) {
local_poll_timeout = kbd_data.poll_timeout; local_poll_timeout = data->poll_timeout;
start_poll_cycles = k_cycle_get_32(); start_poll_cycles = k_cycle_get_32();
} else if (!poll_expired(start_poll_cycles, } else if (!poll_expired(start_poll_cycles,
&local_poll_timeout)) { &local_poll_timeout)) {
@ -307,21 +383,22 @@ void polling_task(void *dummy1, void *dummy2, void *dummy3)
*/ */
current_cycles = k_cycle_get_32(); current_cycles = k_cycle_get_32();
cycles_diff = current_cycles - start_period_cycles; cycles_diff = current_cycles - start_period_cycles;
wait_period = kbd_data.poll_period - wait_period = data->poll_period -
CLOCK_32K_HW_CYCLES_TO_US(cycles_diff); CLOCK_32K_HW_CYCLES_TO_US(cycles_diff);
/* Override wait_period in case it is less than 1 ms */ /* Override wait_period in case it is less than 1 ms */
if (wait_period < MSEC_PER_MS) if (wait_period < MSEC_PER_MS) {
wait_period = MSEC_PER_MS; wait_period = MSEC_PER_MS;
}
/* wait period results in a larger number when /* wait period results in a larger number when
* current cycles counter wrap. In this case, the * current cycles counter wrap. In this case, the
* whole poll period is used * whole poll period is used
*/ */
if (wait_period > kbd_data.poll_period) { if (wait_period > data->poll_period) {
LOG_DBG("wait_period : %u", wait_period); LOG_DBG("wait_period : %u", wait_period);
wait_period = kbd_data.poll_period; wait_period = data->poll_period;
} }
/* Allow other threads to run while we sleep */ /* Allow other threads to run while we sleep */
@ -333,33 +410,34 @@ void polling_task(void *dummy1, void *dummy2, void *dummy3)
static int kscan_xec_configure(const struct device *dev, static int kscan_xec_configure(const struct device *dev,
kscan_callback_t callback) kscan_callback_t callback)
{ {
ARG_UNUSED(dev); struct kscan_xec_data *const data = dev->data;
if (!callback) { if (!callback) {
return -EINVAL; return -EINVAL;
} }
kbd_data.callback = callback; data->callback = callback;
MCHP_GIRQ_ENSET(MCHP_KSCAN_GIRQ) = BIT(MCHP_KSCAN_GIRQ_POS); kscan_clear_girq_status(dev);
kscan_configure_girq(dev, 1);
return 0; return 0;
} }
static int kscan_xec_inhibit_interface(const struct device *dev) static int kscan_xec_inhibit_interface(const struct device *dev)
{ {
ARG_UNUSED(dev); struct kscan_xec_data *const data = dev->data;
atomic_set(&kbd_data.enable_scan, 0); atomic_set(&data->enable_scan, 0);
return 0; return 0;
} }
static int kscan_xec_enable_interface(const struct device *dev) static int kscan_xec_enable_interface(const struct device *dev)
{ {
ARG_UNUSED(dev); struct kscan_xec_data *const data = dev->data;
atomic_set(&kbd_data.enable_scan, 1); atomic_set(&data->enable_scan, 1);
return 0; return 0;
} }
@ -370,45 +448,63 @@ static const struct kscan_driver_api kscan_xec_driver_api = {
.enable_callback = kscan_xec_enable_interface, .enable_callback = kscan_xec_enable_interface,
}; };
static int kscan_xec_init(const struct device *dev);
DEVICE_DT_INST_DEFINE(0,
&kscan_xec_init,
NULL,
NULL, NULL,
POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY,
&kscan_xec_driver_api);
static int kscan_xec_init(const struct device *dev) static int kscan_xec_init(const struct device *dev)
{ {
ARG_UNUSED(dev); struct kscan_xec_config const *cfg = dev->config;
struct kscan_xec_data *const data = dev->data;
struct kscan_regs *regs = cfg->regs;
kscan_clr_slp_en(dev);
/* Enable predrive */ /* Enable predrive */
base->KSO_SEL |= BIT(MCHP_KSCAN_KSO_EN_POS); regs->KSO_SEL |= BIT(MCHP_KSCAN_KSO_EN_POS);
base->EXT_CTRL = MCHP_KSCAN_EXT_CTRL_PREDRV_EN; regs->EXT_CTRL = MCHP_KSCAN_EXT_CTRL_PREDRV_EN;
base->KSO_SEL &= ~BIT(MCHP_KSCAN_KSO_EN_POS); regs->KSO_SEL &= ~BIT(MCHP_KSCAN_KSO_EN_POS);
base->KSI_IEN = MCHP_KSCAN_KSI_IEN_REG_MASK; regs->KSI_IEN = MCHP_KSCAN_KSI_IEN_REG_MASK;
/* Time figures are transformed from msec to usec */ /* Time figures are transformed from msec to usec */
kbd_data.deb_time_press = (uint32_t) data->deb_time_press = (uint32_t)
(CONFIG_KSCAN_XEC_DEBOUNCE_DOWN * MSEC_PER_MS); (CONFIG_KSCAN_XEC_DEBOUNCE_DOWN * MSEC_PER_MS);
kbd_data.deb_time_rel = (uint32_t) data->deb_time_rel = (uint32_t)
(CONFIG_KSCAN_XEC_DEBOUNCE_UP * MSEC_PER_MS); (CONFIG_KSCAN_XEC_DEBOUNCE_UP * MSEC_PER_MS);
kbd_data.poll_period = (uint32_t) data->poll_period = (uint32_t)
(CONFIG_KSCAN_XEC_POLL_PERIOD * MSEC_PER_MS); (CONFIG_KSCAN_XEC_POLL_PERIOD * MSEC_PER_MS);
kbd_data.poll_timeout = 100 * MSEC_PER_MS; data->poll_timeout = 100 * MSEC_PER_MS;
k_sem_init(&kbd_data.poll_lock, 0, 1); k_sem_init(&data->poll_lock, 0, 1);
atomic_set(&kbd_data.enable_scan, 1); atomic_set(&data->enable_scan, 1);
k_thread_create(&kbd_data.thread, kbd_data.thread_stack, k_thread_create(&data->thread, data->thread_stack,
TASK_STACK_SIZE, TASK_STACK_SIZE,
polling_task, NULL, NULL, NULL, (void (*)(void *, void *, void *))polling_task,
(void *)dev, NULL, NULL,
K_PRIO_COOP(4), 0, K_NO_WAIT); K_PRIO_COOP(4), 0, K_NO_WAIT);
/* Interrupts are enabled in the thread function */ /* Interrupts are enabled in the thread function */
IRQ_CONNECT(MCHP_KSAN_NVIC, 0, scan_matrix_xec_isr, NULL, 0); IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
scan_matrix_xec_isr, DEVICE_DT_INST_GET(0), 0);
return 0; return 0;
} }
static struct kscan_xec_data kbd_data;
static struct kscan_xec_config kscan_xec_cfg_0 = {
.regs = (struct kscan_regs *)(DT_INST_REG_ADDR(0)),
#ifdef CONFIG_SOC_SERIES_MEC172X
.girq = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 0)),
.girq_pos = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 1)),
.pcr_idx = (uint8_t)(DT_INST_PROP_BY_IDX(0, pcrs, 0)),
.pcr_pos = (uint8_t)(DT_INST_PROP_BY_IDX(0, pcrs, 1)),
#else
.girq = MCHP_KSCAN_GIRQ,
.girq_pos = MCHP_KSCAN_GIRQ_POS,
.pcr_idx = 3u,
.pcr_pos = MCHP_PCR3_KEYSCAN_POS,
#endif
};
DEVICE_DT_INST_DEFINE(0, kscan_xec_init,
NULL, &kbd_data, &kscan_xec_cfg_0,
POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY,
&kscan_xec_driver_api);

View file

@ -736,6 +736,7 @@
#io-channel-cells = <1>; #io-channel-cells = <1>;
}; };
kscan0: kscan@40009c00 { kscan0: kscan@40009c00 {
compatible = "microchip,xec-kscan";
reg = <0x40009c00 0x18>; reg = <0x40009c00 0x18>;
interrupts = <135 0>; interrupts = <135 0>;
girqs = <21 25>; girqs = <21 25>;

View file

@ -1,11 +1,12 @@
# Copyright (c) 2019, Intel Corporation # Copyright (c) 2019, Intel Corporation
# Copyright (c) 2021, Microchip Technology Inc.
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
description: Microchip XEC keyboard matrix controller description: Microchip XEC keyboard matrix controller
compatible: "microchip,xec-kscan" compatible: "microchip,xec-kscan"
include: kscan.yaml include: [kscan.yaml]
properties: properties:
"#address-cells": "#address-cells":
@ -19,3 +20,21 @@ properties:
interrupts: interrupts:
required: true required: true
girqs:
type: array
required: false
description: Array of pairs of GIRQ number and bit position
pcrs:
type: array
required: false
description: ADC PCR register index and bit position
girq-cells:
- girqnum
- bitpos
pcr-cells:
- regidx
- bitpos