Files
OpenCellular/board/keyborg/master_slave.c
Vic Yang 94acd01e0c 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>
2014-06-19 03:25:12 +00:00

193 lines
4.2 KiB
C

/* 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.
*/
/* Master/slave identification */
#include "config.h"
#include "debug.h"
#include "master_slave.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#define SYNC1 (1 << 1) /* PI1 */
#define SYNC2 (1 << 2) /* PI2 */
static int is_master = -1;
int master_slave_is_master(void)
{
return is_master;
}
static int wait_sync_signal(int mask, int v, int timeout_ms)
{
uint32_t start = get_time().le.lo;
while ((!!(STM32_GPIO_IDR(GPIO_I) & mask)) != v) {
if ((get_time().le.lo - start) >= timeout_ms * MSEC)
return EC_ERROR_TIMEOUT;
}
return EC_SUCCESS;
}
int master_slave_sync_impl(const char *filename, int line, int timeout_ms)
{
int err = EC_SUCCESS;
if (is_master) {
STM32_GPIO_BSRR(GPIO_I) = SYNC1 << 0;
if (wait_sync_signal(SYNC2, 1, timeout_ms))
err = EC_ERROR_TIMEOUT;
STM32_GPIO_BSRR(GPIO_I) = SYNC1 << 16;
if (wait_sync_signal(SYNC2, 0, 5))
err = EC_ERROR_TIMEOUT;
} else {
if (wait_sync_signal(SYNC1, 1, timeout_ms))
err = EC_ERROR_TIMEOUT;
STM32_GPIO_BSRR(GPIO_I) = SYNC2 << 0;
if (wait_sync_signal(SYNC1, 0, 5))
err = EC_ERROR_TIMEOUT;
STM32_GPIO_BSRR(GPIO_I) = SYNC2 << 16;
}
if (err != EC_SUCCESS)
debug_printf("Sync failed at %s:%d\n", filename, line);
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;
int err;
/* SYNC2 is the sync signal from the slave. Set it to input. */
val = STM32_GPIO_CRL(GPIO_I);
val &= ~0x00000f00;
val |= 0x00000400;
STM32_GPIO_CRL(GPIO_I) = val;
err = master_slave_sync(1000);
err |= master_slave_sync(20);
err |= master_slave_sync(20);
return err;
}
static int slave_handshake(void)
{
uint32_t val;
int err;
/*
* N_CHG is used to drive SPI_NSS on the master. Set it to
* output low.
*/
val = STM32_GPIO_CRL(GPIO_A);
val &= ~0x000000f0;
val |= 0x00000010;
STM32_GPIO_CRL(GPIO_A) = val;
STM32_GPIO_BSRR(GPIO_A) = 1 << (1 + 16);
/* SYNC1 is the sync signal from the master. Set it to input. */
val = STM32_GPIO_CRL(GPIO_I);
val &= ~0x000000f0;
val |= 0x00000040;
STM32_GPIO_CRL(GPIO_I) = val;
err = master_slave_sync(1000);
err |= master_slave_sync(20);
err |= master_slave_sync(20);
return err;
}
static void master_slave_check(void)
{
/*
* Master slave identity check:
* - Master has USB_PU connected to N_CHG through 1.5K
* resistor. USB_PU is initially low, so N_CHG is low.
* - Slave has N_CHG connected to master NSS with a 20K
* pull-up. Master NSS is initially Hi-Z, so N_CHG is
* high.
*/
if (STM32_GPIO_IDR(GPIO_A) & (1 << 1) /* N_CHG */) {
debug_printf("I'm slave\n");
is_master = 0;
} else {
debug_printf("I'm master\n");
is_master = 1;
}
}
int master_slave_init(void)
{
int handshake_err;
master_slave_check();
if (is_master)
handshake_err = master_handshake();
else
handshake_err = slave_handshake();
if (handshake_err != EC_SUCCESS)
debug_printf("handshake error\n");
else
debug_printf("handshake done\n");
return handshake_err;
}