mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 16:41:55 +00:00
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>
193 lines
4.2 KiB
C
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;
|
|
}
|
|
|