diff options
-rw-r--r-- | board/flapjack/board.c | 35 | ||||
-rw-r--r-- | board/flapjack/board.h | 7 | ||||
-rw-r--r-- | board/flapjack/ec.tasklist | 3 | ||||
-rw-r--r-- | board/flapjack/gpio.inc | 5 | ||||
-rw-r--r-- | common/charge_manager.c | 23 | ||||
-rw-r--r-- | common/usb_charger.c | 9 | ||||
-rw-r--r-- | driver/build.mk | 3 | ||||
-rw-r--r-- | driver/charger/rt946x.c | 29 | ||||
-rw-r--r-- | driver/wpc/p9221.c | 802 | ||||
-rw-r--r-- | driver/wpc/p9221.h | 323 | ||||
-rw-r--r-- | include/charge_manager.h | 5 |
11 files changed, 1227 insertions, 17 deletions
diff --git a/board/flapjack/board.c b/board/flapjack/board.c index f05616f853..dd0f1bebe3 100644 --- a/board/flapjack/board.c +++ b/board/flapjack/board.c @@ -46,6 +46,8 @@ #include "usb_mux.h" #include "usb_pd_tcpm.h" #include "util.h" +#include "driver/wpc/p9221.h" + #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) #define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) @@ -273,8 +275,13 @@ int board_set_active_charge_port(int charge_port) switch (charge_port) { case 0: - /* Don't charge from a source port */ + /* Don't charge from a source port except wireless charging*/ +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + if (board_vbus_source_enabled(charge_port) + && !wpc_chip_is_online()) +#else if (board_vbus_source_enabled(charge_port)) +#endif return -1; break; case CHARGE_PORT_NONE: @@ -302,14 +309,7 @@ void board_set_charge_limit(int port, int supplier, int charge_ma, int extpower_is_present(void) { - /* - * The charger will indicate VBUS presence if we're sourcing 5V, - * so exclude such ports. - */ - if (board_vbus_source_enabled(0)) - return 0; - else - return tcpm_get_vbus_level(0); + return tcpm_get_vbus_level(0); } int pd_snk_is_vbus_provided(int port) @@ -355,6 +355,10 @@ static void board_init(void) gpio_enable_interrupt(GPIO_CHARGER_INT_ODL); #ifdef SECTION_IS_RW +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + /* Enable Wireless charger interrupts */ + gpio_enable_interrupt(GPIO_P9221_INT_ODL); +#endif /* Enable interrupts from BMI160 sensor. */ gpio_enable_interrupt(GPIO_ACCEL_INT_ODL); @@ -495,3 +499,16 @@ int board_allow_i2c_passthru(int port) void usb_charger_set_switches(int port, enum usb_switch setting) { } + +int board_get_fod(uint8_t **fod) +{ + *fod = NULL; + return 0; +} + +int board_get_epp_fod(uint8_t **fod) +{ + *fod = NULL; + return 0; +} + diff --git a/board/flapjack/board.h b/board/flapjack/board.h index 6884f309a2..e31c8d3a77 100644 --- a/board/flapjack/board.h +++ b/board/flapjack/board.h @@ -110,6 +110,12 @@ #define CONFIG_ACCEL_FIFO 256 #define CONFIG_ACCEL_FIFO_THRES (CONFIG_ACCEL_FIFO / 3) +/* Wireless Power Charger Config */ +#ifdef SECTION_IS_RW +#define CONFIG_WIRELESS_CHARGER_P9221_R7 +#endif + + /* USB PD config */ #define CONFIG_CHARGE_MANAGER #define CONFIG_USB_POWER_DELIVERY @@ -203,6 +209,7 @@ /* I2C ports */ #define I2C_PORT_CHARGER 0 #define I2C_PORT_TCPC0 0 +#define I2C_PORT_WPC 0 #define I2C_PORT_BATTERY 1 #define I2C_PORT_VIRTUAL_BATTERY I2C_PORT_BATTERY #define I2C_PORT_ACCEL 1 diff --git a/board/flapjack/ec.tasklist b/board/flapjack/ec.tasklist index f265649f3e..6000ece4b5 100644 --- a/board/flapjack/ec.tasklist +++ b/board/flapjack/ec.tasklist @@ -17,5 +17,6 @@ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \ TASK_ALWAYS(PD_C0, pd_task, NULL, VENTI_TASK_STACK_SIZE) \ TASK_ALWAYS(PD_INT_C0, pd_interrupt_handler_task, 0, TASK_STACK_SIZE) \ - TASK_ALWAYS_RO(EMMC, emmc_task, NULL, LARGER_TASK_STACK_SIZE) + TASK_ALWAYS_RO(EMMC, emmc_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS_RW(WPC,wireless_power_charger_task,NULL,LARGER_TASK_STACK_SIZE) diff --git a/board/flapjack/gpio.inc b/board/flapjack/gpio.inc index 3ff868d09f..309c36c714 100644 --- a/board/flapjack/gpio.inc +++ b/board/flapjack/gpio.inc @@ -43,9 +43,8 @@ GPIO_INT(LID_OPEN, PIN(C, 5), GPIO_INT_BOTH, lid_interrupt) /* HALL_INT_L */ GPIO_INT(GAUGE_INT_ODL, PIN(C, 9), GPIO_INT_FALLING | GPIO_PULL_UP, gauge_interrupt) - -/* Interrupts not implemented yet */ -GPIO(P9221_INT_ODL, PIN(A, 6), GPIO_INPUT) +GPIO_INT_RW(P9221_INT_ODL, PIN(A, 6), GPIO_INT_FALLING, + p9221_interrupt) /* Voltage rails control pins */ diff --git a/common/charge_manager.c b/common/charge_manager.c index 804376f528..cdc3bc228b 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -42,8 +42,14 @@ test_mockable const int supplier_priority[] = { [CHARGE_SUPPLIER_BC12_CDP] = 4, [CHARGE_SUPPLIER_BC12_SDP] = 5, [CHARGE_SUPPLIER_OTHER] = 6, - [CHARGE_SUPPLIER_VBUS] = 7 + [CHARGE_SUPPLIER_VBUS] = 7, #endif +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + [CHARGE_SUPPLIER_WPC_BPP] = 6, + [CHARGE_SUPPLIER_WPC_EPP] = 6, + [CHARGE_SUPPLIER_WPC_GPP] = 6, +#endif + }; BUILD_ASSERT(ARRAY_SIZE(supplier_priority) == CHARGE_SUPPLIER_COUNT); @@ -333,13 +339,28 @@ static void charge_manager_fill_power_info(int port, r->type = USB_CHG_TYPE_VBUS; break; #endif +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + /* + * Todo:need kernel add wpc device node in power_supply + * before that use USB_CHG_TYPE_PROPRIETARY to present WPC. + */ + case CHARGE_SUPPLIER_WPC_BPP: + case CHARGE_SUPPLIER_WPC_EPP: + case CHARGE_SUPPLIER_WPC_GPP: + r->type = USB_CHG_TYPE_PROPRIETARY; + break; +#endif #if CONFIG_DEDICATED_CHARGE_PORT_COUNT > 0 case CHARGE_SUPPLIER_DEDICATED: r->type = USB_CHG_TYPE_DEDICATED; break; #endif default: +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + r->type = USB_CHG_TYPE_VBUS; +#else r->type = USB_CHG_TYPE_OTHER; +#endif } r->meas.voltage_max = available_charge[sup][port].voltage; diff --git a/common/usb_charger.c b/common/usb_charger.c index 8b1c39647f..4d0d615a9b 100644 --- a/common/usb_charger.c +++ b/common/usb_charger.c @@ -97,6 +97,15 @@ void usb_charger_reset_charge(int port) charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED, port, NULL); #endif +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + charge_manager_update_charge(CHARGE_SUPPLIER_WPC_BPP, + port, NULL); + charge_manager_update_charge(CHARGE_SUPPLIER_WPC_EPP, + port, NULL); + charge_manager_update_charge(CHARGE_SUPPLIER_WPC_GPP, + port, NULL); +#endif + } static void usb_charger_init(void) diff --git a/driver/build.mk b/driver/build.mk index 714fae0449..40ff37fc13 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -140,3 +140,6 @@ driver-$(CONFIG_USBC_PPC_NX20P3483)+=ppc/nx20p348x.o # video converters driver-$(CONFIG_MCDP28X0)+=mcdp28x0.o + +# Wireless Power Chargers +driver-$(HAS_TASK_WPC) += wpc/p9221.o diff --git a/driver/charger/rt946x.c b/driver/charger/rt946x.c index 9a69f3847a..57dc8707a8 100644 --- a/driver/charger/rt946x.c +++ b/driver/charger/rt946x.c @@ -16,6 +16,7 @@ #include "hooks.h" #include "i2c.h" #include "printf.h" +#include "driver/wpc/p9221.h" #include "rt946x.h" #include "task.h" #include "timer.h" @@ -24,6 +25,8 @@ /* Console output macros */ #define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) +#define CPRINTS(format, args...) cprints(CC_CHARGER, "CHG " format, ## args) + /* Charger parameters */ static const struct charger_info rt946x_charger_info = { @@ -926,17 +929,37 @@ void usb_charger_task(void *u) /* VBUS attach event */ if (reg & RT946X_MASK_DPDMIRQ_ATTACH) { + CPRINTS("VBUS attached: %dmV", + charger_get_vbus_voltage(0)); bc12_type = rt946x_get_bc12_device_type(); + + CPRINTS("BC12 type %d", bc12_type); if (bc12_type != CHARGE_SUPPLIER_NONE) { - chg.current = rt946x_get_bc12_ilim(bc12_type); - charge_manager_update_charge(bc12_type, - 0, &chg); +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + if ((bc12_type == CHARGE_SUPPLIER_BC12_SDP) && + wpc_chip_is_online()) { + p9221_notify_vbus_change(1); + CPRINTS("WPC ON"); + } else { + +#endif + chg.current = rt946x_get_bc12_ilim( + bc12_type); + charge_manager_update_charge(bc12_type, + 0, &chg); +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + } +#endif rt946x_enable_bc12_detection(0); } } /* VBUS detach event */ if (reg & RT946X_MASK_DPDMIRQ_DETACH) { + CPRINTS("VBUS detached"); +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + p9221_notify_vbus_change(0); +#endif charge_manager_update_charge(bc12_type, 0, NULL); rt946x_enable_bc12_detection(1); } diff --git a/driver/wpc/p9221.c b/driver/wpc/p9221.c new file mode 100644 index 0000000000..2678173ea6 --- /dev/null +++ b/driver/wpc/p9221.c @@ -0,0 +1,802 @@ +/* Copyright 2019 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. + */ + +/* + * IDT P9221-R7 Wireless Power Receiver driver. + */ + +#include "p9221.h" +#include "charge_manager.h" +#include "chipset.h" +#include "common.h" +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "power.h" +#include "tcpm.h" +#include "timer.h" +#include "usb_charge.h" +#include "usb_pd.h" +#include "util.h" +#include <stdbool.h> +#include "printf.h" + +#define CPRINTS(format, args...) cprints(CC_USBPD, "WPC " format, ## args) + +#define P9221_TX_TIMEOUT_MS (20 * 1000*1000) +#define P9221_DCIN_TIMEOUT_MS (2 * 1000*1000) +#define P9221_VRECT_TIMEOUT_MS (2 * 1000*1000) +#define P9221_NOTIFIER_DELAY_MS (80*1000) +#define P9221R7_ILIM_MAX_UA (1600 * 1000) +#define P9221R7_OVER_CHECK_NUM 3 + +#define OVC_LIMIT 1 +#define OVC_THRESHOLD 1400000 +#define OVC_BACKOFF_LIMIT 900000 +#define OVC_BACKOFF_AMOUNT 100000 + +/* P9221 parameters */ +static struct wpc_charger_info p9221_charger_info = { + .online = false, + .i2c_port = I2C_PORT_WPC, + .pp_buf_valid = false, +}; + +static struct wpc_charger_info *wpc = &p9221_charger_info; + +static void p9221_set_offline(void); + +static const uint32_t p9221_ov_set_lut[] = { + 17000000, 20000000, 15000000, 13000000, + 11000000, 11000000, 11000000, 11000000 +}; + +static int p9221_reg_is_8_bit(uint16_t reg) +{ + switch (reg) { + case P9221_CHIP_REVISION_REG: + case P9221R7_VOUT_SET_REG: + case P9221R7_ILIM_SET_REG: + case P9221R7_CHARGE_STAT_REG: + case P9221R7_EPT_REG: + case P9221R7_SYSTEM_MODE_REG: + case P9221R7_COM_CHAN_RESET_REG: + case P9221R7_COM_CHAN_SEND_SIZE_REG: + case P9221R7_COM_CHAN_SEND_IDX_REG: + case P9221R7_COM_CHAN_RECV_SIZE_REG: + case P9221R7_COM_CHAN_RECV_IDX_REG: + case P9221R7_DEBUG_REG: + case P9221R7_EPP_Q_FACTOR_REG: + case P9221R7_EPP_TX_GUARANTEED_POWER_REG: + case P9221R7_EPP_TX_POTENTIAL_POWER_REG: + case P9221R7_EPP_TX_CAPABILITY_FLAGS_REG: + case P9221R7_EPP_RENEGOTIATION_REG: + case P9221R7_EPP_CUR_RPP_HEADER_REG: + case P9221R7_EPP_CUR_NEGOTIATED_POWER_REG: + case P9221R7_EPP_CUR_MAXIMUM_POWER_REG: + case P9221R7_EPP_CUR_FSK_MODULATION_REG: + case P9221R7_EPP_REQ_RPP_HEADER_REG: + case P9221R7_EPP_REQ_NEGOTIATED_POWER_REG: + case P9221R7_EPP_REQ_MAXIMUM_POWER_REG: + case P9221R7_EPP_REQ_FSK_MODULATION_REG: + case P9221R7_VRECT_TARGET_REG: + case P9221R7_VRECT_KNEE_REG: + case P9221R7_FOD_SECTION_REG: + case P9221R7_VRECT_ADJ_REG: + case P9221R7_ALIGN_X_ADC_REG: + case P9221R7_ALIGN_Y_ADC_REG: + case P9221R7_ASK_MODULATION_DEPTH_REG: + case P9221R7_OVSET_REG: + case P9221R7_EPP_TX_SPEC_REV_REG: + return true; + default: + return false; + } +} + +static int p9221_read8(uint16_t reg, int *val) +{ + return i2c_read_offset16(wpc->i2c_port, P9221_R7_ADDR, reg, val, 1); +} + +static int p9221_write8(uint16_t reg, int val) +{ + return i2c_write_offset16(wpc->i2c_port, P9221_R7_ADDR, reg, val, 1); +} + +static int p9221_read16(uint16_t reg, int *val) +{ + return i2c_read_offset16(wpc->i2c_port, P9221_R7_ADDR, reg, val, 2); +} + +static int p9221_write16(uint16_t reg, int val) +{ + return i2c_write_offset16(wpc->i2c_port, P9221_R7_ADDR, reg, val, 2); +} + +static int p9221_block_read(uint16_t reg, uint8_t *data, int len) +{ + return i2c_read_offset16_block(wpc->i2c_port, P9221_R7_ADDR, reg, data, + len); +} + +static int p9221_block_write(uint16_t reg, uint8_t *data, int len) +{ + return i2c_write_offset16_block(wpc->i2c_port, P9221_R7_ADDR, reg, data, + len); +} + +static int p9221_set_cmd_reg(uint8_t cmd) +{ + int cur_cmd; + int retry; + int ret; + + for (retry = 0; retry < P9221_COM_CHAN_RETRIES; retry++) { + ret = p9221_read8(P9221_COM_REG, &cur_cmd); + if (ret == EC_SUCCESS && cur_cmd == 0) + break; + msleep(25); + } + + if (retry >= P9221_COM_CHAN_RETRIES) { + CPRINTS("Failed to wait for cmd free %02x", cur_cmd); + return EC_ERROR_TIMEOUT; + } + + ret = p9221_write8(P9221_COM_REG, cmd); + if (ret) + CPRINTS("Failed to set cmd reg %02x: %d", cmd, ret); + + return ret; +} + +/* Convert a register value to uV, Hz, or uA */ +static int p9221_convert_reg_r7(uint16_t reg, uint16_t raw_data, uint32_t *val) +{ + switch (reg) { + case P9221R7_ALIGN_X_ADC_REG: /* raw */ + case P9221R7_ALIGN_Y_ADC_REG: /* raw */ + *val = raw_data; + break; + case P9221R7_VOUT_ADC_REG: /* 12-bit ADC raw */ + case P9221R7_IOUT_ADC_REG: /* 12-bit ADC raw */ + case P9221R7_DIE_TEMP_ADC_REG: /* 12-bit ADC raw */ + case P9221R7_EXT_TEMP_REG: + *val = raw_data & 0xFFF; + break; + case P9221R7_VOUT_SET_REG: /* 0.1V -> uV */ + *val = raw_data * 100 * 1000; + break; + case P9221R7_IOUT_REG: /* mA -> uA */ + case P9221R7_VRECT_REG: /* mV -> uV */ + case P9221R7_VOUT_REG: /* mV -> uV */ + case P9221R7_OP_FREQ_REG: /* kHz -> Hz */ + case P9221R7_TX_PINGFREQ_REG: /* kHz -> Hz */ + *val = raw_data * 1000; + break; + case P9221R7_ILIM_SET_REG: /* 100mA -> uA, 200mA offset */ + *val = ((raw_data * 100) + 200) * 1000; + break; + case P9221R7_OVSET_REG: /* uV */ + raw_data &= P9221R7_OVSET_MASK; + *val = p9221_ov_set_lut[raw_data]; + break; + default: + return -2; + } + + return 0; +} + +static int p9221_reg_read_converted(uint16_t reg, uint32_t *val) +{ + int ret; + int data; + + if (p9221_reg_is_8_bit(reg)) + ret = p9221_read8(reg, &data); + else + ret = p9221_read16(reg, &data); + + if (ret) + return ret; + + return p9221_convert_reg_r7(reg, data, val); +} + +static int p9221_is_online(void) +{ + int chip_id; + + if (p9221_read16(P9221_CHIP_ID_REG, &chip_id) + || chip_id != P9221_CHIP_ID) + return false; + else + return true; +} + +int wpc_chip_is_online(void) +{ + return p9221_is_online(); +} + + +void p9221_interrupt(enum gpio_signal signal) +{ + task_wake(TASK_ID_WPC); +} + +static int p9221r7_clear_interrupts(uint16_t mask) +{ + int ret; + + ret = p9221_write16(P9221R7_INT_CLEAR_REG, mask); + if (ret) { + CPRINTS("Failed to clear INT reg: %d", ret); + return ret; + } + + ret = p9221_set_cmd_reg(P9221_COM_CLEAR_INT_MASK); + if (ret) + CPRINTS("Failed to reset INT: %d", ret); + + return ret; +} + +/* + * Enable interrupts on the P9221 R7, note we don't really need to disable + * interrupts since when the device goes out of field, the P9221 is reset. + */ +static int p9221_enable_interrupts_r7(void) +{ + uint16_t mask = 0; + int ret; + + CPRINTS("Enable interrupts"); + + mask = P9221R7_STAT_LIMIT_MASK | P9221R7_STAT_CC_MASK + | P9221_STAT_VRECT; + + p9221r7_clear_interrupts(mask); + + ret = p9221_write8(P9221_INT_ENABLE_REG, mask); + if (ret) + CPRINTS("Failed to enable INTs: %d", ret); + return ret; +} + +static int p9221_send_csp(uint8_t status) +{ + int ret; + + CPRINTS("Send CSP=%d", status); + mutex_lock(&wpc->cmd_lock); + + ret = p9221_write8(P9221R7_CHARGE_STAT_REG, status); + if (ret == EC_SUCCESS) + ret = p9221_set_cmd_reg(P9221R7_COM_SENDCSP); + + mutex_unlock(&wpc->cmd_lock); + return ret; +} + +static int p9221_send_eop(uint8_t reason) +{ + int rv; + + CPRINTS("Send EOP reason=%d", reason); + mutex_lock(&wpc->cmd_lock); + + rv = p9221_write8(P9221R7_EPT_REG, reason); + if (rv == EC_SUCCESS) + rv = p9221_set_cmd_reg(P9221R7_COM_SENDEPT); + + mutex_unlock(&wpc->cmd_lock); + return rv; +} + +static void print_current_samples(uint32_t *iout_val, int count) +{ + int i; + char temp[P9221R7_OVER_CHECK_NUM * 9 + 1] = { 0 }; + + for (i = 0; i < count ; i++) + snprintf(temp + i * 9, sizeof(temp) - i * 9, + "%08x ", iout_val[i]); + CPRINTS("OVER IOUT_SAMPLES: %s", temp); +} + + +/* + * Number of times to poll the status to see if the current limit condition + * was transient or not. + */ +static void p9221_limit_handler_r7(uint16_t orign_irq_src) +{ + uint8_t reason; + int i; + int ret; + int ovc_count = 0; + uint32_t iout_val[P9221R7_OVER_CHECK_NUM] = { 0 }; + int irq_src = (int)orign_irq_src; + + CPRINTS("OVER INT: %02x", irq_src); + + if (irq_src & P9221R7_STAT_OVV) { + reason = P9221_EOP_OVER_VOLT; + goto send_eop; + } + + if (irq_src & P9221R7_STAT_OVT) { + reason = P9221_EOP_OVER_TEMP; + goto send_eop; + } + + if ((irq_src & P9221R7_STAT_UV) && !(irq_src & P9221R7_STAT_OVC)) + return; + + reason = P9221_EOP_OVER_CURRENT; + for (i = 0; i < P9221R7_OVER_CHECK_NUM; i++) { + ret = p9221r7_clear_interrupts( + irq_src & P9221R7_STAT_LIMIT_MASK); + msleep(50); + if (ret) + continue; + + ret = p9221_reg_read_converted(P9221R7_IOUT_REG, &iout_val[i]); + if (ret) { + CPRINTS("Failed to read IOUT[%d]: %d", i, ret); + continue; + } else if (iout_val[i] > OVC_THRESHOLD) { + ovc_count++; + } + + ret = p9221_read16(P9221_STATUS_REG, &irq_src); + if (ret) { + CPRINTS("Failed to read status: %d", ret); + continue; + } + + if ((irq_src & P9221R7_STAT_OVC) == 0) { + print_current_samples(iout_val, i + 1); + CPRINTS("OVER condition %04x cleared after %d tries", + irq_src, i); + return; + } + + CPRINTS("OVER status is still %04x, retry", irq_src); + } + + if (ovc_count < OVC_LIMIT) { + print_current_samples(iout_val, P9221R7_OVER_CHECK_NUM); + CPRINTS("ovc_threshold=%d, ovc_count=%d, ovc_limit=%d", + OVC_THRESHOLD, ovc_count, OVC_LIMIT); + return; + } + +send_eop: + CPRINTS("OVER is %04x, sending EOP %d", irq_src, reason); + + ret = p9221_send_eop(reason); + if (ret) + CPRINTS("Failed to send EOP %d: %d", reason, ret); +} + +static void p9221_abort_transfers(void) +{ + wpc->tx_busy = false; + wpc->tx_done = true; + wpc->rx_done = true; + wpc->rx_len = 0; +} + +/* Handler for r7 and R7 chips */ +static void p9221r7_irq_handler(uint16_t irq_src) +{ + int res; + + if (irq_src & P9221R7_STAT_LIMIT_MASK) + p9221_limit_handler_r7(irq_src); + + /* Receive complete */ + if (irq_src & P9221R7_STAT_CCDATARCVD) { + int rxlen = 0; + + res = p9221_read8(P9221R7_COM_CHAN_RECV_SIZE_REG, &rxlen); + if (res) + CPRINTS("Failed to read len: %d", res); + + if (rxlen) { + res = p9221_block_read(P9221R7_DATA_RECV_BUF_START, + wpc->rx_buf, rxlen); + if (res) { + CPRINTS("Failed to read CC data: %d", res); + rxlen = 0; + } + + wpc->rx_len = rxlen; + wpc->rx_done = true; + } + } + + /* Send complete */ + if (irq_src & P9221R7_STAT_CCSENDBUSY) { + wpc->tx_busy = false; + wpc->tx_done = true; + } + + /* Proprietary packet */ + if (irq_src & P9221R7_STAT_PPRCVD) { + res = p9221_block_read(P9221R7_DATA_RECV_BUF_START, + wpc->pp_buf, sizeof(wpc->pp_buf)); + if (res) { + CPRINTS("Failed to read PP: %d", res); + wpc->pp_buf_valid = false; + return; + } + + /* We only care about PP which come with 0x4F header */ + wpc->pp_buf_valid = (wpc->pp_buf[0] == 0x4F); + + hexdump(wpc->pp_buf, sizeof(wpc->pp_buf)); + } + + /* CC Reset complete */ + if (irq_src & P9221R7_STAT_CCRESET) + p9221_abort_transfers(); +} + +static int p9221_is_epp(void) +{ + int ret, reg; + uint32_t vout_uv; + + if (p9221_read8(P9221R7_SYSTEM_MODE_REG, ®) == EC_SUCCESS) + return reg & P9221R7_SYSTEM_MODE_EXTENDED_MASK; + + /* Check based on power supply voltage */ + ret = p9221_reg_read_converted(P9221R7_VOUT_ADC_REG, &vout_uv); + if (ret) { + CPRINTS("Failed to read VOUT_ADC: %d", ret); + return false; + } + + CPRINTS("Voltage is %duV", vout_uv); + if (vout_uv > P9221_EPP_THRESHOLD_UV) + return true; + + return false; +} + +static void p9221_config_fod(void) +{ + + int epp; + uint8_t *fod; + int fod_len; + int ret; + int retries = 3; + + CPRINTS("Config FOD"); + + epp = p9221_is_epp(); + fod_len = epp ? board_get_epp_fod(&fod) : board_get_fod(&fod); + if (!fod_len || !fod) { + CPRINTS("FOD data not found"); + return; + } + + while (retries) { + uint8_t fod_read[fod_len]; + + CPRINTS("Writing %s FOD (n=%d try=%d)", + epp ? "EPP" : "BPP", fod_len, retries); + + ret = p9221_block_write(P9221R7_FOD_REG, fod, fod_len); + if (ret) + goto no_fod; + + /* Verify the FOD has been written properly */ + ret = p9221_block_read(P9221R7_FOD_REG, fod_read, fod_len); + if (ret) + goto no_fod; + + if (memcmp(fod, fod_read, fod_len) == 0) + return; + + hexdump(fod_read, fod_len); + + retries--; + msleep(100); + } + +no_fod: + CPRINTS("Failed to set FOD. retries:%d ret:%d", retries, ret); +} + +static void p9221_set_online(void) +{ + int ret; + + CPRINTS("Set online"); + + wpc->online = true; + + wpc->tx_busy = false; + wpc->tx_done = true; + wpc->rx_done = false; + wpc->charge_supplier = CHARGE_SUPPLIER_WPC_BPP; + + ret = p9221_enable_interrupts_r7(); + if (ret) + CPRINTS("Failed to enable INT: %d", ret); + + /* NOTE: depends on _is_epp() which is not valid until DC_IN */ + p9221_config_fod(); +} + +static void p9221_vbus_check_timeout(void) +{ + CPRINTS("Timeout VBUS, online=%d", wpc->online); + if (wpc->online) + p9221_set_offline(); + +} +DECLARE_DEFERRED(p9221_vbus_check_timeout); + +static void p9221_set_offline(void) +{ + CPRINTS("Set offline"); + + wpc->online = false; + /* Reset PP buf so we can get a new serial number next time around */ + wpc->pp_buf_valid = false; + + p9221_abort_transfers(); + + hook_call_deferred(&p9221_vbus_check_timeout_data, -1); +} + +/* P9221_NOTIFIER_DELAY_MS from VRECTON */ +static int p9221_notifier_check_det(void) +{ + if (wpc->online) + goto done; + + /* send out a FOD but is_epp() is still invalid */ + p9221_set_online(); + + /* Give the vbus 2 seconds to come up. */ + CPRINTS("Waiting VBUS"); + hook_call_deferred(&p9221_vbus_check_timeout_data, -1); + hook_call_deferred(&p9221_vbus_check_timeout_data, + P9221_DCIN_TIMEOUT_MS); + +done: + wpc->p9221_check_det = false; + return 0; +} + +static int p9221_get_charge_supplier(void) +{ + uint32_t tx_id; + int txmf_id; + + if (!wpc->online) + return EC_ERROR_UNKNOWN; + + if (p9221_is_epp()) { + int ret; + wpc->charge_supplier = CHARGE_SUPPLIER_WPC_EPP; + + ret = p9221_read16(P9221R7_EPP_TX_MFG_CODE_REG, &txmf_id); + if (ret || txmf_id != P9221_GPP_TX_MF_ID) + return ret; + + ret = p9221_block_read(P9221R7_PROP_TX_ID_REG, + (uint8_t *) &tx_id, + P9221R7_PROP_TX_ID_SIZE); + if (ret) + return ret; + + if (tx_id & P9221R7_PROP_TX_ID_GPP_MASK) + wpc->charge_supplier = CHARGE_SUPPLIER_WPC_GPP; + } else { + wpc->charge_supplier = CHARGE_SUPPLIER_WPC_BPP; + } + + CPRINTS("txmf_id=0x%04x tx_id=0x%08x supplier=%d", + txmf_id, tx_id, wpc->charge_supplier); + return EC_SUCCESS; +} + +static int p9221_get_icl(int charge_supplier) +{ + switch (charge_supplier) { + case CHARGE_SUPPLIER_WPC_EPP: + case CHARGE_SUPPLIER_WPC_GPP: + return P9221_DC_ICL_EPP_MA; + case CHARGE_SUPPLIER_WPC_BPP: + default: + return P9221_DC_ICL_BPP_MA; + } +} + +static int p9221_get_ivl(int charge_supplier) +{ + switch (charge_supplier) { + case CHARGE_SUPPLIER_WPC_EPP: + case CHARGE_SUPPLIER_WPC_GPP: + return P9221_DC_IVL_EPP_MV; + case CHARGE_SUPPLIER_WPC_BPP: + default: + return P9221_DC_IVL_BPP_MV; + } +} + +static void p9221_update_charger(int type, struct charge_port_info *chg) +{ + if (!chg) + charge_manager_update_dualrole(0, CAP_UNKNOWN); + else + charge_manager_update_dualrole(0, CAP_DEDICATED); + + charge_manager_update_charge(type, 0, chg); +} + +static int p9221_reg_write_converted_r7(uint16_t reg, uint32_t val) +{ + int ret = 0; + uint16_t data; + int i; + /* Do the appropriate conversion */ + switch (reg) { + case P9221R7_ILIM_SET_REG: + /* uA -> 0.1A, offset 0.2A */ + if ((val < 200000) || (val > 1600000)) + return -EC_ERROR_INVAL; + data = (val / (100 * 1000)) - 2; + break; + case P9221R7_VOUT_SET_REG: + /* uV -> 0.1V */ + val /= 1000; + if (val < 3500 || val > 9000) + return -EC_ERROR_INVAL; + data = val / 100; + break; + case P9221R7_OVSET_REG: + /* uV */ + for (i = 0; i < ARRAY_SIZE(p9221_ov_set_lut); i++) { + if (val == p9221_ov_set_lut[i]) + break; + } + if (i == ARRAY_SIZE(p9221_ov_set_lut)) + return -EC_ERROR_INVAL; + data = i; + break; + default: + return -EC_ERROR_INVAL; + } + if (p9221_reg_is_8_bit(reg)) + ret = p9221_write8(reg, data); + else + ret = p9221_write16(reg, data); + return ret; +} + +static int p9221_set_dc_icl(void) +{ + /* Increase the IOUT limit */ + if (p9221_reg_write_converted_r7(P9221R7_ILIM_SET_REG, + P9221R7_ILIM_MAX_UA)) + CPRINTS("%s set rx_iout limit fail.", __func__); + + return EC_SUCCESS; +} + + +static void p9221_notifier_check_vbus(void) +{ + struct charge_port_info chg; + + wpc->p9221_check_vbus = false; + + CPRINTS("%s online:%d vbus:%d is_online:%d", __func__, wpc->online, + wpc->vbus_status); + + /* + * We now have confirmation from DC_IN, kill the timer, p9221_online + * will be set by this function. + */ + hook_call_deferred(&p9221_vbus_check_timeout_data, -1); + + if (wpc->vbus_status) { + /* WPC VBUS on ,Always write FOD, check dc_icl, send CSP */ + p9221_set_dc_icl(); + p9221_config_fod(); + + p9221_send_csp(1); + + /* when wpc vbus attached after 2s, set wpc online */ + if (!wpc->online) + p9221_set_online(); + + /* WPC VBUS on , update charge voltage and current */ + p9221_get_charge_supplier(); + chg.voltage = p9221_get_ivl(wpc->charge_supplier); + chg.current = p9221_get_icl(wpc->charge_supplier); + + p9221_update_charger(wpc->charge_supplier, &chg); + } else { + /* + * Vbus detached, set wpc offline and update wpc charge voltage + * and current to zero. + */ + if (wpc->online) { + p9221_set_offline(); + p9221_update_charger(wpc->charge_supplier, NULL); + } + } + + CPRINTS("check_vbus changed on:%d vbus:%d", wpc->online, + wpc->vbus_status); + +} + +static void p9221_detect_work(void) +{ + + CPRINTS("%s online:%d check_vbus:%d check_det:%d vbus:%d", __func__, + wpc->online, wpc->p9221_check_vbus, wpc->p9221_check_det, + wpc->vbus_status); + + /* Step 1 */ + if (wpc->p9221_check_det) + p9221_notifier_check_det(); + + /* Step 2 */ + if (wpc->p9221_check_vbus) + p9221_notifier_check_vbus(); + +} +DECLARE_DEFERRED(p9221_detect_work); + +void p9221_notify_vbus_change(int vbus) +{ + wpc->p9221_check_vbus = true; + wpc->vbus_status = vbus; + hook_call_deferred(&p9221_detect_work_data, P9221_NOTIFIER_DELAY_MS); +} + +void wireless_power_charger_task(void *u) +{ + while (1) { + int ret, irq_src; + task_wait_event(-1); + + ret = p9221_read16(P9221_INT_REG, &irq_src); + if (ret) { + CPRINTS("Failed to read INT REG"); + continue; + } + + CPRINTS("INT SRC 0x%04x", irq_src); + + if (p9221r7_clear_interrupts(irq_src)) + continue; + + if (irq_src & P9221_STAT_VRECT) { + CPRINTS("VRECTON, online=%d", wpc->online); + if (!wpc->online) { + wpc->p9221_check_det = true; + hook_call_deferred(&p9221_detect_work_data, + P9221_NOTIFIER_DELAY_MS); + } + } + + p9221r7_irq_handler(irq_src); + } +} diff --git a/driver/wpc/p9221.h b/driver/wpc/p9221.h new file mode 100644 index 0000000000..7c5156c833 --- /dev/null +++ b/driver/wpc/p9221.h @@ -0,0 +1,323 @@ +/* Copyright 2018 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. + */ + + +/* + * IDT P9221-R7 Wireless Power Receiver driver definitions. + */ + +#ifndef __P9221_R7_H +#define __P9221_R7_H + +#include "common.h" +#include "gpio.h" +#include "charge_manager.h" +#include "task.h" + + +/* ========== Variant-specific configuration ============ */ + +#define P9221_R7_ADDR (0x61 << 1) + +/* + * P9221 common registers + */ +#define P9221_CHIP_ID_REG 0x00 +#define P9221_CHIP_ID 0x9220 +#define P9221_CHIP_REVISION_REG 0x02 +#define P9221_CUSTOMER_ID_REG 0x03 +#define P9221R7_CUSTOMER_ID_VAL 0x05 +#define P9221_OTP_FW_MAJOR_REV_REG 0x04 +#define P9221_OTP_FW_MINOR_REV_REG 0x06 +#define P9221_OTP_FW_DATE_REG 0x08 +#define P9221_OTP_FW_DATE_SIZE 12 +#define P9221_OTP_FW_TIME_REG 0x14 +#define P9221_OTP_FW_TIME_SIZE 8 +#define P9221_SRAM_FW_MAJOR_REV_REG 0x1C +#define P9221_SRAM_FW_MINOR_REV_REG 0x1E +#define P9221_SRAM_FW_DATE_REG 0x20 +#define P9221_SRAM_FW_DATE_SIZE 12 +#define P9221_SRAM_FW_TIME_REG 0x2C +#define P9221_SRAM_FW_TIME_SIZE 8 +#define P9221_STATUS_REG 0x34 +#define P9221_INT_REG 0x36 +#define P9221_INT_MASK 0xF7 +#define P9221_INT_ENABLE_REG 0x38 +#define P9221_GPP_TX_MF_ID 0x0072 + +/* + * P9221 Rx registers (x != 5) + */ +#define P9221_CHARGE_STAT_REG 0x3A +#define P9221_EPT_REG 0x3B +#define P9221_VOUT_ADC_REG 0x3C +#define P9221_VOUT_ADC_MASK 0x0FFF +#define P9221_VOUT_SET_REG 0x3E +#define P9221_MAX_VOUT_SET_MV_DEFAULT 9000 +#define P9221_VRECT_ADC_REG 0x40 +#define P9221_VRECT_ADC_MASK 0x0FFF +#define P9221_OVSET_REG 0x42 +#define P9221_OVSET_MASK 0x70 +#define P9221_OVSET_SHIFT 4 +#define P9221_RX_IOUT_REG 0x44 +#define P9221_DIE_TEMP_ADC_REG 0x46 +#define P9221_DIE_TEMP_ADC_MASK 0x0FFF +#define P9221_OP_FREQ_REG 0x48 +#define P9221_ILIM_SET_REG 0x4A +#define P9221_ALIGN_X_ADC_REG 0x4B +#define P9221_ALIGN_Y_ADC_REG 0x4C +#define P9221_OP_MODE_REG 0x4D +#define P9221_COM_REG 0x4E +#define P9221_FW_SWITCH_KEY_REG 0x4F +#define P9221_INT_CLEAR_REG 0x56 +#define P9221_RXID_REG 0x5C +#define P9221_RXID_LEN 6 +#define P9221_MPREQ_REG 0x5C +#define P9221_MPREQ_LEN 6 +#define P9221_FOD_REG 0x68 +#define P9221_NUM_FOD 16 +#define P9221_RX_RAWIOUT_REG 0x7A +#define P9221_RX_RAWIOUT_MASK 0xFFF +#define P9221_PMA_AD_REG 0x7C +#define P9221_RX_PINGFREQ_REG 0xFC +#define P9221_RX_PINGFREQ_MASK 0xFFF +#define P9221_LAST_REG 0xFF + +/* + * P9221R7 unique registers + */ +#define P9221R7_INT_CLEAR_REG 0x3A +#define P9221R7_VOUT_SET_REG 0x3C +#define P9221R7_ILIM_SET_REG 0x3D +#define P9221R7_ILIM_SET_MAX 0x0E /* 0x0E = 1.6A */ +#define P9221R7_CHARGE_STAT_REG 0x3E +#define P9221R7_EPT_REG 0x3F +#define P9221R7_VRECT_REG 0x40 +#define P9221R7_VOUT_REG 0x42 +#define P9221R7_IOUT_REG 0x44 +#define P9221R7_OP_FREQ_REG 0x48 +#define P9221R7_SYSTEM_MODE_REG 0x4C +#define P9221R7_COM_CHAN_RESET_REG 0x50 +#define P9221R7_COM_CHAN_SEND_SIZE_REG 0x58 +#define P9221R7_COM_CHAN_SEND_IDX_REG 0x59 +#define P9221R7_COM_CHAN_RECV_SIZE_REG 0x5A +#define P9221R7_COM_CHAN_RECV_IDX_REG 0x5B +#define P9221R7_VRECT_ADC_REG 0x60 +#define P9221R7_VOUT_ADC_REG 0x62 +#define P9221R7_VOUT_ADC_MASK 0xFFF +#define P9221R7_IOUT_ADC_REG 0x64 +#define P9221R7_IOUT_ADC_MASK 0xFFF +#define P9221R7_DIE_TEMP_ADC_REG 0x66 +#define P9221R7_DIE_TEMP_ADC_MASK 0xFFF +#define P9221R7_AC_PERIOD_REG 0x68 +#define P9221R7_TX_PINGFREQ_REG 0x6A +#define P9221R7_EXT_TEMP_REG 0x6C +#define P9221R7_EXT_TEMP_MASK 0xFFF +#define P9221R7_FOD_REG 0x70 +#define P9221R7_NUM_FOD 16 +#define P9221R7_DEBUG_REG 0x80 +#define P9221R7_EPP_Q_FACTOR_REG 0x83 +#define P9221R7_EPP_TX_GUARANTEED_POWER_REG 0x84 +#define P9221R7_EPP_TX_POTENTIAL_POWER_REG 0x85 +#define P9221R7_EPP_TX_CAPABILITY_FLAGS_REG 0x86 +#define P9221R7_EPP_RENEGOTIATION_REG 0x87 +#define P9221R7_EPP_CUR_RPP_HEADER_REG 0x88 +#define P9221R7_EPP_CUR_NEGOTIATED_POWER_REG 0x89 +#define P9221R7_EPP_CUR_MAXIMUM_POWER_REG 0x8A +#define P9221R7_EPP_CUR_FSK_MODULATION_REG 0x8B +#define P9221R7_EPP_REQ_RPP_HEADER_REG 0x8C +#define P9221R7_EPP_REQ_NEGOTIATED_POWER_REG 0x8D +#define P9221R7_EPP_REQ_MAXIMUM_POWER_REG 0x8E +#define P9221R7_EPP_REQ_FSK_MODULATION_REG 0x8F +#define P9221R7_VRECT_TARGET_REG 0x90 +#define P9221R7_VRECT_KNEE_REG 0x92 +#define P9221R7_VRECT_CORRECTION_FACTOR_REG 0x93 +#define P9221R7_VRECT_MAX_CORRECTION_FACTOR_REG 0x94 +#define P9221R7_VRECT_MIN_CORRECTION_FACTOR_REG 0x96 +#define P9221R7_FOD_SECTION_REG 0x99 +#define P9221R7_VRECT_ADJ_REG 0x9E +#define P9221R7_ALIGN_X_ADC_REG 0xA0 +#define P9221R7_ALIGN_Y_ADC_REG 0xA1 +#define P9221R7_ASK_MODULATION_DEPTH_REG 0xA2 +#define P9221R7_OVSET_REG 0xA3 +#define P9221R7_OVSET_MASK 0x7 +#define P9221R7_EPP_TX_SPEC_REV_REG 0xA9 +#define P9221R7_EPP_TX_MFG_CODE_REG 0xAA +#define P9221R7_GP0_RESET_VOLT_REG 0xAC +#define P9221R7_GP1_RESET_VOLT_REG 0xAE +#define P9221R7_GP2_RESET_VOLT_REG 0xB0 +#define P9221R7_GP3_RESET_VOLT_REG 0xB2 +#define P9221R7_PROP_TX_ID_REG 0xB4 +#define P9221R7_PROP_TX_ID_SIZE 4 +#define P9221R7_DATA_SEND_BUF_START 0x100 +#define P9221R7_DATA_SEND_BUF_SIZE 0x80 +#define P9221R7_DATA_RECV_BUF_START 0x180 +#define P9221R7_DATA_RECV_BUF_SIZE 0x80 +#define P9221R7_MAX_PP_BUF_SIZE 16 +#define P9221R7_LAST_REG 0x1FF + +/* + * System Mode Mask (r7+/0x4C) + */ +#define P9221R7_SYSTEM_MODE_EXTENDED_MASK (1 << 3) + +/* + * TX ID GPP Mask (r7+/0xB4->0xB7) + */ +#define P9221R7_PROP_TX_ID_GPP_MASK (1 << 29) + +/* + * Com Channel Commands + */ +#define P9221R7_COM_CHAN_CCRESET BIT(7) +#define P9221_COM_CHAN_RETRIES 5 + +/* + * End of Power packet types + */ +#define P9221_EOP_UNKNOWN 0x00 +#define P9221_EOP_EOC 0x01 +#define P9221_EOP_INTERNAL_FAULT 0x02 +#define P9221_EOP_OVER_TEMP 0x03 +#define P9221_EOP_OVER_VOLT 0x04 +#define P9221_EOP_OVER_CURRENT 0x05 +#define P9221_EOP_BATT_FAIL 0x06 +#define P9221_EOP_RECONFIG 0x07 +#define P9221_EOP_NO_RESPONSE 0x08 +#define P9221_EOP_NEGOTIATION_FAIL 0x0A +#define P9221_EOP_RESTART_POWER 0x0B + +/* + * Command flags + */ +#define P9221R7_COM_RENEGOTIATE P9221_COM_RENEGOTIATE +#define P9221R7_COM_SWITCH2RAM P9221_COM_SWITCH_TO_RAM_MASK +#define P9221R7_COM_CLRINT P9221_COM_CLEAR_INT_MASK +#define P9221R7_COM_SENDCSP P9221_COM_SEND_CHG_STAT_MASK +#define P9221R7_COM_SENDEPT P9221_COM_SEND_EOP_MASK +#define P9221R7_COM_LDOTGL P9221_COM_LDO_TOGGLE +#define P9221R7_COM_CCACTIVATE BIT(0) + +#define P9221_COM_RENEGOTIATE BIT(7) +#define P9221_COM_SWITCH_TO_RAM_MASK BIT(6) +#define P9221_COM_CLEAR_INT_MASK BIT(5) +#define P9221_COM_SEND_CHG_STAT_MASK BIT(4) +#define P9221_COM_SEND_EOP_MASK BIT(3) +#define P9221_COM_LDO_TOGGLE BIT(1) + +/* + * Interrupt/Status flags for P9221 + */ +#define P9221_STAT_VOUT BIT(7) +#define P9221_STAT_VRECT BIT(6) +#define P9221_STAT_ACMISSING BIT(5) +#define P9221_STAT_OV_TEMP BIT(2) +#define P9221_STAT_OV_VOLT BIT(1) +#define P9221_STAT_OV_CURRENT BIT(0) +#define P9221_STAT_LIMIT_MASK (P9221_STAT_OV_TEMP | \ + P9221_STAT_OV_VOLT | \ + P9221_STAT_OV_CURRENT) +/* + * Interrupt/Status flags for P9221R7 + */ +#define P9221R7_STAT_CCRESET BIT(12) +#define P9221R7_STAT_CCERROR BIT(11) +#define P9221R7_STAT_PPRCVD BIT(10) +#define P9221R7_STAT_CCDATARCVD BIT(9) +#define P9221R7_STAT_CCSENDBUSY BIT(8) +#define P9221R7_STAT_VOUTCHANGED BIT(7) +#define P9221R7_STAT_VRECTON BIT(6) +#define P9221R7_STAT_MODECHANGED BIT(5) +#define P9221R7_STAT_UV BIT(3) +#define P9221R7_STAT_OVT BIT(2) +#define P9221R7_STAT_OVV BIT(1) +#define P9221R7_STAT_OVC BIT(0) +#define P9221R7_STAT_MASK 0x1FFF +#define P9221R7_STAT_CC_MASK (P9221R7_STAT_CCRESET | \ + P9221R7_STAT_PPRCVD | \ + P9221R7_STAT_CCERROR | \ + P9221R7_STAT_CCDATARCVD | \ + P9221R7_STAT_CCSENDBUSY) +#define P9221R7_STAT_LIMIT_MASK (P9221R7_STAT_UV | \ + P9221R7_STAT_OVV | \ + P9221R7_STAT_OVT | \ + P9221R7_STAT_OVC) + +#define P9221_DC_ICL_BPP_MA 1000 +#define P9221_DC_ICL_EPP_MA 1100 +#define P9221_DC_IVL_BPP_MV 5000 +#define P9221_DC_IVL_EPP_MV 9000 +#define P9221_EPP_THRESHOLD_UV 7000000 + +#define true 1 +#define false 0 + +struct wpc_charger_info { + uint8_t online; /* wpc is online */ + uint8_t cust_id; /* customer id */ + uint8_t i2c_port; /* i2c port */ + /* Proprietary Packets receive buffer, to get Proprietary data from TX*/ + uint8_t pp_buf[P9221R7_MAX_PP_BUF_SIZE]; + uint8_t pp_buf_valid; + /* Common message Packets receive buffer, for get data from TX */ + uint8_t rx_buf[P9221R7_DATA_RECV_BUF_SIZE]; + uint8_t rx_len; + uint8_t rx_done; + /* Message packets send buffer, used when send messages from RX to TX*/ + uint8_t tx_buf[P9221R7_DATA_SEND_BUF_SIZE]; + uint8_t tx_id; /* TX device id */ + uint8_t tx_len; /* The data size need send to TX */ + uint8_t tx_done; /* TX data send has done */ + uint8_t tx_busy; /* when tx_busy=1, can't transfer data from RX to TX */ + /* p9221_check_vbus=1 when VBUS has changed, need update charge state */ + uint8_t p9221_check_vbus; + /* p9221_check_det=1 when TX device has detected */ + uint8_t p9221_check_det; + /* vbus_status is 1 when VBUS attached and is 0 when VBUS detached*/ + uint8_t vbus_status; + /* supplier type of wireless charger */ + uint8_t charge_supplier; + /* lock of send command to p9221 */ + struct mutex cmd_lock; +}; + +/* Interrupt handler for p9221 */ +void p9221_interrupt(enum gpio_signal signal); + +/** + * notify p9221 detect update charger status when VBUS changed + * + * @param vbus: new status of VBUS, 1 if VBUS on, 0 if VBUS off. + */ +void p9221_notify_vbus_change(int vbus); + +/** + * get the fod (foreign-object detection) parameters for bpp charger type + * + * @param fod: return the real value of fod paramerters, + * return NULL if fod paramerters not set. + * + * @return the count bytes of fod paramerters. + */ +int board_get_fod(uint8_t **fod); + +/** + * get the fod (foreign-object detection) parameters for epp chager type + * + * @param fod: return the real value of fod paramerters, + * return NULL if fod paramerters not set. + * + * @return the count bytes of fod paramerters. + */ +int board_get_epp_fod(uint8_t **fod); + +/** + * return the wireless charge online status + * + * @return true if online, false if offline. + */ +int wpc_chip_is_online(void); + +#endif diff --git a/include/charge_manager.h b/include/charge_manager.h index 41ba9bcb59..6177408acb 100644 --- a/include/charge_manager.h +++ b/include/charge_manager.h @@ -45,6 +45,11 @@ enum charge_supplier { #if CONFIG_DEDICATED_CHARGE_PORT_COUNT > 0 CHARGE_SUPPLIER_DEDICATED, #endif +#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 + CHARGE_SUPPLIER_WPC_BPP, + CHARGE_SUPPLIER_WPC_EPP, + CHARGE_SUPPLIER_WPC_GPP, +#endif CHARGE_SUPPLIER_COUNT }; |