Files
OpenCellular/board/oak/board.c
Rong Chang c2ebc9e477 oak: use EXTRA_CLFAGS instead of CONFIG_BOARD_OAK_REV
Oak board revisions are not global configs. Move them out of
include/config.h . This change also makes it easier to build EC
and PD image for different board revisions.

BRANCH=none
BUG=none
TEST=manual
  build for board revision n and load on oak:
    make BOARD=oak clean
    make BOARD=oak_pd claen
    make EXTRA_CFLAGS=-DBOARD_REV=n BOARD=oak -j
    make EXTRA_CFLAGS=-DBOARD_REV=n BOARD=oak_pd -j

Change-Id: I331b4c5a1af94b179d7c6f7878a9c3939ea6025a
Signed-off-by: Rong Chang <rongchang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/294441
Reviewed-by: Shawn N <shawnn@chromium.org>
2015-08-21 08:10:23 +00:00

348 lines
8.8 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.
*/
/* Oak board configuration */
#include "adc_chip.h"
#include "battery.h"
#include "charge_manager.h"
#include "charge_state.h"
#include "charger.h"
#include "chipset.h"
#include "common.h"
#include "console.h"
#include "driver/temp_sensor/tmp432.h"
#include "extpower.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "i2c.h"
#include "keyboard_raw.h"
#include "lid_switch.h"
#include "pi3usb9281.h"
#include "power.h"
#include "power_button.h"
#include "registers.h"
#include "spi.h"
#include "switch.h"
#include "system.h"
#include "task.h"
#include "temp_sensor.h"
#include "temp_sensor_chip.h"
#include "thermal.h"
#include "timer.h"
#include "usb_charge.h"
#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
#include "util.h"
#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
#define GPIO_KB_INPUT (GPIO_INPUT | GPIO_PULL_UP | GPIO_INT_BOTH)
#define GPIO_KB_OUTPUT GPIO_ODR_HIGH
/* Dispaly port hardware can connect to port 0, 1 or neither. */
#define PD_PORT_NONE -1
void pd_mcu_interrupt(enum gpio_signal signal)
{
#ifdef HAS_TASK_PDCMD
/* Exchange status with PD MCU to determin interrupt cause */
host_command_pd_send_status(0);
#endif
}
#include "gpio_list.h"
/* power signal list. Must match order of enum power_signal. */
const struct power_signal_info power_signal_list[] = {
{GPIO_SOC_POWER_GOOD, 1, "POWER_GOOD"}, /* Active high */
{GPIO_SUSPEND_L, 0, "SUSPEND#_ASSERTED"}, /* Active low */
};
BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
/* ADC channels */
const struct adc_t adc_channels[] = {
/* VDC_BOOSTIN_SENSE(PC1): ADC_IN11, output in mV */
[ADC_VBUS] = {"VBUS", 33000, 4096, 0, STM32_AIN(11)},
/*
* PSYS_MONITOR(PA2): ADC_IN2, 1.44 uA/W on 6.05k Ohm
* output in mW
*/
[ADC_PSYS] = {"PSYS", 379415, 4096, 0, STM32_AIN(2)},
/* AMON_BMON(PC0): ADC_IN10, output in uV */
[ADC_AMON_BMON] = {"AMON_BMON", 183333, 4096, 0, STM32_AIN(10)},
};
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* I2C ports */
const struct i2c_port_t i2c_ports[] = {
{"battery", I2C_PORT_BATTERY, 100, GPIO_I2C0_SCL, GPIO_I2C0_SDA},
{"pd", I2C_PORT_PD_MCU, 1000, GPIO_I2C1_SCL, GPIO_I2C1_SDA}
};
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
struct mutex pericom_mux_lock;
struct pi3usb9281_config pi3usb9281_chips[] = {
{
.i2c_port = I2C_PORT_PERICOM,
.mux_gpio = GPIO_USB_C_BC12_SEL,
.mux_gpio_level = 0,
.mux_lock = &pericom_mux_lock,
},
{
.i2c_port = I2C_PORT_PERICOM,
.mux_gpio = GPIO_USB_C_BC12_SEL,
.mux_gpio_level = 1,
.mux_lock = &pericom_mux_lock,
},
};
BUILD_ASSERT(ARRAY_SIZE(pi3usb9281_chips) ==
CONFIG_USB_SWITCH_PI3USB9281_CHIP_COUNT);
/*
* Temperature sensors data; must be in same order as enum temp_sensor_id.
* Sensor index and name must match those present in coreboot:
* src/mainboard/google/${board}/acpi/dptf.asl
*/
const struct temp_sensor_t temp_sensors[] = {
{"TMP432_Internal", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val,
TMP432_IDX_LOCAL, 4},
{"TMP432_Sensor_1", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val,
TMP432_IDX_REMOTE1, 4},
{"TMP432_Sensor_2", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val,
TMP432_IDX_REMOTE2, 4},
{"Battery", TEMP_SENSOR_TYPE_BATTERY, charge_temp_sensor_get_val,
0, 4},
};
BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
/* Thermal limits for each temp sensor. All temps are in degrees K. Must be in
* same order as enum temp_sensor_id. To always ignore any temp, use 0.
*/
struct ec_thermal_config thermal_params[] = {
{{0, 0, 0}, 0, 0}, /* TMP432_Internal */
{{0, 0, 0}, 0, 0}, /* TMP432_Sensor_1 */
{{0, 0, 0}, 0, 0}, /* TMP432_Sensor_2 */
{{0, 0, 0}, 0, 0}, /* Battery Sensor */
};
BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
{
.port_addr = 0x54 << 1,
.driver = &pi3usb30532_usb_mux_driver,
},
{
.port_addr = 0x55 << 1,
.driver = &pi3usb30532_usb_mux_driver,
},
};
/**
* Store the current DP hardware route.
*/
static int dp_hw_port = PD_PORT_NONE;
static struct mutex dp_hw_lock;
/**
* Reset PD MCU
*/
void board_reset_pd_mcu(void)
{
gpio_set_level(GPIO_USB_PD_RST_L, 0);
usleep(100);
gpio_set_level(GPIO_USB_PD_RST_L, 1);
}
void __board_i2c_set_timeout(int port, uint32_t timeout)
{
}
void i2c_set_timeout(int port, uint32_t timeout)
__attribute__((weak, alias("__board_i2c_set_timeout")));
/* Initialize board. */
static void board_init(void)
{
/* Enable rev1 testing GPIOs */
gpio_set_level(GPIO_SYSTEM_POWER_H, 1);
/* Enable PD MCU interrupt */
gpio_enable_interrupt(GPIO_PD_MCU_INT);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
/**
* Set active charge port -- only one port can active at a time.
*
* @param charge_port Charge port to enable.
*
* Return EC_SUCCESS if charge port is accepted and made active.
* EC_ERROR_* otherwise.
*/
int board_set_active_charge_port(int charge_port)
{
/* charge port is a physical port */
int is_real_port = (charge_port >= 0 &&
charge_port < CONFIG_USB_PD_PORT_COUNT);
/* check if we are source VBUS on the port */
int source = gpio_get_level(charge_port == 0 ? GPIO_USB_C0_5V_EN :
GPIO_USB_C1_5V_EN);
if (is_real_port && source) {
CPRINTF("Skip enable p%d", charge_port);
return EC_ERROR_INVAL;
}
CPRINTF("New chg p%d", charge_port);
if (charge_port == CHARGE_PORT_NONE) {
/*
* TODO: currently we only get VBUS knowledge when charge
* is enabled. so, when not changing, we need to enable
* both ports. but, this is dangerous if you have two
* chargers plugged in and you set charge override to -1
* then it will enable both sides!
*/
gpio_set_level(GPIO_USB_C0_CHARGE_L, 0);
gpio_set_level(GPIO_USB_C1_CHARGE_L, 0);
} else {
/* Make sure non-charging port is disabled */
gpio_set_level(charge_port ? GPIO_USB_C0_CHARGE_L :
GPIO_USB_C1_CHARGE_L, 1);
/* Enable charging port */
gpio_set_level(charge_port ? GPIO_USB_C1_CHARGE_L :
GPIO_USB_C0_CHARGE_L, 0);
}
return EC_SUCCESS;
}
/**
* Set the charge limit based upon desired maximum.
*
* @param charge_ma Desired charge limit (mA).
*/
void board_set_charge_limit(int charge_ma)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT));
}
static void hpd_irq_deferred(void)
{
gpio_set_level(GPIO_USB_DP_HPD, 1);
}
DECLARE_DEFERRED(hpd_irq_deferred);
/**
* Turn on DP hardware on type-C port.
*/
void board_typec_dp_on(int port)
{
mutex_lock(&dp_hw_lock);
if (dp_hw_port != !port) {
/* Get control of DP hardware */
dp_hw_port = port;
#if BOARD_REV == OAK_REV2
gpio_set_level(GPIO_DP_SWITCH_CTL, port);
#endif
if (!gpio_get_level(GPIO_USB_DP_HPD)) {
gpio_set_level(GPIO_USB_DP_HPD, 1);
} else {
gpio_set_level(GPIO_USB_DP_HPD, 0);
hook_call_deferred(hpd_irq_deferred,
HPD_DSTREAM_DEBOUNCE_IRQ);
}
}
mutex_unlock(&dp_hw_lock);
}
/**
* Turn off a PD port's DP output.
*/
void board_typec_dp_off(int port, int *dp_flags)
{
mutex_lock(&dp_hw_lock);
if (dp_hw_port == !port) {
mutex_unlock(&dp_hw_lock);
return;
}
dp_hw_port = PD_PORT_NONE;
gpio_set_level(GPIO_USB_DP_HPD, 0);
mutex_unlock(&dp_hw_lock);
/* Enable the other port if its dp flag is on */
if (dp_flags[!port] & DP_FLAGS_DP_ON)
board_typec_dp_on(!port);
}
/**
* Set DP hotplug detect level.
*/
void board_typec_dp_set(int port, int level)
{
mutex_lock(&dp_hw_lock);
if (dp_hw_port == PD_PORT_NONE) {
dp_hw_port = port;
#if BOARD_REV == OAK_REV2
gpio_set_level(GPIO_DP_SWITCH_CTL, port);
#endif
}
if (dp_hw_port == port)
gpio_set_level(GPIO_USB_DP_HPD, level);
mutex_unlock(&dp_hw_lock);
}
#ifndef CONFIG_AP_WARM_RESET_INTERRUPT
/* Using this hook if system doesn't have enough external line. */
static void check_ap_reset_second(void)
{
/* Check the warm reset signal from servo board */
static int warm_reset, last;
warm_reset = !gpio_get_level(GPIO_AP_RESET_L);
if (last == warm_reset)
return;
if (warm_reset)
chipset_reset(0); /* Warm reset AP */
last = warm_reset;
}
DECLARE_HOOK(HOOK_SECOND, check_ap_reset_second, HOOK_PRIO_DEFAULT);
#endif
/**
* Set AP reset.
*
* PMIC_WARM_RESET_H (PB3) is connected to PMIC RESET before rev < 3.
* AP_RESET_L (PC3, CPU_WARM_RESET_L) is connected to PMIC SYSRSTB
* after rev >= 3.
*/
void board_set_ap_reset(int asserted)
{
if (system_get_board_version() < 3) {
/* Signal is active-high */
CPRINTS("pmic warm reset(%d)", asserted);
gpio_set_level(GPIO_PMIC_WARM_RESET_H, asserted);
} else {
/* Signal is active-low */
CPRINTS("ap warm reset(%d)", asserted);
gpio_set_level(GPIO_AP_RESET_L, !asserted);
}
}