diff options
l--------- | board/gandof/Makefile | 1 | ||||
-rw-r--r-- | board/gandof/battery.c | 63 | ||||
-rw-r--r-- | board/gandof/board.c | 207 | ||||
-rw-r--r-- | board/gandof/board.h | 128 | ||||
-rw-r--r-- | board/gandof/build.mk | 12 | ||||
-rw-r--r-- | board/gandof/ec.tasklist | 27 | ||||
-rw-r--r-- | board/gandof/gpio.inc | 102 | ||||
-rw-r--r-- | board/gandof/led.c | 216 | ||||
-rwxr-xr-x | util/flash_ec | 1 |
9 files changed, 757 insertions, 0 deletions
diff --git a/board/gandof/Makefile b/board/gandof/Makefile new file mode 120000 index 0000000000..94aaae2c4d --- /dev/null +++ b/board/gandof/Makefile @@ -0,0 +1 @@ +../../Makefile
\ No newline at end of file diff --git a/board/gandof/battery.c b/board/gandof/battery.c new file mode 100644 index 0000000000..bcb8ed036f --- /dev/null +++ b/board/gandof/battery.c @@ -0,0 +1,63 @@ +/* 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. + * + * Battery pack vendor provided charging profile + */ + +#include "battery.h" +#include "battery_smart.h" +#include "gpio.h" +#include "host_command.h" + +#define SB_SHIP_MODE_ADDR 0x3a +#define SB_SHIP_MODE_DATA 0xc574 + +/* Values for 48Wh 4UAF495780-1-T1186/AC011353-PRR14G01 battery */ +static const struct battery_info info_4s1p = { + + .voltage_max = 17200, + .voltage_normal = 15200, /* Average of max & min */ + .voltage_min = 12000, + + /* Pre-charge values. */ + .precharge_current = 256, /* mA */ + + .start_charging_min_c = 0, + .start_charging_max_c = 50, + .charging_min_c = 0, + .charging_max_c = 60, + .discharging_min_c = 0, + .discharging_max_c = 40, +}; + +/* Values for 54Wh LIS3091ACPC(SYS6)/AC011401-PRR13G01 battery */ +static const struct battery_info info_3s1p = { + + .voltage_max = 12600, + .voltage_normal = 11100, /* Average of max & min */ + .voltage_min = 9000, + + /* Pre-charge values. */ + .precharge_current = 256, /* mA */ + + .start_charging_min_c = 0, + .start_charging_max_c = 50, + .charging_min_c = 0, + .charging_max_c = 60, + .discharging_min_c = 0, + .discharging_max_c = 75, +}; + +const struct battery_info *battery_get_info(void) +{ + if (gpio_get_level(GPIO_BAT_ID)) + return &info_3s1p; + else + return &info_4s1p; +} + +int board_cut_off_battery(void) +{ + return sb_write(SB_SHIP_MODE_ADDR, SB_SHIP_MODE_DATA); +} diff --git a/board/gandof/board.c b/board/gandof/board.c new file mode 100644 index 0000000000..7a7bac0564 --- /dev/null +++ b/board/gandof/board.c @@ -0,0 +1,207 @@ +/* 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. + */ +/* EC for Gandof board configuration */ + +#include "adc.h" +#include "adc_chip.h" +#include "backlight.h" +#include "chipset.h" +#include "common.h" +#include "console.h" +#include "driver/temp_sensor/g781.h" +#include "extpower.h" +#include "fan.h" +#include "gpio.h" +#include "host_command.h" +#include "i2c.h" +#include "jtag.h" +#include "keyboard_scan.h" +#include "lid_switch.h" +#include "peci.h" +#include "power.h" +#include "power_button.h" +#include "pwm.h" +#include "pwm_chip.h" +#include "registers.h" +#include "switch.h" +#include "temp_sensor.h" +#include "temp_sensor_chip.h" +#include "thermal.h" +#include "timer.h" +#include "uart.h" +#include "util.h" + +#include "gpio_list.h" + +#ifdef CONFIG_FAN_RPM_CUSTOM +#define NUM_FAN_LEVELS 8 + +struct fan_step { + int on; + int off; + int rpm; +}; + +/* Do not make the fan on/off point equal to 0 or 100 */ +const struct fan_step fan_table[NUM_FAN_LEVELS] = { + {.rpm = 0}, + {.on = 9, .off = 1, .rpm = 3200}, + {.on = 20, .off = 12, .rpm = 3700}, + {.on = 31, .off = 23, .rpm = 4000}, + {.on = 37, .off = 29, .rpm = 4400}, + {.on = 40, .off = 32, .rpm = 4900}, + {.on = 59, .off = 51, .rpm = 5500}, + {.on = 98, .off = 90, .rpm = 6500}, +}; + +int fan_percent_to_rpm(int fan, int pct) +{ + static int index; + static int previous_pct; + int i; + int temp_index; + + /* + * Compare the pct and previous pct, we have the three paths : + * 1. decreasing path. (check the off point) + * 2. increasing path. (check the on point) + * 3. invariant path. (return the current RPM) + */ + if (pct == previous_pct) { + temp_index = index; + } else if (pct < previous_pct) { + temp_index = 0; + for (i = 1; i <= index; i++) { + if (pct > fan_table[i].off) + temp_index = i; + else + break; + } + } else { + temp_index = NUM_FAN_LEVELS - 1; + for (i = NUM_FAN_LEVELS - 1; i > index; i--) { + if (pct < fan_table[i].on) + temp_index = i - 1; + else + break; + } + } + index = temp_index; + + previous_pct = pct; + + if (fan_table[index].rpm != fan_get_rpm_target(fans[fan].ch)) + cprintf(CC_THERMAL, "[%T Setting fan RPM to %d]\n", + fan_table[index].rpm); + + return fan_table[index].rpm; +} +#endif /* CONFIG_FAN_RPM_CUSTOM */ + +/* power signal list. Must match order of enum power_signal. */ +const struct power_signal_info power_signal_list[] = { + {GPIO_PP5000_PGOOD, 1, "PGOOD_PP5000"}, + {GPIO_PP1350_PGOOD, 1, "PGOOD_PP1350"}, + {GPIO_PP1050_PGOOD, 1, "PGOOD_PP1050"}, + {GPIO_VCORE_PGOOD, 1, "PGOOD_VCORE"}, + {GPIO_PCH_SLP_S0_L, 1, "SLP_S0#_DEASSERTED"}, + {GPIO_PCH_SLP_S3_L, 1, "SLP_S3#_DEASSERTED"}, + {GPIO_PCH_SLP_S5_L, 1, "SLP_S5#_DEASSERTED"}, + {GPIO_PCH_SLP_SUS_L, 1, "SLP_SUS#_DEASSERTED"}, +}; +BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT); + +/* ADC channels. Must be in the exactly same order as in enum adc_channel. */ +const struct adc_t adc_channels[] = { + /* EC internal temperature is calculated by + * 273 + (295 - 450 * ADC_VALUE / ADC_READ_MAX) / 2 + * = -225 * ADC_VALUE / ADC_READ_MAX + 420.5 + */ + {"ECTemp", LM4_ADC_SEQ0, -225, ADC_READ_MAX, 420, + LM4_AIN_NONE, 0x0e /* TS0 | IE0 | END0 */, 0, 0}, + + /* IOUT == ICMNT is on PE3/AIN0 */ + /* We have 0.01-ohm resistors, and IOUT is 20X the differential + * voltage, so 1000mA ==> 200mV. + * ADC returns 0x000-0xFFF, which maps to 0.0-3.3V (as configured). + * mA = 1000 * ADC_VALUE / ADC_READ_MAX * 3300 / 200 + */ + {"ChargerCurrent", LM4_ADC_SEQ1, 33000, ADC_READ_MAX * 2, 0, + LM4_AIN(0), 0x06 /* IE0 | END0 */, LM4_GPIO_E, (1<<3)}, +}; +BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); + +/* PWM channels. Must be in the exactly same order as in enum pwm_channel. */ +const struct pwm_t pwm_channels[] = { + {0, 0}, +}; +BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT); + +/* Physical fans. These are logically separate from pwm_channels. */ +const struct fan_t fans[] = { + {.flags = FAN_USE_RPM_MODE, + .rpm_min = 3200, + .rpm_max = 6500, + .ch = 2, + .pgood_gpio = GPIO_PP5000_PGOOD, + .enable_gpio = GPIO_PP5000_FAN_EN, + }, +}; +BUILD_ASSERT(ARRAY_SIZE(fans) == CONFIG_FANS); + +/* I2C ports */ +const struct i2c_port_t i2c_ports[] = { + {"batt_chg", 0, 100}, + {"thermal", 5, 100}, +}; +const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); + +/* Temperature sensors data; must be in same order as enum temp_sensor_id. */ +const struct temp_sensor_t temp_sensors[] = { + {"PECI", TEMP_SENSOR_TYPE_CPU, peci_temp_sensor_get_val, 0, 2}, + {"ECInternal", TEMP_SENSOR_TYPE_BOARD, chip_temp_sensor_get_val, 0, 4}, + {"G781Internal", TEMP_SENSOR_TYPE_BOARD, g781_get_val, + G781_IDX_INTERNAL, 4}, + {"G781External", TEMP_SENSOR_TYPE_BOARD, g781_get_val, + G781_IDX_EXTERNAL, 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[] = { + /* Only the AP affects the thermal limits and fan speed. */ + {{C_TO_K(95), C_TO_K(97), C_TO_K(105)}, C_TO_K(32), C_TO_K(96)}, + {{0, 0, 0}, 0, 0}, + {{0, 0, 0}, 0, 0}, + {{0, 0, 0}, 0, 0}, +}; +BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT); + +struct keyboard_scan_config keyscan_config = { + .output_settle_us = 40, + .debounce_down_us = 6 * MSEC, + .debounce_up_us = 30 * MSEC, + .scan_period_us = 1500, + .min_post_scan_delay_us = 1000, + .poll_timeout_us = SECOND, + .actual_key_mask = { + 0x14, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff, + 0xa4, 0xff, 0xf6, 0x55, 0xfa, 0xca /* full set */ + }, +}; + +/** + * Discharge battery when on AC power for factory test. + */ +int board_discharge_on_ac(int enable) +{ + if (enable) + gpio_set_level(GPIO_CHARGE_L, 1); + else + gpio_set_level(GPIO_CHARGE_L, 0); + return EC_SUCCESS; +} diff --git a/board/gandof/board.h b/board/gandof/board.h new file mode 100644 index 0000000000..44f6c4600c --- /dev/null +++ b/board/gandof/board.h @@ -0,0 +1,128 @@ +/* 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. + */ + +/* Configuration for Gandof mainboard */ + +#ifndef __BOARD_H +#define __BOARD_H + +/* Optional features */ +#define CONFIG_BACKLIGHT_LID +#define CONFIG_BACKLIGHT_REQ_GPIO GPIO_PCH_BKLTEN +#define CONFIG_BATTERY_CUT_OFF +#define CONFIG_BATTERY_PRESENT_GPIO GPIO_BAT_PRESENT_L +#define CONFIG_BATTERY_SMART +#define CONFIG_BOARD_VERSION +#define CONFIG_CHARGER +#define CONFIG_CHARGER_V1 +#define CONFIG_CHARGER_BQ24707A +#define CONFIG_CHARGER_DISCHARGE_ON_AC +#define CONFIG_CHIPSET_CAN_THROTTLE +#define CONFIG_CHIPSET_HASWELL +#define CONFIG_POWER_COMMON +#define CONFIG_CMD_GSV +#define CONFIG_EXTPOWER_GPIO +#define CONFIG_FANS 1 +#define CONFIG_FAN_RPM_CUSTOM +#define CONFIG_KEYBOARD_BOARD_CONFIG +#define CONFIG_KEYBOARD_COL2_INVERTED +#define CONFIG_KEYBOARD_PROTOCOL_8042 +#define CONFIG_LED_COMMON +#define CONFIG_LOW_POWER_IDLE +#define CONFIG_PECI_TJMAX 105 +#define CONFIG_POWER_BUTTON +#define CONFIG_POWER_BUTTON_X86 +#define CONFIG_PWM +#define CONFIG_PWM_KBLIGHT +#define CONFIG_SWITCH_DEDICATED_RECOVERY +#define CONFIG_TEMP_SENSOR +#define CONFIG_TEMP_SENSOR_G781 +#define CONFIG_TEMP_SENSOR_POWER_GPIO GPIO_PP3300_DX_EN +#define CONFIG_UART_HOST 2 +#define CONFIG_USB_PORT_POWER_DUMB +#define CONFIG_VBOOT_HASH +#define CONFIG_WIRELESS +#define CONFIG_WIRELESS_SUSPEND \ + (EC_WIRELESS_SWITCH_WLAN | EC_WIRELESS_SWITCH_WLAN_POWER) + +#ifndef __ASSEMBLER__ + +/* I2C ports */ +#define I2C_PORT_BATTERY 0 +#define I2C_PORT_CHARGER 0 +#define I2C_PORT_THERMAL 5 + +/* 13x8 keyboard scanner uses an entire GPIO bank for row inputs */ +#define KB_SCAN_ROW_IRQ LM4_IRQ_GPIOK +#define KB_SCAN_ROW_GPIO LM4_GPIO_K + +/* Host connects to keyboard controller module via LPC */ +#define HOST_KB_BUS_LPC + +/* USB ports */ +#define USB_PORT_COUNT 2 + +#include "gpio_signal.h" + +/* power signal definitions */ +enum power_signal { + X86_PGOOD_PP5000 = 0, + X86_PGOOD_PP1350, + X86_PGOOD_PP1050, + X86_PGOOD_VCORE, + X86_SLP_S0_DEASSERTED, + X86_SLP_S3_DEASSERTED, + X86_SLP_S5_DEASSERTED, + X86_SLP_SUS_DEASSERTED, + + /* Number of X86 signals */ + POWER_SIGNAL_COUNT +}; + +/* Charger module */ +#define CONFIG_CHARGER_SENSE_RESISTOR 10 /* Charge sense resistor, mOhm */ +#define CONFIG_CHARGER_SENSE_RESISTOR_AC 10 /* Input sensor resistor, mOhm */ +#define CONFIG_CHARGER_INPUT_CURRENT 3078 /* mA, 90% of power supply rating */ + +enum adc_channel { + /* EC internal die temperature in degrees K. */ + ADC_CH_EC_TEMP = 0, + + /* Charger current in mA. */ + ADC_CH_CHARGER_CURRENT, + + ADC_CH_COUNT +}; + +enum pwm_channel { + PWM_CH_KBLIGHT, + + /* Number of PWM channels */ + PWM_CH_COUNT +}; + +enum temp_sensor_id { + /* CPU die temperature via PECI */ + TEMP_SENSOR_CPU_PECI = 0, + /* EC internal temperature sensor */ + TEMP_SENSOR_EC_INTERNAL, + /* G781 internal and external sensors */ + TEMP_SENSOR_I2C_G781_INTERNAL, + TEMP_SENSOR_I2C_G781_EXTERNAL, + + TEMP_SENSOR_COUNT +}; + +/* Wireless signals */ +#define WIRELESS_GPIO_WLAN GPIO_WLAN_OFF_L +#define WIRELESS_GPIO_WWAN GPIO_PP3300_LTE_EN +#define WIRELESS_GPIO_WLAN_POWER GPIO_PP3300_WLAN_EN + +/* Discharge battery when on AC power for factory test. */ +int board_discharge_on_ac(int enable); + +#endif /* !__ASSEMBLER__ */ + +#endif /* __BOARD_H */ diff --git a/board/gandof/build.mk b/board/gandof/build.mk new file mode 100644 index 0000000000..d3e60bffc4 --- /dev/null +++ b/board/gandof/build.mk @@ -0,0 +1,12 @@ +# -*- makefile -*- +# 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. +# +# Board specific files build +# + +# the IC is TI Stellaris LM4 +CHIP:=lm4 + +board-y=board.o battery.o led.o diff --git a/board/gandof/ec.tasklist b/board/gandof/ec.tasklist new file mode 100644 index 0000000000..cafdb702ed --- /dev/null +++ b/board/gandof/ec.tasklist @@ -0,0 +1,27 @@ +/* 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. + */ + +/** + * List of enabled tasks in the priority order + * + * The first one has the lowest priority. + * + * For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and + * TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries, + * where : + * 'n' is the name of the task + * 'r' is the main routine of the task + * 'd' is an opaque parameter passed to the routine at startup + * 's' is the stack size in bytes; must be a multiple of 8 + */ +#define CONFIG_TASK_LIST \ + TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(CHARGER, charger_task, NULL, TASK_STACK_SIZE) \ + TASK_NOTEST(CHIPSET, chipset_task, NULL, TASK_STACK_SIZE) \ + TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \ + TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \ + TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(POWERBTN, power_button_task, NULL, TASK_STACK_SIZE) \ + TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, TASK_STACK_SIZE) diff --git a/board/gandof/gpio.inc b/board/gandof/gpio.inc new file mode 100644 index 0000000000..f3a156782a --- /dev/null +++ b/board/gandof/gpio.inc @@ -0,0 +1,102 @@ +/* -*- mode:c -*- + * + * Copyright (c) 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. + */ + +/* Inputs with interrupt handlers are first for efficiency */ +GPIO(POWER_BUTTON_L, A, 2, GPIO_INT_BOTH_DSLEEP, power_button_interrupt) /* Power button */ +GPIO(LID_OPEN, A, 3, GPIO_INT_BOTH_DSLEEP, lid_interrupt) /* Lid switch */ +GPIO(AC_PRESENT, H, 3, GPIO_INT_BOTH_DSLEEP, extpower_interrupt) /* AC power present */ +GPIO(PCH_BKLTEN, M, 3, GPIO_INT_BOTH, backlight_interrupt) /* Backlight enable signal from PCH */ +GPIO(PCH_SLP_S0_L, G, 6, GPIO_INT_BOTH, power_signal_interrupt) /* SLP_S0# signal from PCH */ +GPIO(PCH_SLP_S3_L, G, 7, GPIO_INT_BOTH_DSLEEP, power_signal_interrupt) /* SLP_S3# signal from PCH */ +GPIO(PCH_SLP_S5_L, H, 1, GPIO_INT_BOTH_DSLEEP, power_signal_interrupt) /* SLP_S5# signal from PCH */ +GPIO(PCH_SLP_SUS_L, G, 3, GPIO_INT_BOTH, power_signal_interrupt) /* SLP_SUS# signal from PCH */ +GPIO(PP1050_PGOOD, H, 4, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on 1.05V */ +GPIO(PP1350_PGOOD, H, 6, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on 1.35V (DRAM) */ +GPIO(PP5000_PGOOD, N, 0, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on 5V */ +GPIO(VCORE_PGOOD, C, 6, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on core VR */ +GPIO(PCH_EDP_VDD_EN, J, 1, GPIO_INT_BOTH, power_interrupt) /* PCH wants EDP enabled */ +GPIO(RECOVERY_L, A, 5, GPIO_PULL_UP | GPIO_INT_BOTH, switch_interrupt) /* Recovery signal from servo */ +GPIO(WP_L, A, 4, GPIO_INT_BOTH, switch_interrupt) /* Write protect input */ +GPIO(JTAG_TCK, C, 0, GPIO_DEFAULT, jtag_interrupt) /* JTAG clock input */ +GPIO(UART0_RX, A, 0, GPIO_PULL_UP | GPIO_INT_BOTH_DSLEEP, uart_deepsleep_interrupt) /* UART0 RX input */ + +/* Other inputs */ +GPIO(FAN_ALERT_L, B, 0, GPIO_INPUT, NULL) /* From thermal sensor */ +GPIO(PCH_SUSWARN_L, G, 2, GPIO_INT_BOTH, NULL) /* SUSWARN# signal from PCH */ +GPIO(USB1_OC_L, E, 7, GPIO_INPUT, NULL) /* USB port overcurrent warning */ +GPIO(USB2_OC_L, E, 0, GPIO_INPUT, NULL) /* USB port overcurrent warning */ +GPIO(BOARD_VERSION1, Q, 5, GPIO_INPUT, NULL) /* Board version stuffing resistor 1 */ +GPIO(BOARD_VERSION2, Q, 6, GPIO_INPUT, NULL) /* Board version stuffing resistor 2 */ +GPIO(BOARD_VERSION3, Q, 7, GPIO_INPUT, NULL) /* Board version stuffing resistor 3 */ +GPIO(CPU_PGOOD, C, 4, GPIO_INPUT, NULL) /* Power good to the CPU */ +GPIO(BAT_PRESENT_L, B, 4, GPIO_INPUT, NULL) /* Battery present. Repurposed BAT_TEMP */ +GPIO(BAT_ID, N, 5, GPIO_INPUT, NULL) /* Battery id for 48w/54w battery*/ +/* Outputs; all unasserted by default except for reset signals */ +GPIO(CPU_PROCHOT, B, 1, GPIO_OUT_LOW, NULL) /* Force CPU to think it's overheated */ +GPIO(PP1350_EN, H, 5, GPIO_OUT_LOW, NULL) /* Enable 1.35V supply */ +GPIO(PP3300_DX_EN, J, 2, GPIO_OUT_LOW, NULL) /* Enable power to lots of peripherals */ +GPIO(PP3300_LTE_EN, D, 2, GPIO_OUT_LOW, NULL) /* Enable LTE radio */ +GPIO(PP3300_WLAN_EN, J, 0, GPIO_OUT_LOW, NULL) /* Enable WiFi power */ +GPIO(SUSP_VR_EN, C, 7, GPIO_OUT_LOW, NULL) /* Enable 1.05V regulator */ +GPIO(VCORE_EN, C, 5, GPIO_OUT_LOW, NULL) /* Stuffing option - not connected */ +GPIO(PP5000_EN, H, 7, GPIO_OUT_LOW, NULL) /* Enable 5V supply */ +GPIO(PP5000_FAN_EN, J, 3, GPIO_OUT_LOW, NULL) /* Enable fan power rail */ +GPIO(SYS_PWROK, H, 2, GPIO_OUT_LOW, NULL) /* EC thinks everything is up and ready */ +GPIO(WLAN_OFF_L, J, 4, GPIO_OUT_LOW, NULL) /* Disable WiFi radio */ +GPIO(CHARGE_L, E, 6, GPIO_OUT_LOW, NULL) /* Allow battery to charge when on AC */ + +GPIO(ENABLE_BACKLIGHT, M, 7, GPIO_OUT_LOW, NULL) /* Enable backlight power */ +GPIO(ENABLE_TOUCHPAD, N, 1, GPIO_OUT_LOW, NULL) /* Enable touchpad power */ +GPIO(ENTERING_RW, D, 3, GPIO_OUT_LOW, NULL) /* Indicate when EC is entering RW code */ +GPIO(PCH_DPWROK, G, 0, GPIO_OUT_LOW, NULL) /* Indicate when VccDSW is good */ + +/* + * HDA_SDO is technically an output, but we need to leave it as an + * input until we drive it high. So can't use open-drain (HI_Z). + */ +GPIO(PCH_HDA_SDO, G, 1, GPIO_INPUT, NULL) /* HDA_SDO signal to PCH; when high, ME ignores security descriptor */ +GPIO(PCH_WAKE_L, F, 0, GPIO_OUT_HIGH, NULL) /* Wake signal from EC to PCH */ +GPIO(PCH_NMI_L, F, 2, GPIO_OUT_HIGH, NULL) /* Non-maskable interrupt pin to PCH */ +GPIO(PCH_PWRBTN_L, H, 0, GPIO_OUT_HIGH, NULL) /* Power button output to PCH */ +GPIO(PCH_PWROK, F, 5, GPIO_OUT_LOW, NULL) /* PWROK / APWROK signals to PCH */ + +/* + * PL6 is one of 4 pins on the EC which can't be used in open-drain + * mode. To work around this PCH_RCIN_L is set to an input. It will + * only be set to an output when it needs to be driven to 0. + */ +GPIO(PCH_RCIN_L, L, 6, GPIO_INPUT, NULL) /* RCIN# line to PCH (for 8042 emulation) */ +GPIO(PCH_RSMRST_L, F, 1, GPIO_OUT_LOW, NULL) /* Reset PCH resume power plane logic */ +GPIO(PCH_SMI_L, F, 4, GPIO_ODR_HIGH, NULL) /* System management interrupt to PCH */ +GPIO(TOUCHSCREEN_RESET_L, N, 7, GPIO_OUT_LOW, NULL) /* Reset touch screen */ +GPIO(EC_EDP_VDD_EN, J, 5, GPIO_OUT_LOW, NULL) /* Enable EDP (passthru from PCH) */ + +GPIO(LPC_CLKRUN_L, M, 2, GPIO_ODR_HIGH, NULL) /* Dunno. Probably important, though. */ +GPIO(USB1_ENABLE, E, 4, GPIO_OUT_LOW, NULL) /* USB port 1 output power enable */ +GPIO(USB2_ENABLE, D, 5, GPIO_OUT_LOW, NULL) /* USB port 2 output power enable */ + +GPIO(PCH_SUSACK_L, F, 3, GPIO_OUT_HIGH, NULL) /* Acknowledge PCH SUSWARN# signal */ +GPIO(PCH_RTCRST_L, F, 6, GPIO_ODR_HIGH, NULL) /* Not supposed to be here */ +GPIO(PCH_SRTCRST_L, F, 7, GPIO_ODR_HIGH, NULL) /* Not supposed to be here */ + +GPIO(BAT_LED0_L, D, 0, GPIO_ODR_HIGH, NULL) /* Battery charging LED - blue */ +GPIO(BAT_LED1_L, N, 4, GPIO_ODR_HIGH, NULL) /* Battery charging LED - orange */ +GPIO(PWR_LED0_L, D, 1, GPIO_ODR_HIGH, NULL) /* Power LED - blue */ +GPIO(PWR_LED1_L, N, 6, GPIO_ODR_HIGH, NULL) /* Power LED - orange */ + +ALTERNATE(A, 0x03, 1, MODULE_UART, GPIO_PULL_UP) /* UART0 */ +ALTERNATE(B, 0x04, 3, MODULE_I2C, 0) /* I2C0 SCL */ +ALTERNATE(B, 0x08, 3, MODULE_I2C, GPIO_OPEN_DRAIN) /* I2C0 SDA */ +ALTERNATE(B, 0x40, 3, MODULE_I2C, 0) /* I2C5 SCL */ +ALTERNATE(B, 0x80, 3, MODULE_I2C, GPIO_OPEN_DRAIN) /* I2C5 SDA */ +ALTERNATE(G, 0x30, 1, MODULE_UART, 0) /* UART2 */ +ALTERNATE(J, 0x40, 1, MODULE_PECI, 0) /* PECI Tx */ +ALTERNATE(J, 0x80, 0, MODULE_PECI, GPIO_ANALOG) /* PECI Rx */ +ALTERNATE(L, 0x3f, 15, MODULE_LPC, 0) /* LPC */ +ALTERNATE(M, 0x33, 15, MODULE_LPC, 0) /* LPC */ +ALTERNATE(N, 0x0c, 1, MODULE_PWM_FAN, 0) /* FAN0PWM2 */ +ALTERNATE(M, 0x40, 1, MODULE_PWM_LED, 0) /* FAN0PWM0 */ diff --git a/board/gandof/led.c b/board/gandof/led.c new file mode 100644 index 0000000000..4835404eb7 --- /dev/null +++ b/board/gandof/led.c @@ -0,0 +1,216 @@ +/* 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. + * + * Power and battery LED control for Gandof. + */ + +#include "battery.h" +#include "charge_state.h" +#include "chipset.h" +#include "ec_commands.h" +#include "gpio.h" +#include "hooks.h" +#include "host_command.h" +#include "led_common.h" +#include "util.h" + +#define CRITICAL_LOW_BATTERY_PERMILLAGE 71 +#define LOW_BATTERY_PERMILLAGE 137 +#define FULL_BATTERY_PERMILLAGE 937 + +#define LED_TOTAL_4SECS_TICKS 16 +#define LED_TOTAL_2SECS_TICKS 8 +#define LED_ON_1SEC_TICKS 4 +#define LED_ON_2SECS_TICKS 8 + +enum led_color { + LED_OFF = 0, + LED_BLUE, + LED_AMBER, + LED_PINK, + + LED_COLOR_COUNT /* Number of colors, not a color itself */ +}; + +const enum ec_led_id supported_led_ids[] = { + EC_LED_ID_POWER_LED, EC_LED_ID_BATTERY_LED}; + +const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); + +static int gandof_led_set_gpio(enum led_color color, + enum gpio_signal gpio_led_blue_l, + enum gpio_signal gpio_led_amber_l) +{ + switch (color) { + case LED_OFF: + gpio_set_level(gpio_led_blue_l, 1); + gpio_set_level(gpio_led_amber_l, 1); + break; + case LED_BLUE: + gpio_set_level(gpio_led_blue_l, 0); + gpio_set_level(gpio_led_amber_l, 1); + break; + case LED_AMBER: + gpio_set_level(gpio_led_blue_l, 1); + gpio_set_level(gpio_led_amber_l, 0); + break; + case LED_PINK: + gpio_set_level(gpio_led_blue_l, 0); + gpio_set_level(gpio_led_amber_l, 0); + break; + default: + return EC_ERROR_UNKNOWN; + } + return EC_SUCCESS; +} + +static int gandof_led_set_color_battery(enum led_color color) +{ + return gandof_led_set_gpio(color, GPIO_BAT_LED0_L, GPIO_BAT_LED1_L); +} + +static int gandof_led_set_color_power(enum led_color color) +{ + return gandof_led_set_gpio(color, GPIO_PWR_LED0_L, GPIO_PWR_LED1_L); +} + +static int gandof_led_set_color(enum ec_led_id led_id, enum led_color color) +{ + int rv; + + led_auto_control(led_id, 0); + switch (led_id) { + case EC_LED_ID_BATTERY_LED: + rv = gandof_led_set_color_battery(color); + break; + case EC_LED_ID_POWER_LED: + rv = gandof_led_set_color_power(color); + break; + default: + return EC_ERROR_UNKNOWN; + } + return rv; +} + +int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) +{ + if (brightness[EC_LED_COLOR_BLUE] != 0 && + brightness[EC_LED_COLOR_YELLOW] != 0) + gandof_led_set_color(led_id, LED_PINK); + else if (brightness[EC_LED_COLOR_BLUE] != 0) + gandof_led_set_color(led_id, LED_BLUE); + else if (brightness[EC_LED_COLOR_YELLOW] != 0) + gandof_led_set_color(led_id, LED_AMBER); + else + gandof_led_set_color(led_id, LED_OFF); + + return EC_SUCCESS; +} + +void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) +{ + /* Ignoring led_id as both leds support the same colors */ + brightness_range[EC_LED_COLOR_BLUE] = 1; + brightness_range[EC_LED_COLOR_YELLOW] = 1; +} + +static void gandof_led_set_power(void) +{ + static int power_ticks; + static int previous_state_suspend; + + power_ticks++; + + if (chipset_in_state(CHIPSET_STATE_SUSPEND)) { + /* Reset ticks if entering suspend so LED turns amber + * as soon as possible. */ + if (!previous_state_suspend) + power_ticks = 0; + + /* Blink once every four seconds. */ + gandof_led_set_color_power( + (power_ticks % LED_TOTAL_4SECS_TICKS < + LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF); + + previous_state_suspend = 1; + return; + } + + previous_state_suspend = 0; + + if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) + gandof_led_set_color_power(LED_OFF); + else if (chipset_in_state(CHIPSET_STATE_ON)) + gandof_led_set_color_power(LED_BLUE); +} + +static void gandof_led_set_battery(void) +{ + static int battery_ticks; + uint32_t chflags = charge_get_flags(); + int remaining_capacity; + int full_charge_capacity; + int permillage; + + battery_ticks++; + + remaining_capacity = *(int *)host_get_memmap(EC_MEMMAP_BATT_CAP); + full_charge_capacity = *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC); + permillage = !full_charge_capacity ? 0 : + (1000 * remaining_capacity) / full_charge_capacity; + + switch (charge_get_state()) { + case PWR_STATE_CHARGE: + /* Make the percentage approximate to UI shown */ + gandof_led_set_color_battery(permillage < + FULL_BATTERY_PERMILLAGE ? LED_AMBER : LED_BLUE); + break; + case PWR_STATE_CHARGE_NEAR_FULL: + gandof_led_set_color_battery(LED_BLUE); + break; + case PWR_STATE_DISCHARGE: + /* Less than 3%, blink one second every two seconds */ + if (!chipset_in_state(CHIPSET_STATE_ANY_OFF) && + permillage <= CRITICAL_LOW_BATTERY_PERMILLAGE) + gandof_led_set_color_battery( + (battery_ticks % LED_TOTAL_2SECS_TICKS < + LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF); + /* Less than 10%, blink one second every four seconds */ + else if (!chipset_in_state(CHIPSET_STATE_ANY_OFF) && + permillage <= LOW_BATTERY_PERMILLAGE) + gandof_led_set_color_battery( + (battery_ticks % LED_TOTAL_4SECS_TICKS < + LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF); + else + gandof_led_set_color_battery(LED_OFF); + break; + case PWR_STATE_ERROR: + gandof_led_set_color_battery( + (battery_ticks % LED_TOTAL_2SECS_TICKS < + LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF); + break; + case PWR_STATE_IDLE: /* External power connected in IDLE. */ + if (chflags & CHARGE_FLAG_FORCE_IDLE) + gandof_led_set_color_battery( + (battery_ticks % LED_TOTAL_4SECS_TICKS < + LED_ON_2SECS_TICKS) ? LED_BLUE : LED_AMBER); + else + gandof_led_set_color_battery(LED_BLUE); + break; + default: + /* Other states don't alter LED behavior */ + break; + } +} + +/* Called by hook task every 250mSec */ +static void led_tick(void) +{ + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + gandof_led_set_power(); + + if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) + gandof_led_set_battery(); +} +DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); diff --git a/util/flash_ec b/util/flash_ec index 04f8426a92..e251bd586c 100755 --- a/util/flash_ec +++ b/util/flash_ec @@ -46,6 +46,7 @@ die() { # Note: Link is a special case and is not included here. BOARDS_LM4=( + gandof auron falco paine |