/* 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. * * TI bq25710 battery charger driver. */ #include "battery.h" #include "battery_smart.h" #include "bq25710.h" #include "charge_ramp.h" #include "charge_state_v2.h" #include "charger.h" #include "common.h" #include "console.h" #include "hooks.h" #include "i2c.h" #include "task.h" #include "system.h" #include "timer.h" #include "util.h" #ifndef CONFIG_CHARGER_NARROW_VDC #error "BQ25710 is a NVDC charger, please enable CONFIG_CHARGER_NARROW_VDC." #endif /* * Delay required from taking the bq25710 out of low power mode and having the * correct value in register 0x3E for VSYS_MIN voltage. The length of the delay * was determined by experiment. Less than 12 msec was not enough of delay, so * the value here is set to 20 msec to have plenty of margin. */ #define BQ25710_VDDA_STARTUP_DELAY_MSEC 20 /* Sense resistor configurations and macros */ #define DEFAULT_SENSE_RESISTOR 10 #ifdef CONFIG_CHARGER_SENSE_RESISTOR_AC_BQ25710 #undef CONFIG_CHARGER_SENSE_RESISTOR_AC #define CONFIG_CHARGER_SENSE_RESISTOR_AC \ CONFIG_CHARGER_SENSE_RESISTOR_AC_BQ25710 #endif #define INPUT_RESISTOR_RATIO \ ((CONFIG_CHARGER_SENSE_RESISTOR_AC) / DEFAULT_SENSE_RESISTOR) #define CHARGING_RESISTOR_RATIO \ ((CONFIG_CHARGER_SENSE_RESISTOR) / DEFAULT_SENSE_RESISTOR) #define REG_TO_CHARGING_CURRENT(REG) ((REG) / CHARGING_RESISTOR_RATIO) #define CHARGING_CURRENT_TO_REG(CUR) ((CUR) * CHARGING_RESISTOR_RATIO) #ifdef CONFIG_CHARGER_BQ25720 #define VMIN_AP_VSYS_TH2_TO_REG(DV) ((DV) - 32) #endif /* Console output macros */ #define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) #ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA /* * If this config option is defined, then the bq25710 needs to remain in * performance mode when the AP is in S0. Performance mode is active whenever AC * power is connected or when the EN_LWPWR bit in ChargeOption0 is clear. */ static uint32_t bq25710_perf_mode_req; static struct mutex bq25710_perf_mode_mutex; #endif /* Charger parameters */ static const struct charger_info bq25710_charger_info = { .name = "bq25710", .voltage_max = 19200, .voltage_min = 1024, .voltage_step = 8, .current_max = 8128 / CHARGING_RESISTOR_RATIO, .current_min = 64 / CHARGING_RESISTOR_RATIO, .current_step = 64 / CHARGING_RESISTOR_RATIO, .input_current_max = 6400 / INPUT_RESISTOR_RATIO, .input_current_min = 50 / INPUT_RESISTOR_RATIO, .input_current_step = 50 / INPUT_RESISTOR_RATIO, }; static enum ec_error_list bq25710_get_option(int chgnum, int *option); static enum ec_error_list bq25710_set_option(int chgnum, int option); static inline int iin_dpm_reg_to_current(int reg) { return (reg + 1) * BQ25710_IIN_DPM_CURRENT_STEP_MA / INPUT_RESISTOR_RATIO; } static inline int iin_host_current_to_reg(int current) { return (current * INPUT_RESISTOR_RATIO / BQ25710_IIN_HOST_CURRENT_STEP_MA) - 1; } static inline enum ec_error_list raw_read16(int chgnum, int offset, int *value) { return i2c_read16(chg_chips[chgnum].i2c_port, chg_chips[chgnum].i2c_addr_flags, offset, value); } static inline int min_system_voltage_to_reg(int voltage_mv) { return (voltage_mv / BQ25710_MIN_SYSTEM_VOLTAGE_STEP_MV) << BQ25710_MIN_SYSTEM_VOLTAGE_SHIFT; } static inline enum ec_error_list raw_write16(int chgnum, int offset, int value) { return i2c_write16(chg_chips[chgnum].i2c_port, chg_chips[chgnum].i2c_addr_flags, offset, value); } #if defined(CONFIG_CHARGE_RAMP_HW) || \ defined(CONFIG_USB_PD_VBUS_MEASURE_CHARGER) static int bq25710_get_low_power_mode(int chgnum, int *mode) { int rv; int reg; rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_0, ®); if (rv) return rv; *mode = !!(reg & BQ25710_CHARGE_OPTION_0_LOW_POWER_MODE); return EC_SUCCESS; } static int bq25710_set_low_power_mode(int chgnum, int enable) { int rv; int reg; rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_0, ®); if (rv) return rv; #ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA mutex_lock(&bq25710_perf_mode_mutex); /* * Performance mode means not in low power mode. The bit that controls * this is EN_LWPWR in ChargeOption0. The 'enable' param in this * function is refeerring to low power mode, so enabling low power mode * means disabling performance mode and vice versa. */ if (enable) bq25710_perf_mode_req &= ~(1 << task_get_current()); else bq25710_perf_mode_req |= (1 << task_get_current()); enable = !bq25710_perf_mode_req; #endif if (enable) reg |= BQ25710_CHARGE_OPTION_0_LOW_POWER_MODE; else reg &= ~BQ25710_CHARGE_OPTION_0_LOW_POWER_MODE; rv = raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_0, reg); #ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA mutex_unlock(&bq25710_perf_mode_mutex); #endif if (rv) return rv; return EC_SUCCESS; } static int bq25710_adc_start(int chgnum, int adc_en_mask) { int reg; int mode; int tries_left = BQ25710_ADC_OPTION_ADC_CONV_MS; /* Save current mode to restore same state after ADC read */ if (bq25710_get_low_power_mode(chgnum, &mode)) return EC_ERROR_UNKNOWN; /* Exit low power mode so ADC conversion takes typical time */ if (bq25710_set_low_power_mode(chgnum, 0)) return EC_ERROR_UNKNOWN; /* * Turn on the ADC for one reading. Note that adc_en_mask * maps to bit[7:0] in ADCOption register. */ reg = (adc_en_mask & BQ25710_ADC_OPTION_EN_ADC_ALL) | BQ25710_ADC_OPTION_ADC_START; if (raw_write16(chgnum, BQ25710_REG_ADC_OPTION, reg)) return EC_ERROR_UNKNOWN; /* * Wait until the ADC operation completes. The spec says typical * conversion time is 10 msec (25 msec on bq25720). If low power * mode isn't exited first, then the conversion time jumps to * ~60 msec. */ do { /* sleep 2 ms so we time out after 2x the expected time */ msleep(2); raw_read16(chgnum, BQ25710_REG_ADC_OPTION, ®); } while (--tries_left && (reg & BQ25710_ADC_OPTION_ADC_START)); /* ADC reading attempt complete, go back to low power mode */ if (bq25710_set_low_power_mode(chgnum, mode)) return EC_ERROR_UNKNOWN; /* Could not complete read */ if (reg & BQ25710_ADC_OPTION_ADC_START) return EC_ERROR_TIMEOUT; return EC_SUCCESS; } #endif static void bq25710_init(int chgnum) { int reg; int vsys; int rv; /* * Reset registers to their default settings. There is no reset pin for * this chip so without a full power cycle, some registers may not be at * their default values. Note, need to save the POR value of * MIN_SYSTEM_VOLTAGE register prior to setting the reset so that the * correct value is preserved. In order to have the correct value read, * the bq25710 must not be in low power mode, otherwise the VDDA rail * may not be powered if AC is not connected. Note, this reset is only * required when running out of RO and not following sysjump to RW. */ if (!system_jumped_late()) { rv = bq25710_set_low_power_mode(chgnum, 0); /* Allow enough time for VDDA to be powered */ msleep(BQ25710_VDDA_STARTUP_DELAY_MSEC); rv |= raw_read16(chgnum, BQ25710_REG_MIN_SYSTEM_VOLTAGE, &vsys); rv |= raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_3, ®); if (!rv) { reg |= BQ25710_CHARGE_OPTION_3_RESET_REG; /* Set all registers to default values */ raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_3, reg); /* Restore VSYS_MIN voltage to POR reset value */ raw_write16(chgnum, BQ25710_REG_MIN_SYSTEM_VOLTAGE, vsys); } /* Reenable low power mode */ bq25710_set_low_power_mode(chgnum, 1); } if (!raw_read16(chgnum, BQ25710_REG_PROCHOT_OPTION_1, ®)) { /* Disable VDPM prochot profile at initialization */ reg &= ~BQ25710_PROCHOT_PROFILE_VDPM; /* * Enable PROCHOT to be asserted with VSYS min detection. Note * that when no battery is present, then VSYS will be set to the * value in register 0x3E (MinSysVoltage) which means that when * no battery is present prochot will continuosly be asserted. */ reg |= BQ25710_PROCHOT_PROFILE_VSYS; #ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA /* * Set the IDCHG limit who's value is defined in the config * option in mA. Also, enable IDCHG trigger for prochot. */ reg &= ~BQ25710_PROCHOT_IDCHG_VTH_MASK; /* * IDCHG limit is in 512 mA steps. Note there is a 128 mA offset * so the actual IDCHG limit will be the value stored in bits * 15:10 + 128 mA. */ reg |= ((CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA << 1) & BQ25710_PROCHOT_IDCHG_VTH_MASK); reg |= BQ25710_PROCHOT_PROFILE_IDCHG; #endif raw_write16(chgnum, BQ25710_REG_PROCHOT_OPTION_1, reg); #ifdef CONFIG_CHARGER_BQ25720_VSYS_TH2_DV /* * The default VSYS_TH2 is 5.9v for a 2S config. Boards * may need to increase this for stability. PROCHOT is * asserted when the threshold is reached. */ if (!raw_read16(chgnum, BQ25720_REG_VMIN_ACTIVE_PROTECTION, ®)) { reg &= ~BQ25720_VMIN_AP_VSYS_TH2_MASK; reg |= VMIN_AP_VSYS_TH2_TO_REG( CONFIG_CHARGER_BQ25720_VSYS_TH2_DV) << BQ25720_VMIN_AP_VSYS_TH2_SHIFT; raw_write16(chgnum, BQ25720_REG_VMIN_ACTIVE_PROTECTION, reg); } #endif } /* Reduce ILIM from default of 150% to 105% */ if (!raw_read16(chgnum, BQ25710_REG_PROCHOT_OPTION_0, ®)) { reg &= ~BQ25710_PROCHOT0_ILIM_VTH_MASK; raw_write16(chgnum, BQ25710_REG_PROCHOT_OPTION_0, reg); } /* * Reduce peak power mode overload and relax cycle time from default 20 * msec to the minimum of 5 msec. */ if (!raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_2, ®)) { reg &= ~BQ25710_CHARGE_OPTION_2_TMAX_MASK; raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_2, reg); } } /* Charger interfaces */ static const struct charger_info *bq25710_get_info(int chgnum) { return &bq25710_charger_info; } static enum ec_error_list bq25710_post_init(int chgnum) { /* * Note: bq25710 power on reset state is: * watch dog timer = 175 sec * input current limit = ~1/2 maximum setting * charging voltage = 0 mV * charging current = 0 mA * discharge on AC = disabled */ return EC_SUCCESS; } static enum ec_error_list bq25710_get_status(int chgnum, int *status) { int rv; int option; rv = bq25710_get_option(chgnum, &option); if (rv) return rv; /* Default status */ *status = CHARGER_LEVEL_2; if (option & BQ25710_CHARGE_OPTION_0_CHRG_INHIBIT) *status |= CHARGER_CHARGE_INHIBITED; return EC_SUCCESS; } static enum ec_error_list bq25710_set_mode(int chgnum, int mode) { int rv; int option; rv = bq25710_get_option(chgnum, &option); if (rv) return rv; if (mode & CHARGER_CHARGE_INHIBITED) option |= BQ25710_CHARGE_OPTION_0_CHRG_INHIBIT; else option &= ~BQ25710_CHARGE_OPTION_0_CHRG_INHIBIT; return bq25710_set_option(chgnum, option); } static enum ec_error_list bq25710_enable_otg_power(int chgnum, int enabled) { /* This is controlled with the EN_OTG pin. Support not added yet. */ return EC_ERROR_UNIMPLEMENTED; } static enum ec_error_list bq25710_set_otg_current_voltage(int chgum, int output_current, int output_voltage) { /* Add when needed. */ return EC_ERROR_UNIMPLEMENTED; } static enum ec_error_list bq25710_get_current(int chgnum, int *current) { int rv, reg; rv = raw_read16(chgnum, BQ25710_REG_CHARGE_CURRENT, ®); if (!rv) *current = REG_TO_CHARGING_CURRENT(reg); return rv; } static enum ec_error_list bq25710_set_current(int chgnum, int current) { return raw_write16(chgnum, BQ25710_REG_CHARGE_CURRENT, CHARGING_CURRENT_TO_REG(current)); } /* Get/set charge voltage limit in mV */ static enum ec_error_list bq25710_get_voltage(int chgnum, int *voltage) { return raw_read16(chgnum, BQ25710_REG_MAX_CHARGE_VOLTAGE, voltage); } static enum ec_error_list bq25710_set_voltage(int chgnum, int voltage) { return raw_write16(chgnum, BQ25710_REG_MAX_CHARGE_VOLTAGE, voltage); } /* Discharge battery when on AC power. */ static enum ec_error_list bq25710_discharge_on_ac(int chgnum, int enable) { int rv, option; rv = bq25710_get_option(chgnum, &option); if (rv) return rv; if (enable) option |= BQ25710_CHARGE_OPTION_0_EN_LEARN; else option &= ~BQ25710_CHARGE_OPTION_0_EN_LEARN; return bq25710_set_option(chgnum, option); } static enum ec_error_list bq25710_set_input_current_limit(int chgnum, int input_current) { int num_steps = iin_host_current_to_reg(input_current); return raw_write16(chgnum, BQ25710_REG_IIN_HOST, num_steps << BQ25710_IIN_HOST_CURRENT_SHIFT); } static enum ec_error_list bq25710_get_input_current_limit(int chgnum, int *input_current) { int rv, reg; /* * IIN_DPM register reflects the actual input current limit programmed * in the register, either from host or from ICO. After ICO, the * current limit used by DPM regulation may differ from the IIN_HOST * register settings. */ rv = raw_read16(chgnum, BQ25710_REG_IIN_DPM, ®); if (!rv) *input_current = iin_dpm_reg_to_current(reg >> BQ25710_IIN_DPM_CURRENT_SHIFT); return rv; } static enum ec_error_list bq25710_manufacturer_id(int chgnum, int *id) { return raw_read16(chgnum, BQ25710_REG_MANUFACTURER_ID, id); } static enum ec_error_list bq25710_device_id(int chgnum, int *id) { return raw_read16(chgnum, BQ25710_REG_DEVICE_ADDRESS, id); } #ifdef CONFIG_USB_PD_VBUS_MEASURE_CHARGER #if defined(CONFIG_CHARGER_BQ25720) static int reg_adc_vbus_to_mv(int reg) { /* * LSB => 96mV, no DC offset. */ return reg * BQ25720_ADC_VBUS_STEP_MV; } #elif defined(CONFIG_CHARGER_BQ25710) static int reg_adc_vbus_to_mv(int reg) { /* * LSB => 64mV. * Return 0 when VBUS <= 3.2V as ADC can't measure it. */ return reg ? (reg * BQ25710_ADC_VBUS_STEP_MV + BQ25710_ADC_VBUS_BASE_MV) : 0; } #else #error Only the BQ25720 and BQ25710 are supported by bq25710 driver. #endif static enum ec_error_list bq25710_get_vbus_voltage(int chgnum, int port, int *voltage) { int reg, rv; rv = bq25710_adc_start(chgnum, BQ25710_ADC_OPTION_EN_ADC_VBUS); if (rv) goto error; /* Read ADC value */ rv = raw_read16(chgnum, BQ25710_REG_ADC_VBUS_PSYS, ®); if (rv) goto error; reg >>= BQ25710_ADC_VBUS_STEP_BIT_OFFSET; *voltage = reg_adc_vbus_to_mv(reg); error: if (rv) CPRINTF("Could not read VBUS ADC! Error: %d\n", rv); return rv; } #endif static enum ec_error_list bq25710_get_option(int chgnum, int *option) { /* There are 4 option registers, but we only need the first for now. */ return raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_0, option); } static enum ec_error_list bq25710_set_option(int chgnum, int option) { /* There are 4 option registers, but we only need the first for now. */ return raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_0, option); } int bq25710_set_min_system_voltage(int chgnum, int mv) { int reg; reg = min_system_voltage_to_reg(mv); return raw_write16(chgnum, BQ25710_REG_MIN_SYSTEM_VOLTAGE, reg); } #ifdef CONFIG_CHARGE_RAMP_HW static void bq25710_chg_ramp_handle(void) { int ramp_curr; int chgnum = 0; if (IS_ENABLED(CONFIG_OCPC)) chgnum = charge_get_active_chg_chip(); /* * Once the charge ramp is stable write back the stable ramp * current to the host input current limit register */ ramp_curr = chg_ramp_get_current_limit(); if (chg_ramp_is_stable()) { if (ramp_curr && !charger_set_input_current_limit(chgnum, ramp_curr)) CPRINTF("bq25710: stable ramp current=%d\n", ramp_curr); } else { CPRINTF("bq25710: ICO stall, ramp current=%d\n", ramp_curr); } /* * Disable ICO mode. When ICO mode is active the input current limit is * given by the value in register IIN_DPM (0x22) */ charger_set_hw_ramp(0); } DECLARE_DEFERRED(bq25710_chg_ramp_handle); static enum ec_error_list bq25710_set_hw_ramp(int chgnum, int enable) { int option3_reg, option2_reg, rv; rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_3, &option3_reg); if (rv) return rv; rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_2, &option2_reg); if (rv) return rv; if (enable) { /* * ICO mode can only be used when a battery is present. If there * is no battery, or if the battery has not recovered yet from * cutoff, then enabling ICO mode will lead to VSYS * dropping out. */ if (!battery_is_present() || (battery_get_disconnect_state() != BATTERY_NOT_DISCONNECTED)) { CPRINTF("bq25710: no battery, skip ICO enable\n"); return EC_ERROR_UNKNOWN; } /* Set InputVoltage register to BC1.2 minimum ramp voltage */ rv = raw_write16(chgnum, BQ25710_REG_INPUT_VOLTAGE, BQ25710_BC12_MIN_VOLTAGE_MV); if (rv) return rv; /* Enable ICO algorithm */ option3_reg |= BQ25710_CHARGE_OPTION_3_EN_ICO_MODE; /* 0b: Input current limit is set by BQ25710_REG_IIN_HOST */ option2_reg &= ~BQ25710_CHARGE_OPTION_2_EN_EXTILIM; /* Charge ramp may take up to 2s to settle down */ hook_call_deferred(&bq25710_chg_ramp_handle_data, (4 * SECOND)); } else { /* Disable ICO algorithm */ option3_reg &= ~BQ25710_CHARGE_OPTION_3_EN_ICO_MODE; /* * 1b: Input current limit is set by the lower value of * ILIM_HIZ pin and BQ25710_REG_IIN_HOST */ option2_reg |= BQ25710_CHARGE_OPTION_2_EN_EXTILIM; } rv = raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_2, option2_reg); if (rv) return rv; return raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_3, option3_reg); } static int bq25710_ramp_is_stable(int chgnum) { int reg; if (raw_read16(chgnum, BQ25710_REG_CHARGER_STATUS, ®)) return 0; return reg & BQ25710_CHARGE_STATUS_ICO_DONE; } static int bq25710_ramp_get_current_limit(int chgnum) { int reg, rv; rv = raw_read16(chgnum, BQ25710_REG_IIN_DPM, ®); if (rv) { CPRINTF("Could not read iin_dpm current limit! Error: %d\n", rv); return 0; } return iin_dpm_reg_to_current(reg >> BQ25710_IIN_DPM_CURRENT_SHIFT); } #endif /* CONFIG_CHARGE_RAMP_HW */ #ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA /* Called on AP S5 -> S3 and S3/S0iX -> S0 transition */ static void bq25710_chipset_startup(void) { bq25710_set_low_power_mode(CHARGER_SOLO, 0); } DECLARE_HOOK(HOOK_CHIPSET_STARTUP, bq25710_chipset_startup, HOOK_PRIO_DEFAULT); DECLARE_HOOK(HOOK_CHIPSET_RESUME, bq25710_chipset_startup, HOOK_PRIO_DEFAULT); /* Called on AP S0 -> S0iX/S3 or S3 -> S5 transition */ static void bq25710_chipset_suspend(void) { bq25710_set_low_power_mode(CHARGER_SOLO, 1); } DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, bq25710_chipset_suspend, HOOK_PRIO_DEFAULT); DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, bq25710_chipset_suspend, HOOK_PRIO_DEFAULT); #endif #ifdef CONFIG_CMD_CHARGER_DUMP static int console_bq25710_dump_regs(int argc, char **argv) { int i; int val; int chgnum = 0; char *e; /* Dump all readable registers on bq25710. */ static const uint8_t regs[] = { BQ25710_REG_CHARGE_OPTION_0, BQ25710_REG_CHARGE_CURRENT, BQ25710_REG_MAX_CHARGE_VOLTAGE, BQ25710_REG_CHARGER_STATUS, BQ25710_REG_PROCHOT_STATUS, BQ25710_REG_IIN_DPM, BQ25710_REG_ADC_VBUS_PSYS, BQ25710_REG_ADC_IBAT, BQ25710_REG_ADC_CMPIN_IIN, BQ25710_REG_ADC_VSYS_VBAT, BQ25710_REG_CHARGE_OPTION_1, BQ25710_REG_CHARGE_OPTION_2, BQ25710_REG_CHARGE_OPTION_3, BQ25710_REG_PROCHOT_OPTION_0, BQ25710_REG_PROCHOT_OPTION_1, BQ25710_REG_ADC_OPTION, #ifdef CONFIG_CHARGER_BQ25720 BQ25720_REG_CHARGE_OPTION_4, BQ25720_REG_VMIN_ACTIVE_PROTECTION, #endif BQ25710_REG_OTG_VOLTAGE, BQ25710_REG_OTG_CURRENT, BQ25710_REG_INPUT_VOLTAGE, BQ25710_REG_MIN_SYSTEM_VOLTAGE, BQ25710_REG_IIN_HOST, BQ25710_REG_MANUFACTURER_ID, BQ25710_REG_DEVICE_ADDRESS, }; if (argc >= 2) { chgnum = strtoi(argv[1], &e, 10); if (*e) return EC_ERROR_PARAM1; } for (i = 0; i < ARRAY_SIZE(regs); ++i) { if (raw_read16(chgnum, regs[i], &val)) continue; ccprintf("BQ25710 REG 0x%02x: 0x%04x\n", regs[i], val); } return 0; } DECLARE_CONSOLE_COMMAND(charger_dump, console_bq25710_dump_regs, "charger_dump ", "Dump all charger registers"); #endif /* CONFIG_CMD_CHARGER_DUMP */ const struct charger_drv bq25710_drv = { .init = &bq25710_init, .post_init = &bq25710_post_init, .get_info = &bq25710_get_info, .get_status = &bq25710_get_status, .set_mode = &bq25710_set_mode, .enable_otg_power = &bq25710_enable_otg_power, .set_otg_current_voltage = &bq25710_set_otg_current_voltage, .get_current = &bq25710_get_current, .set_current = &bq25710_set_current, .get_voltage = &bq25710_get_voltage, .set_voltage = &bq25710_set_voltage, .discharge_on_ac = &bq25710_discharge_on_ac, .get_vbus_voltage = &bq25710_get_vbus_voltage, .set_input_current_limit = &bq25710_set_input_current_limit, .get_input_current_limit = &bq25710_get_input_current_limit, .manufacturer_id = &bq25710_manufacturer_id, .device_id = &bq25710_device_id, .get_option = &bq25710_get_option, .set_option = &bq25710_set_option, #ifdef CONFIG_CHARGE_RAMP_HW .set_hw_ramp = &bq25710_set_hw_ramp, .ramp_is_stable = &bq25710_ramp_is_stable, .ramp_get_current_limit = &bq25710_ramp_get_current_limit, #endif /* CONFIG_CHARGE_RAMP_HW */ };