From 52b10fc3261a28a5debae0f0e772bb67b3aee3b1 Mon Sep 17 00:00:00 2001 From: Matt Wang Date: Mon, 14 Mar 2022 19:52:30 +0800 Subject: kinox: implement OBP function Add the two ADC pins to detect the ADP_ID and the PWR_IN_IMON. ADP_ID can identify the Barrel power device and the PWR_IN_IMON can detect the adapter input voltage. Use those ADC values to set the OBP pointer then trigger PROCHOT. BUG=b:211806236;b:213955278 BRANCH=none TEST=Kinox can get the 90w barrel adapter. Signed-off-by: Matt Wang Change-Id: I84455d1028b2cfc4297e10410092454f3dd61bc2 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3521743 Reviewed-by: Elmo Lan Reviewed-by: Zhuohao Lee --- board/kinox/board.h | 18 +++ board/kinox/build.mk | 1 + board/kinox/power_detection.c | 327 ++++++++++++++++++++++++++++++++++++++++++ board/kinox/sensors.c | 12 ++ 4 files changed, 358 insertions(+) create mode 100644 board/kinox/power_detection.c diff --git a/board/kinox/board.h b/board/kinox/board.h index b2ede09c16..ba67aa07c5 100644 --- a/board/kinox/board.h +++ b/board/kinox/board.h @@ -124,6 +124,22 @@ #include "registers.h" #include "usbc_config.h" +enum adp_id { + TINY = 1, + TIO1, + TIO2 +}; + +struct adpater_id_params { + int min_voltage; + int max_voltage; + int charge_voltage; + int charge_current; + int watt; + int obp95; + int obp85; +}; + enum charge_port { CHARGE_PORT_TYPEC0, CHARGE_PORT_BARRELJACK, @@ -135,7 +151,9 @@ enum adc_channel { ADC_TEMP_SENSOR_2_CPU_VR, ADC_TEMP_SENSOR_3_WIFI, ADC_TEMP_SENSOR_4_DIMM, + ADC_PWR_IN_IMON, ADC_VBUS, + ADC_ADP_ID, ADC_CH_COUNT }; diff --git a/board/kinox/build.mk b/board/kinox/build.mk index 9c668e0e2a..440d137968 100644 --- a/board/kinox/build.mk +++ b/board/kinox/build.mk @@ -13,6 +13,7 @@ BASEBOARD:=brask board-y= board-y+=board.o +board-y+=power_detection.o board-y+=fans.o board-y+=fw_config.o board-y+=i2c.o diff --git a/board/kinox/power_detection.c b/board/kinox/power_detection.c new file mode 100644 index 0000000000..575ec0e8aa --- /dev/null +++ b/board/kinox/power_detection.c @@ -0,0 +1,327 @@ +/* Copyright 2022 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. + */ +#include "adc.h" +#include "charge_manager.h" +#include "chipset.h" +#include "common.h" +#include "compile_time_macros.h" +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "power.h" +#include "registers.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* Console output macros */ +#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) + +/******************************************************************************/ + +static const char * const adp_id_names[] = { + "unknown", + "tiny", + "tio1", + "tio2", +}; + +/* ADP_ID control */ +struct adpater_id_params tio1_power[] = { + { + .min_voltage = 3300, + .max_voltage = 3300, + .charge_voltage = 20000, + .charge_current = 6000, + .watt = 120, + .obp95 = 1990, + .obp85 = 1780, + }, +}; + +struct adpater_id_params tio2_power[] = { + { + .min_voltage = 0, + .max_voltage = 68, + .charge_voltage = 20000, + .charge_current = 8500, + .watt = 170, + .obp95 = 2820, + .obp85 = 916, + }, + { + .min_voltage = 68, + .max_voltage = 142, + .charge_voltage = 20000, + .charge_current = 2250, + .watt = 45, + .obp95 = 750, + .obp85 = 670, + }, + { + .min_voltage = 200, + .max_voltage = 288, + .charge_voltage = 20000, + .charge_current = 3250, + .watt = 65, + .obp95 = 1080, + .obp85 = 960, + }, + { + .min_voltage = 531, + .max_voltage = 607, + .charge_voltage = 20000, + .charge_current = 6000, + .watt = 120, + .obp95 = 1990, + .obp85 = 1780, + }, + { + .min_voltage = 384, + .max_voltage = 480, + .charge_voltage = 20000, + .charge_current = 7500, + .watt = 150, + .obp95 = 2490, + .obp85 = 2220, + }, + { + .min_voltage = 1062, + .max_voltage = 1126, + .charge_voltage = 20000, + .charge_current = 8500, + .watt = 170, + .obp95 = 2820, + .obp85 = 916, + }, + { + .min_voltage = 2816, + .max_voltage = 3300, + .charge_voltage = 20000, + .charge_current = 6000, + .watt = 120, + .obp95 = 1990, + .obp85 = 1780, + }, +}; + +struct adpater_id_params tiny_power[] = { + { + .min_voltage = 68, + .max_voltage = 142, + .charge_voltage = 20000, + .charge_current = 2250, + .watt = 45, + .obp95 = 750, + .obp85 = 670, + }, + { + .min_voltage = 200, + .max_voltage = 288, + .charge_voltage = 20000, + .charge_current = 3250, + .watt = 65, + .obp95 = 1080, + .obp85 = 960, + }, + { + .min_voltage = 384, + .max_voltage = 480, + .charge_voltage = 20000, + .charge_current = 4500, + .watt = 90, + .obp95 = 1490, + .obp85 = 1330, + }, + { + .min_voltage = 531, + .max_voltage = 607, + .charge_voltage = 20000, + .charge_current = 6000, + .watt = 120, + .obp95 = 0x2D3, + .obp85 = 0x286, + }, + { + .min_voltage = 653, + .max_voltage = 783, + .charge_voltage = 20000, + .charge_current = 6750, + .watt = 135, + .obp95 = 2240, + .obp85 = 2000, + }, + { + .min_voltage = 851, + .max_voltage = 997, + .charge_voltage = 20000, + .charge_current = 7500, + .watt = 150, + .obp95 = 2490, + .obp85 = 2220, + }, + { + .min_voltage = 1063, + .max_voltage = 1226, + .charge_voltage = 20000, + .charge_current = 8500, + .watt = 170, + .obp95 = 2820, + .obp85 = 916, + }, + { + .min_voltage = 1749, + .max_voltage = 1968, + .charge_voltage = 20000, + .charge_current = 11500, + .watt = 230, + .obp95 = 3810, + .obp85 = 3410, + }, +}; + +struct adpater_id_params power_type[8]; +static int adp_id_value_debounce; + +void obp_point_95(void) +{ + /* Disable this interrupt while it's asserted. */ + npcx_adc_thresh_int_enable(NPCX_ADC_THRESH1, 0); + /* Enable the voltage low interrupt. */ + npcx_adc_thresh_int_enable(NPCX_ADC_THRESH2, 1); + + /* Trigger the PROCHOT */ + gpio_set_level(GPIO_EC_PROCHOT_ODL, 0); + CPRINTF("Adapter voltage over then 95%% trigger prochot."); +} + +void obp_point_85(void) +{ + /* Disable this interrupt while it's asserted. */ + npcx_adc_thresh_int_enable(NPCX_ADC_THRESH2, 0); + /* Enable the voltage high interrupt. */ + npcx_adc_thresh_int_enable(NPCX_ADC_THRESH1, 1); + + /* Release the PROCHOT */ + gpio_set_level(GPIO_EC_PROCHOT_ODL, 1); + CPRINTF("Adapter voltage less then 85%% release prochot."); +} + +struct npcx_adc_thresh_t adc_obp_point_95 = { + .adc_ch = ADC_PWR_IN_IMON, + .adc_thresh_cb = obp_point_95, + .thresh_assert = 3300, /* Default */ +}; + +struct npcx_adc_thresh_t adc_obp_point_85 = { + .adc_ch = ADC_PWR_IN_IMON, + .adc_thresh_cb = obp_point_85, + .lower_or_higher = 1, + .thresh_assert = 0, /* Default */ +}; + +static void set_up_adc_irqs(void) +{ + /* Set interrupt thresholds for the ADC. */ + CPRINTS("%s", __func__); + npcx_adc_register_thresh_irq(NPCX_ADC_THRESH1, &adc_obp_point_95); + npcx_adc_register_thresh_irq(NPCX_ADC_THRESH2, &adc_obp_point_85); + npcx_set_adc_repetitive(adc_channels[ADC_PWR_IN_IMON].input_ch, 1); + npcx_adc_thresh_int_enable(NPCX_ADC_THRESH1, 1); + npcx_adc_thresh_int_enable(NPCX_ADC_THRESH2, 1); +} + +/* + * Scalar change to Scalar change to + * downgrade voltage 3.3V voltage + * | | + * | SIO collect | SIO collect + * | 1st adapter | 2nd adapter + * | information | information + * | | | | | | | | | | + * ------------------------------------------------------- + * | | | + * |---220 ms---|-----400 ms-----| + * + * Tiny: Twice adapter ADC values are less than 0x3FF. + * TIO1: Twice adapter ADC values are 0x3FF. + * TIO2: First adapter ADC value less than 0x3FF. + * Second adpater ADC value is 0x3FF. + */ +static void adp_id_deferred(void); +DECLARE_DEFERRED(adp_id_deferred); +void adp_id_deferred(void) +{ + struct charge_port_info pi = { 0 }; + int i = 0; + int adp_type = 0; + int adp_id_value; + int adp_finial_adc_value; + int power_type_len = 0; + + adp_id_value = adc_read_channel(ADC_ADP_ID); + + if (!adp_id_value_debounce) { + adp_id_value_debounce = adp_id_value; + /* for delay the 400ms to get the next APD_ID value */ + hook_call_deferred(&adp_id_deferred_data, 400 * MSEC); + } else if (adp_id_value_debounce == 0x3FF && adp_id_value == 0x3FF) { + adp_finial_adc_value = adp_id_value; + adp_type = TIO1; + } else if (adp_id_value_debounce < 0x3FF && adp_id_value == 0x3FF) { + adp_finial_adc_value = adp_id_value_debounce; + adp_type = TIO2; + } else if (adp_id_value_debounce < 0x3FF && adp_id_value < 0x3FF) { + adp_finial_adc_value = adp_id_value; + adp_type = TINY; + } else { + CPRINTS("ADP_ID mismatch anything!"); + /* Set the default shipping adaptor max ADC value */ + adp_finial_adc_value = 0x69; + adp_type = TINY; + } + + + switch (adp_type) { + case TIO1: + power_type_len = sizeof(tio1_power) / + sizeof(struct adpater_id_params); + memcpy(&power_type, &tio1_power, sizeof(tio1_power)); + break; + case TIO2: + power_type_len = sizeof(tio2_power) / + sizeof(struct adpater_id_params); + memcpy(&power_type, &tio2_power, sizeof(tio2_power)); + break; + case TINY: + power_type_len = sizeof(tiny_power) / + sizeof(struct adpater_id_params); + memcpy(&power_type, &tiny_power, sizeof(tiny_power)); + break; + } + + for (i = 0; (i < power_type_len) && adp_type; i++) { + if (adp_finial_adc_value <= power_type[i].max_voltage) { + adc_obp_point_95.thresh_assert = power_type[i].obp95; + adc_obp_point_85.thresh_assert = power_type[i].obp85; + pi.voltage = power_type[i].charge_voltage; + pi.current = power_type[i].charge_current; + set_up_adc_irqs(); + charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED, + DEDICATED_CHARGE_PORT, &pi); + CPRINTS("Power type %s, %dW", adp_id_names[adp_type], + power_type[i].watt); + break; + } + } +} + +static void adp_id_init(void) +{ + /* Delay 220ms to get the first ADP_ID value */ + hook_call_deferred(&adp_id_deferred_data, 220 * MSEC); +} +DECLARE_HOOK(HOOK_INIT, adp_id_init, HOOK_PRIO_DEFAULT); diff --git a/board/kinox/sensors.c b/board/kinox/sensors.c index a828904593..e444664e8f 100644 --- a/board/kinox/sensors.c +++ b/board/kinox/sensors.c @@ -46,6 +46,18 @@ const struct adc_t adc_channels[] = { .factor_mul = ADC_MAX_VOLT * 39, .factor_div = (ADC_READ_MAX + 1) * 5, }, + [ADC_PWR_IN_IMON] = { + .name = "PWR_IN_IMON", + .input_ch = NPCX_ADC_CH3, + .factor_mul = ADC_MAX_VOLT, + .factor_div = ADC_READ_MAX + 1, + }, + [ADC_ADP_ID] = { + .name = "ADP_ID", + .input_ch = NPCX_ADC_CH4, + .factor_mul = ADC_MAX_VOLT, + .factor_div = ADC_READ_MAX + 1, + }, }; BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); -- cgit v1.2.1