summaryrefslogtreecommitdiff
path: root/chip/npcx/keyboard_raw.c
blob: e6599a35e2bdc5471b8aad4b7d615819167874c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* Copyright (c) 2014 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.
 */

/* Functions needed by keyboard scanner module for Chrome EC */

#include "common.h"
#include "keyboard_raw.h"
#include "keyboard_scan.h"
#include "clock.h"
#include "registers.h"
#include "task.h"

/**
 * Initialize the raw keyboard interface.
 */
void keyboard_raw_init(void)
{
	/* Enable clock for KBS peripheral */
	clock_enable_peripheral(CGC_OFFSET_KBS, CGC_KBS_MASK,
			CGC_MODE_RUN | CGC_MODE_SLEEP);

	/* Ensure top-level interrupt is disabled */
	keyboard_raw_enable_interrupt(0);

	/* pull-up KBSIN 0-7 internally */
	NPCX_KBSINPU = 0xFF;

	/* Disable automatic scan mode */
	CLEAR_BIT(NPCX_KBSCTL, NPCX_KBSMODE);

	/* Disable automatic interrupt enable */
	CLEAR_BIT(NPCX_KBSCTL, NPCX_KBSIEN);

	/* Disable increment enable */
	CLEAR_BIT(NPCX_KBSCTL, NPCX_KBSINC);

	/* Set KBSOUT to zero to detect key-press */
	NPCX_KBSOUT0 = 0x00;
	NPCX_KBSOUT1 = 0x00;

	/*
	 * Enable interrupts for the inputs.  The top-level interrupt is still
	 * masked off, so this won't trigger interrupts yet.
	 */

	/* Clear pending input sources used by scanner */
	NPCX_WKPCL(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) = 0xFF;

	/* Enable Wake-up Button */
	NPCX_WKEN(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) = 0xFF;

	/* Select high to low transition (falling edge) */
	NPCX_WKEDG(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) =  0xFF;

	/* Enable interrupt of WK KBS */
	keyboard_raw_enable_interrupt(1);
}

/**
 * Finish initialization after task scheduling has started.
 */
void keyboard_raw_task_start(void)
{
	/* Enable MIWU to trigger KBS interrupt */
	task_enable_irq(NPCX_IRQ_KSI_WKINTC_1);
}

/**
 * Drive the specified column low.
 */
test_mockable void keyboard_raw_drive_column(int col)
{
	/*
	 * Nuvoton Keyboard Scan IP supports 18x8 Matrix
	 * It also support automatic scan functionality
	 */
	uint32_t mask;

	/* Drive all lines to high */
	if (col == KEYBOARD_COLUMN_NONE)
		mask = KB_COL_MASK;
	/* Set KBSOUT to zero to detect key-press */
	else if (col == KEYBOARD_COLUMN_ALL)
		mask = 0;
	/* Drive one line for detection */
	else
		mask = ((~(1 << col)) & KB_COL_MASK);

	/* Set KBSOUT */
	NPCX_KBSOUT0 = (mask & 0xFFFF);
	NPCX_KBSOUT1 = ((mask >> 16) & 0x03);
}

/**
 * Read raw row state.
 * Bits are 1 if signal is present, 0 if not present.
 */
test_mockable int keyboard_raw_read_rows(void)
{
	/* Bits are active-low, so invert returned levels */
	return (~NPCX_KBSIN) & KB_ROW_MASK;
}

/**
 * Enable or disable keyboard interrupts.
 */
void keyboard_raw_enable_interrupt(int enable)
{
	if (enable)
		task_enable_irq(NPCX_IRQ_KSI_WKINTC_1);
	else
		task_disable_irq(NPCX_IRQ_KSI_WKINTC_1);
}

/*
 * Interrupt handler for the entire GPIO bank of keyboard rows.
 */
void keyboard_raw_interrupt(void)
{
	/* Clear pending input sources used by scanner */
	NPCX_WKPCL(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) = 0xFF;

	/* Wake the scan task */
	task_wake(TASK_ID_KEYSCAN);
}
DECLARE_IRQ(NPCX_IRQ_KSI_WKINTC_1, keyboard_raw_interrupt, 3);