chrome-ec/board/glados_pd/board.c

170 lines
4.4 KiB
C

/* Copyright 2015 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.
*/
/* glados_pd board configuration */
#include "adc.h"
#include "adc_chip.h"
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "i2c.h"
#include "registers.h"
#include "switch.h"
#include "system.h"
#include "task.h"
#include "usb_pd.h"
#include "usb_pd_tcpc.h"
#include "util.h"
#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
/* Indicate which source is driving the ec_int line. */
static uint32_t ec_int_status;
static uint32_t pd_status_flags;
void pd_send_ec_int(void)
{
/* If any sources are active, then drive the line low */
gpio_set_level(GPIO_EC_INT, !ec_int_status);
}
void board_config_pre_init(void)
{
/* enable SYSCFG clock */
STM32_RCC_APB2ENR |= BIT(0);
/*
* the DMA mapping is :
* Chan 2 : TIM1_CH1 (C0 RX)
* Chan 3 : SPI1_TX (C0 TX)
* Chan 4 : TIM3_CH1 (C1 RX)
* Chan 5 : SPI2_TX (C1 TX)
*/
}
#include "gpio_list.h"
__override uint8_t board_get_usb_pd_port_count(void)
{
return CONFIG_USB_PD_PORT_MAX_COUNT;
}
void pd_set_suspend(int port, int suspend)
{
/*
* Do nothing. This is only here to make the linker happy for this
* old board on ToT.
*/
}
/* Initialize board. */
static void board_init(void)
{
/* Enable interrupts on VBUS transitions. */
gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE_L);
gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE_L);
/* Set PD MCU system status bits */
if (system_jumped_late())
pd_status_flags |= PD_STATUS_JUMPED_TO_IMAGE;
if (system_is_in_rw())
pd_status_flags |= PD_STATUS_IN_RW;
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
/* ADC channels */
const struct adc_t adc_channels[] = {
/* USB PD CC lines sensing. Converted to mV (3300mV/4096). */
[ADC_C1_CC1_PD] = {"C1_CC1_PD", 3300, 4096, 0, STM32_AIN(0)},
[ADC_C0_CC1_PD] = {"C0_CC1_PD", 3300, 4096, 0, STM32_AIN(2)},
[ADC_C0_CC2_PD] = {"C0_CC2_PD", 3300, 4096, 0, STM32_AIN(4)},
[ADC_C1_CC2_PD] = {"C1_CC2_PD", 3300, 4096, 0, STM32_AIN(5)},
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
{"slave", I2C_PORT_SLAVE, 1000, GPIO_SLAVE_I2C_SCL, GPIO_SLAVE_I2C_SDA}
};
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
void tcpc_alert(int port)
{
/*
* This function is called when the TCPC sets one of
* bits in the Alert register and that bit's corresponding
* location in the Alert_Mask register is set.
*/
atomic_or(&ec_int_status, port ?
PD_STATUS_TCPC_ALERT_1 : PD_STATUS_TCPC_ALERT_0);
pd_send_ec_int();
}
void tcpc_alert_clear(int port)
{
/*
* The TCPM has acknowledged all Alert bits and the
* Alert# line needs to be set inactive. Clear
* the corresponding port's bit in the static variable.
*/
atomic_clear(&ec_int_status, port ?
PD_STATUS_TCPC_ALERT_1 : PD_STATUS_TCPC_ALERT_0);
pd_send_ec_int();
}
static void system_hibernate_deferred(void)
{
ccprintf("EC requested hibernate\n");
cflush();
system_hibernate(0, 0);
}
DECLARE_DEFERRED(system_hibernate_deferred);
/****************************************************************************/
/* Console commands */
static int command_ec_int(int argc, char **argv)
{
/* Indicate that ec_int gpio is active due to host command */
atomic_or(&ec_int_status, PD_STATUS_HOST_EVENT);
pd_send_ec_int();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(ecint, command_ec_int,
"",
"Toggle EC interrupt line");
static enum ec_status ec_status_host_cmd(struct host_cmd_handler_args *args)
{
const struct ec_params_pd_status *p = args->params;
struct ec_response_pd_status *r = args->response;
/*
* ec_int_status is used to store state for HOST_EVENT,
* TCPC 0 Alert, and TCPC 1 Alert bits.
*/
r->status = ec_int_status | pd_status_flags;
args->response_size = sizeof(*r);
/* Have the PD follow the EC into hibernate. */
if (p->status & EC_STATUS_HIBERNATING)
hook_call_deferred(&system_hibernate_deferred_data, 0);
/*
* If the source of the EC int line was HOST_EVENT, it has
* been acknowledged so can always clear HOST_EVENT bit
* from the ec_int_status variable
*/
atomic_clear(&ec_int_status, PD_STATUS_HOST_EVENT);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd,
EC_VER_MASK(EC_VER_PD_EXCHANGE_STATUS));