summaryrefslogtreecommitdiff
path: root/chip/npcx/ps2.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /chip/npcx/ps2.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14526.84.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'chip/npcx/ps2.c')
-rw-r--r--chip/npcx/ps2.c366
1 files changed, 0 insertions, 366 deletions
diff --git a/chip/npcx/ps2.c b/chip/npcx/ps2.c
deleted file mode 100644
index 7b8086cbcd..0000000000
--- a/chip/npcx/ps2.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright 2019 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/* PS/2 module for Chrome EC */
-#include "atomic.h"
-#include "clock.h"
-#include "console.h"
-#include "hooks.h"
-#include "gpio.h"
-#include "ps2_chip.h"
-#include "task.h"
-#include "registers.h"
-#include "timer.h"
-#include "util.h"
-
-#define CPRINTS(format, args...) cprints(CC_PS2, format, ## args)
-#define CPRINTF(format, args...) cprintf(CC_PS2, format, ## args)
-
-#if !(DEBUG_PS2)
-#define DEBUG_CPRINTS(...)
-#define DEBUG_CPRINTF(...)
-#else
-#define DEBUG_CPRINTS(format, args...) cprints(CC_PS2, format, ## args)
-#define DEBUG_CPRINTF(format, args...) cprintf(CC_PS2, format, ## args)
-#endif
-
-/*
- * Set WDAT3-0 and clear CLK3-0 in the PSOSIG register to
- * reset the shift mechanism.
- */
-#define PS2_SHIFT_MECH_RESET 0x47
-
-#define PS2_TRANSACTION_TIMEOUT (20 * MSEC)
-#define PS2_BUSY_RETRY 10
-
-enum ps2_input_debounce_cycle {
- PS2_IDB_1_CYCLE,
- PS2_IDB_2_CYCLE,
- PS2_IDB_4_CYCLE,
- PS2_IDB_8_CYCLE,
- PS2_IDB_16_CYCLE,
- PS2_IDB_32_CYCLE,
-};
-
-enum ps2_opr_mode {
- PS2_TX_MODE,
- PS2_RX_MODE,
-};
-
-struct ps2_data {
- /* PS/2 module operation mode */
- uint8_t opr_mode;
- /*
- * The callback function to process data received from PS/2 device.
- * Note: this is called in the PS/2 interrupt handler
- */
- void (*rx_handler_cb)(uint8_t data);
-};
-static struct ps2_data ps2_ch_data[NPCX_PS2_CH_COUNT] = {
- [0 ... (NPCX_PS2_CH_COUNT - 1)] = { PS2_RX_MODE, NULL }
-};
-
-/*
- * Bitmap to record the enabled PS/2 channel by upper layer.
- * Only bit[7 and bit[5:3] are used
- * (i.e. the bit position of CLK3-0 in the PS2_PSOSIG register)
- */
-static uint32_t channel_enabled_mask;
-static struct mutex ps2_lock;
-static volatile task_id_t task_waiting = TASK_ID_INVALID;
-
-static void ps2_init(void)
-{
- /* Disable the power down bit of PS/2 */
- clock_enable_peripheral(CGC_OFFSET_PS2, CGC_PS2_MASK,
- CGC_MODE_RUN | CGC_MODE_SLEEP);
-
- /* Disable shift mechanism and configure PS/2 to received mode. */
- NPCX_PS2_PSCON = 0x0;
- /* Set WDAT3-0 and clear CLK3-0 before enabling shift mechanism */
- NPCX_PS2_PSOSIG = PS2_SHIFT_MECH_RESET;
-
- /*
- * PS/2 interrupt enable register
- * [0] - : SOTIE = 1: Start Of Transaction Interrupt Enable
- * [1] - : EOTIE = 1: End Of Transaction Interrupt Enable
- * [4] - : WUE = 1: Wake-Up Enable
- * [7] - : CLK_SEL = 1: Select Free-Run clock as the basic clock
- */
- NPCX_PS2_PSIEN = BIT(NPCX_PS2_PSIEN_SOTIE) |
- BIT(NPCX_PS2_PSIEN_EOTIE) |
- BIT(NPCX_PS2_PSIEN_PS2_WUE) |
- BIT(NPCX_PS2_PSIEN_PS2_CLK_SEL);
-
- /* Enable weak internal pull-up */
- SET_BIT(NPCX_PS2_PSCON, NPCX_PS2_PSCON_WPUED);
- /* Enable shift mechanism */
- SET_BIT(NPCX_PS2_PSCON, NPCX_PS2_PSCON_EN);
-
- /* Configure pins from GPIOs to PS/2 interface */
- gpio_config_module(MODULE_PS2, 1);
- task_enable_irq(NPCX_IRQ_PS2);
-}
-DECLARE_HOOK(HOOK_INIT, ps2_init, HOOK_PRIO_DEFAULT);
-
-void ps2_enable_channel(int channel, int enable,
- void (*callback)(uint8_t data))
-{
- if (channel >= NPCX_PS2_CH_COUNT) {
- CPRINTS("Err:PS/2 CH exceed %d", NPCX_PS2_CH_COUNT);
- return;
- }
-
- /*
- * Disable the interrupt during changing the enabled channel mask to
- * prevent from preemption
- */
- interrupt_disable();
- if (enable) {
- ps2_ch_data[channel].rx_handler_cb = callback;
- channel_enabled_mask |= BIT(NPCX_PS2_PSOSIG_CLK(channel));
- /* Enable the relevant channel clock */
- SET_BIT(NPCX_PS2_PSOSIG, NPCX_PS2_PSOSIG_CLK(channel));
- } else {
- channel_enabled_mask &= ~BIT(NPCX_PS2_PSOSIG_CLK(channel));
- /* Disable the relevant channel clock */
- CLEAR_BIT(NPCX_PS2_PSOSIG, NPCX_PS2_PSOSIG_CLK(channel));
- ps2_ch_data[channel].rx_handler_cb = NULL;
- }
- interrupt_enable();
-}
-
-/* Check if the shift mechanism is busy */
-static int ps2_is_busy(void)
-{
- /*
- * The driver pulls the CLK for non-active channels to low when Start
- * bit is detected and pull the CLK of the active channel low after
- * Stop bit detected. The EOT bit is set when Stop bit is detected,
- * but both SOT and EOT are cleared when all CLKs are pull low
- * (due to Shift Mechanism is reset)
- */
- return (IS_BIT_SET(NPCX_PS2_PSTAT, NPCX_PS2_PSTAT_SOT) |
- IS_BIT_SET(NPCX_PS2_PSTAT, NPCX_PS2_PSTAT_EOT)) ? 1 : 0;
-}
-
-int ps2_transmit_byte(int channel, uint8_t data)
-{
- int event;
-
- uint8_t busy_retry = PS2_BUSY_RETRY;
-
- if (channel >= NPCX_PS2_CH_COUNT) {
- CPRINTS("Err:PS/2 CH exceed %d", NPCX_PS2_CH_COUNT);
- return EC_ERROR_INVAL;
- }
-
- if (!(BIT(NPCX_PS2_PSOSIG_CLK(channel)) & channel_enabled_mask)) {
- CPRINTS("Err: PS/2 Tx w/o enabling CH");
- return EC_ERROR_INVAL;
- }
-
- mutex_lock(&ps2_lock);
- while (ps2_is_busy()) {
- usleep(PS2_TRANSACTION_TIMEOUT);
- if (busy_retry == 0) {
- mutex_unlock(&ps2_lock);
- return EC_ERROR_BUSY;
- }
- busy_retry--;
- }
-
- task_waiting = task_get_current();
- ps2_ch_data[channel].opr_mode = PS2_TX_MODE;
-
- /* Set PS/2 in transmit mode */
- SET_BIT(NPCX_PS2_PSCON, NPCX_PS2_PSCON_XMT);
- /* Enable Start Of Transaction interrupt */
- SET_BIT(NPCX_PS2_PSIEN, NPCX_PS2_PSIEN_SOTIE);
-
- /* Reset the shift mechanism */
- NPCX_PS2_PSOSIG = PS2_SHIFT_MECH_RESET;
- /* Inhibit communication should last at least 100 micro-seconds */
- udelay(100);
-
- /* Write the data to be transmitted */
- NPCX_PS2_PSDAT = data;
- /* Apply the Request-to-send */
- CLEAR_BIT(NPCX_PS2_PSOSIG, NPCX_PS2_PSOSIG_WDAT(channel));
- SET_BIT(NPCX_PS2_PSOSIG, NPCX_PS2_PSOSIG_CLK(channel));
-
- /* Wait for interrupt */
- event = task_wait_event_mask(TASK_EVENT_PS2_DONE,
- PS2_TRANSACTION_TIMEOUT);
- task_waiting = TASK_ID_INVALID;
-
- if (event == TASK_EVENT_TIMER) {
- task_disable_irq(NPCX_IRQ_PS2);
- CPRINTS("PS/2 Tx timeout");
- /* Reset the shift mechanism */
- NPCX_PS2_PSOSIG = PS2_SHIFT_MECH_RESET;
- /* Change the PS/2 module to receive mode */
- CLEAR_BIT(NPCX_PS2_PSCON, NPCX_PS2_PSCON_XMT);
- /* Restore the channel to Receive mode */
- ps2_ch_data[channel].opr_mode = PS2_RX_MODE;
- /*
- * Restore the enabled channel according to channel_enabled_mask
- */
- NPCX_PS2_PSOSIG |= channel_enabled_mask;
- task_enable_irq(NPCX_IRQ_PS2);
- }
- mutex_unlock(&ps2_lock);
-
- DEBUG_CPRINTF("Evt:0x%08x\n", event);
- return (event == TASK_EVENT_PS2_DONE) ? EC_SUCCESS : EC_ERROR_TIMEOUT;
-
-}
-
-static void ps2_stop_inactive_ch_clk(uint8_t active_ch)
-{
- uint8_t mask;
-
- mask = ~NPCX_PS2_PSOSIG_CLK_MASK_ALL |
- BIT(NPCX_PS2_PSOSIG_CLK(active_ch));
- NPCX_PS2_PSOSIG &= mask;
-
-}
-
-static int ps2_is_rx_error(uint8_t ch)
-{
- uint8_t status;
-
- status = NPCX_PS2_PSTAT &
- (BIT(NPCX_PS2_PSTAT_PERR) |
- BIT(NPCX_PS2_PSTAT_RFERR));
- if (status) {
-
- if (status & BIT(NPCX_PS2_PSTAT_PERR))
- CPRINTF("PS2 CH %d RX parity error\n", ch);
- if (status & BIT(NPCX_PS2_PSTAT_RFERR))
- CPRINTF("PS2 CH %d RX Frame error\n", ch);
- return 1;
- } else
- return 0;
-}
-
-void ps2_int_handler(void)
-{
- uint8_t active_ch;
-
- DEBUG_CPRINTS("PS2 INT");
- /*
- * ACH = 1 : CHannel 0
- * ACH = 2 : CHannel 1
- * ACH = 4 : CHannel 2
- * ACH = 5 : CHannel 3
- */
- active_ch = GET_FIELD(NPCX_PS2_PSTAT, NPCX_PS2_PSTAT_ACH);
- active_ch = active_ch > 2 ? (active_ch - 2) : (active_ch - 1);
- DEBUG_CPRINTF("ACH:%0d-", active_ch);
-
- /*
- * Inhibit PS/2 transaction of the other non-active channels by
- * pulling down the clock signal
- */
- ps2_stop_inactive_ch_clk(active_ch);
-
- /* PS/2 Start of Transaction */
- if (IS_BIT_SET(NPCX_PS2_PSTAT, NPCX_PS2_PSTAT_SOT) &&
- IS_BIT_SET(NPCX_PS2_PSIEN, NPCX_PS2_PSIEN_SOTIE)) {
- DEBUG_CPRINTF("SOT-");
- /*
- * Once set, SOT is not cleared until the shift mechanism
- * is reset. Therefore, SOTIE should be cleared on the
- * first occurrence of an SOT interrupt.
- */
- CLEAR_BIT(NPCX_PS2_PSIEN, NPCX_PS2_PSIEN_SOTIE);
- /* PS/2 End of Transaction */
- } else if (IS_BIT_SET(NPCX_PS2_PSTAT, NPCX_PS2_PSTAT_EOT)) {
- DEBUG_CPRINTF("EOT-");
- CLEAR_BIT(NPCX_PS2_PSIEN, NPCX_PS2_PSIEN_EOTIE);
-
- /*
- * Clear the CLK of active channel to reset
- * the shift mechanism
- */
- CLEAR_BIT(NPCX_PS2_PSOSIG, NPCX_PS2_PSOSIG_CLK(active_ch));
-
- if (ps2_ch_data[active_ch].opr_mode == PS2_TX_MODE) {
- /* Change the PS/2 module to receive mode */
- CLEAR_BIT(NPCX_PS2_PSCON, NPCX_PS2_PSCON_XMT);
- ps2_ch_data[active_ch].opr_mode = PS2_RX_MODE;
- task_set_event(task_waiting, TASK_EVENT_PS2_DONE);
- } else {
- if (!ps2_is_rx_error(active_ch)) {
- uint8_t data_read = NPCX_PS2_PSDAT;
- struct ps2_data *ps2_ptr =
- &ps2_ch_data[active_ch];
-
- DEBUG_CPRINTF("Recv:0x%02x", data_read);
- if (ps2_ptr->rx_handler_cb)
- ps2_ptr->rx_handler_cb(data_read);
- }
- }
-
- /* Restore the enabled channel */
- NPCX_PS2_PSOSIG |= channel_enabled_mask;
- /*
- * Re-enable the Start Of Transaction interrupt when
- * the shift mechanism is reset
- */
- SET_BIT(NPCX_PS2_PSIEN, NPCX_PS2_PSIEN_SOTIE);
- SET_BIT(NPCX_PS2_PSIEN, NPCX_PS2_PSIEN_EOTIE);
- }
- DEBUG_CPRINTF("\n");
-
-}
-DECLARE_IRQ(NPCX_IRQ_PS2, ps2_int_handler, 5);
-
-#ifdef CONFIG_CMD_PS2
-static int command_ps2ench(int argc, char **argv)
-{
- uint8_t ch;
- uint8_t enable;
- char *e;
-
- ch = strtoi(argv[1], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
-
- enable = strtoi(argv[2], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
- if (enable)
- ps2_enable_channel(ch, 1, NULL);
- else
- ps2_enable_channel(ch, 0, NULL);
-
- return 0;
-}
-DECLARE_CONSOLE_COMMAND(ps2ench, command_ps2ench,
- "ps2_ench channel 1|0",
- "Enable/Disable PS/2 channel");
-
-static int command_ps2write(int argc, char **argv)
-{
- uint8_t ch, data;
- char *e;
-
- ch = strtoi(argv[1], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
- data = strtoi(argv[2], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
-
- ps2_transmit_byte(ch, data);
- return 0;
-}
-DECLARE_CONSOLE_COMMAND(ps2write, command_ps2write,
- "ps2_write channel data",
- "Write data byte to PS/2 channel ");
-#endif