Keyborg: implement methods needed for touch wake

In order to wake the chips from STOP/SLEEP mode with a touch, we need to
put the two chips in correct state before going into STOP/SLEEP mode.
Also, when one of the chips wakes up, it needs to wake the other chip
with GPIO interrupt.

This CL implements the necessary methods and also adds a sample routine
that put the chips in STOP mode and wait for a touch using the
implemented methods.

BUG=None
TEST=Build and boot. Touch the panel and see the response in console.
BRANCH=None

Change-Id: Ia5f7df8b550ee2459bcae1840f8a2717c8d947ce
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/204482
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Vic Yang
2014-06-18 11:14:25 -07:00
committed by chrome-internal-fetch
parent 6c8e451ff0
commit 94acd01e0c
8 changed files with 154 additions and 3 deletions

View File

@@ -5,6 +5,7 @@
/* Keyborg board-specific configuration */
#include "common.h"
#include "cpu.h"
#include "debug.h"
#include "master_slave.h"
#include "registers.h"
@@ -130,6 +131,27 @@ static const char *get_version(void)
return version_data.version;
}
static void low_power(void)
{
touch_scan_enable_interrupt();
master_slave_enable_interrupt();
CPU_SCB_SYSCTRL |= 0x4;
asm volatile("wfi");
CPU_SCB_SYSCTRL &= ~0x4;
hardware_clock_init();
touch_scan_disable_interrupt();
master_slave_disable_interrupt();
master_slave_wake_other();
/* Wait for the other chip to wake */
udelay(2 * MSEC);
master_slave_sync(5);
}
int main(void)
{
int i = 0;
@@ -151,6 +173,10 @@ int main(void)
master_slave_sync(100);
debug_printf("Touch to start...");
low_power();
debug_printf("\n");
while (1) {
i++;
task_wait_event(SECOND);

View File

@@ -41,6 +41,9 @@ enum gpio_signal;
/* Initialize all useful registers */
void hardware_init(void);
/* Re-initialize clock */
void hardware_clock_init(void);
/* On the master, reboot both chips. On the slave, reboot itself. */
void system_reboot(void);

View File

@@ -9,4 +9,7 @@
*/
ENABLE_IRQ(STM32_IRQ_EXTI0)
ENABLE_IRQ(STM32_IRQ_EXTI1)
ENABLE_IRQ(STM32_IRQ_EXTI2)
ENABLE_IRQ(STM32_IRQ_EXTI3)
ENABLE_IRQ(STM32_IRQ_TIM2)

View File

@@ -12,7 +12,7 @@
#include "touch_scan.h"
#include "util.h"
static void clock_init(void)
void hardware_clock_init(void)
{
/* Turn on HSE */
if (!(STM32_RCC_CR & (1 << 17))) {
@@ -183,7 +183,7 @@ static void pmse_init(void)
void hardware_init(void)
{
power_init();
clock_init();
hardware_clock_init();
pins_init();
timers_init();
adc_init();

View File

@@ -8,6 +8,7 @@
#include "debug.h"
#include "master_slave.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
@@ -55,6 +56,55 @@ int master_slave_sync_impl(const char *filename, int line, int timeout_ms)
return err;
}
void master_slave_enable_interrupt(void)
{
if (is_master) {
/* Interrupt on EXTI2 on port I */
STM32_EXTI_RTSR |= 1 << 2;
STM32_AFIO_EXTICR(0) = (STM32_AFIO_EXTICR(0) & ~0xf00) |
(8 << 8);
STM32_EXTI_IMR |= 1 << 2;
task_clear_pending_irq(STM32_IRQ_EXTI2);
task_enable_irq(STM32_IRQ_EXTI2);
} else {
/* Interrupt on EXTI1 on port I */
STM32_EXTI_RTSR |= 1 << 1;
STM32_AFIO_EXTICR(0) = (STM32_AFIO_EXTICR(0) & ~0xf0) |
(8 << 4);
STM32_EXTI_IMR |= 1 << 1;
task_clear_pending_irq(STM32_IRQ_EXTI1);
task_enable_irq(STM32_IRQ_EXTI1);
}
}
void master_slave_disable_interrupt(void)
{
if (is_master)
task_disable_irq(STM32_IRQ_EXTI2);
else
task_disable_irq(STM32_IRQ_EXTI1);
}
void master_slave_wake_other(void)
{
if (is_master) {
STM32_GPIO_BSRR(GPIO_I) = SYNC1 << 0;
udelay(MSEC);
STM32_GPIO_BSRR(GPIO_I) = SYNC1 << 16;
} else {
STM32_GPIO_BSRR(GPIO_I) = SYNC2 << 0;
udelay(MSEC);
STM32_GPIO_BSRR(GPIO_I) = SYNC2 << 16;
}
}
void master_slave_interrupt(void)
{
STM32_EXTI_PR = STM32_EXTI_PR;
}
DECLARE_IRQ(STM32_IRQ_EXTI1, master_slave_interrupt, 1);
DECLARE_IRQ(STM32_IRQ_EXTI2, master_slave_interrupt, 1);
static int master_handshake(void)
{
uint32_t val;

View File

@@ -28,6 +28,17 @@ int master_slave_is_master(void);
master_slave_sync_impl(__FILE__, __LINE__, timeout_ms)
int master_slave_sync_impl(const char *filename, int line, int timeout_ms);
/**
* Enable/disable master-slave interrupt. Master-slave interrupt is
* implemented using SYNC1/SYNC2 signal, so this is assuming the master
* and the slave are in sync waiting for interrupt.
*/
void master_slave_enable_interrupt(void);
void master_slave_disable_interrupt(void);
/* Interrupt the other chip with a 1-ms pulse. */
void master_slave_wake_other(void);
/**
* Identify this chip and shake hands with the other chip.
*

View File

@@ -7,6 +7,7 @@
#include "common.h"
#include "console.h"
#include "cpu.h"
#include "debug.h"
#include "dma.h"
#include "encode.h"
@@ -15,6 +16,7 @@
#include "master_slave.h"
#include "registers.h"
#include "spi_comm.h"
#include "task.h"
#include "timer.h"
#include "touch_scan.h"
#include "util.h"
@@ -61,6 +63,8 @@ static void set_gpio(const struct ts_pin pin, enum pin_type type)
} else if (type == PIN_PD) {
mask |= 0x88888888 & mode;
STM32_GPIO_BSRR(port) = pmask << 16;
} else if (type == PIN_Z) {
mask |= 0x44444444 & mode;
} else if (type == PIN_ROW) {
/* Nothing for PIN_ROW. Already analog input. */
}
@@ -73,7 +77,7 @@ void touch_scan_init(void)
int i;
for (i = 0; i < ROW_COUNT; ++i) {
set_gpio(col_pins[i], PIN_ROW);
set_gpio(row_pins[i], PIN_ROW);
STM32_PMSE_PxPMR(row_pins[i].port_id) |= 1 << row_pins[i].pin;
}
for (i = 0; i < COL_COUNT; ++i)
@@ -85,6 +89,47 @@ void touch_scan_init(void)
mccr_list[i] = TS_PIN_TO_CR(col_pins[i]);
}
void touch_scan_enable_interrupt(void)
{
int i;
/* Set ALLROW and ALLCOL */
for (i = 0; i < ROW_COUNT; ++i)
set_gpio(row_pins[i], PIN_Z);
for (i = 0; i < COL_COUNT; ++i) {
set_gpio(col_pins[i], PIN_COL);
STM32_PMSE_PxPMR(col_pins[i].port_id) |= 1 << col_pins[i].pin;
}
STM32_PMSE_MCCR = (1 << 31) | (0 << 20);
STM32_PMSE_MRCR = 1 << 31;
/* Enable external interrupt. EXTI3 on port E. Rising edge */
STM32_EXTI_RTSR |= 1 << 3;
STM32_AFIO_EXTICR(0) = (STM32_AFIO_EXTICR(0) & ~0xf000) | (4 << 12);
STM32_EXTI_IMR |= 1 << 3;
task_clear_pending_irq(STM32_IRQ_EXTI3);
task_enable_irq(STM32_IRQ_EXTI3);
}
void touch_scan_disable_interrupt(void)
{
int i;
for (i = 0; i < ROW_COUNT; ++i)
set_gpio(row_pins[i], PIN_ROW);
for (i = 0; i < COL_COUNT; ++i) {
set_gpio(col_pins[i], PIN_PD);
STM32_PMSE_PxPMR(col_pins[i].port_id) &=
~(1 << col_pins[i].pin);
}
}
void touch_scan_interrupt(void)
{
STM32_EXTI_PR = STM32_EXTI_PR;
}
DECLARE_IRQ(STM32_IRQ_EXTI3, touch_scan_interrupt, 1);
static void discharge(void)
{
int i;

View File

@@ -12,6 +12,7 @@ enum pin_type {
PIN_ROW,
PIN_COL,
PIN_PD,
PIN_Z,
};
/* 8-bit window */
@@ -55,10 +56,22 @@ extern const struct ts_pin col_pins[];
#define ROW_COUNT 41
#define COL_COUNT 60
/* Initialize touch scan module */
void touch_scan_init(void);
/* Start scanning on the slave. This is called by SPI command handler. */
void touch_scan_slave_start(void);
/**
* Initiate full matrix scan on the master. This also sends SPI command
* to the slave.
*/
int touch_scan_full_matrix(void);
/* Configure touch scan module to interrupt on touch. */
void touch_scan_enable_interrupt(void);
/* Disable touch scan interrupt. */
void touch_scan_disable_interrupt(void);
#endif /* __BOARD_KEYBORG_TOUCH_SCAN_H */