diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 6bb0e67dc2d..fd098b2126b 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -374,6 +374,15 @@ config BQ25618 ---help--- The BQ25618 are battery charger for lithium-ion batteries. +config SC8551 + bool "SC8551 Battery charger support" + default n + select I2C + select I2C_SC8551 + depends on BATTERY_CHARGER + ---help--- + The SC8551 are battery charger for lithium-ion batteries. + config MCP73871 bool "Microchip MCP73871 Battery charger support" default n @@ -401,19 +410,20 @@ config DEBUG_BQ25618 endif # BQ25618 +if SC8551 + +config DEBUG_SC8551 + bool "SC8551 Debug Features" + default n + ---help--- + Enable SC8551 battery management debug features. + +endif # SC8551 + config BATTERY_GAUGE bool "Battery Fuel Gauge support" default n -config CW2218 - bool "CW2218 Battery fuel gauge support" - default n - select I2C - depends on BATTERY_GAUGE - ---help--- - The CW2218 is an ultra-compact, system-side or pack-side fuel gauging - IC for Lithium-ion based batteries used in wearable and portable devices - config MAX1704X bool "MAX1704X Battery fuel gauge support" default n @@ -459,6 +469,10 @@ config I2C_BQ25618 bool default y if BQ25618 +config I2C_SC8551 + bool + default y if SC8551 + config I2C_MAX1704X bool default y if MAX1704X diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs index bb243bb70bf..57b3383bcb1 100644 --- a/drivers/power/Make.defs +++ b/drivers/power/Make.defs @@ -99,6 +99,10 @@ ifeq ($(CONFIG_I2C_BQ2429X),y) CSRCS += bq2429x.c endif +ifeq ($(CONFIG_I2C_SC8551),y) +CSRCS += sc8551.c +endif + # Add the BQ256XX I2C-based battery charger driver ifeq ($(CONFIG_I2C_BQ25618),y) diff --git a/drivers/power/sc8551.c b/drivers/power/sc8551.c new file mode 100644 index 00000000000..ae96f098ac1 --- /dev/null +++ b/drivers/power/sc8551.c @@ -0,0 +1,1945 @@ +/**************************************************************************** + * drivers/power/sc8551.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * The SC8551 are Li-Ion Battery management + * + * This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_SC8551 - And the driver must be explicitly selected. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sc8551_reg.h" +#include "sc8551.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NOT_PMIC + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sc8551_dev_s +{ + /* The common part of the battery driver visible to the upper-half driver */ + + FAR const struct battery_charger_operations_s *ops; /* Battery operations */ + sem_t batsem; /* Enforce mutually exclusive access */ + + /* Data fields specific to the lower half SC8551 driver follow */ + + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + uint32_t frequency; /* I2C frequency */ + + /* status fields specific to the current status */ + + struct sc8551_stat_s stat; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* I2C support */ + +static int sc8551_getreg8(FAR struct sc8551_dev_s *priv, uint8_t regaddr, + FAR uint8_t *val, int num); +static int sc8551_putreg8(FAR struct sc8551_dev_s *priv, uint8_t regaddr, + uint8_t val); + +static int sc8551_reset(FAR struct sc8551_dev_s *priv); +static int sc8551_watchdog(FAR struct sc8551_dev_s *priv, bool enable); +static int sc8551_sysoff(FAR struct sc8551_dev_s *priv); +static int sc8551_en_term(FAR struct sc8551_dev_s *priv, bool state); +static int sc8551_en_hiz(FAR struct sc8551_dev_s *priv, bool state); +static int sc8551_en_stat(FAR struct sc8551_dev_s *priv, bool state); +static int sc8551_setboost_otg_config(FAR struct sc8551_dev_s *priv, + bool state); +static int sc8551_powersupply(FAR struct sc8551_dev_s *priv, int current); +static int sc8551_setvolt(FAR struct sc8551_dev_s *priv, int volts); +static inline int sc8551_setcurr(FAR struct sc8551_dev_s *priv, + int req_current); + +/* Battery driver lower half methods */ + +static int sc8551_state(FAR struct battery_charger_dev_s *dev, + FAR int *status); +static int sc8551_health(FAR struct battery_charger_dev_s *dev, + FAR int *health); +static int sc8551_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status); +static int sc8551_voltage(FAR struct battery_charger_dev_s *dev, + int value); +static int sc8551_current(FAR struct battery_charger_dev_s *dev, + int value); +static int sc8551_input_current(FAR struct battery_charger_dev_s *dev, + int value); +static int sc8551_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param); + +#ifdef CONFIG_DEBUG_SC8551 +static int sc8551_dump_regs(FAR struct sc8551_dev_s *priv); +# define sc8551_dump_regs(priv) sc8551_dump_regs(priv) +#else +# define sc8551_dump_regs(priv) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Configuration fields specific to the default parameter + ****************************************************************************/ + +const struct sc8551_cfg_s g_sc8551_cfg = +{ + .bat_ovp_disable = false, + .bat_ocp_disable = false, + .bat_ovp_alm_disable = true, + .bat_ocp_alm_disable = true, + .bat_ovp_th = 4500, + .bat_ovp_alm_th = 4350, + .bat_ocp_th = 8500, + .bat_ocp_alm_th = 8000, + .bus_ovp_alm_disable = true, + .bus_ocp_disable = false, + .bus_ocp_alm_disable = true, + .bus_ovp_th = 11000, + .bus_ovp_alm_th = 10500, + .bus_ocp_th = 4000, + .bus_ocp_alm_th = 3800, + .bat_ucp_alm_disable = false, + .bat_ucp_alm_th = 2600, + .ac_ovp_th = 300, + .bat_therm_disable = true, + .bus_therm_disable = true, + .die_therm_disable = false, + .bat_therm_th = 21, /* in % */ + .bus_therm_th = 21, /* in % */ + .die_therm_th = 125, /* in degC */ + .sense_r_mohm = 2, +}; + +static const struct battery_charger_operations_s g_sc8551ops = +{ + sc8551_state, + sc8551_health, + sc8551_online, + sc8551_voltage, + sc8551_current, + sc8551_input_current, + sc8551_operate, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sc8551_getreg8 + * + * Description: + * Read a 8-bit value from a SC8551 register pair. + * + * START ACK ACK + * REPEATED-START ACK Data0 ACK Data1 NO-ACK STOP + * + ****************************************************************************/ + +static int sc8551_getreg8(FAR struct sc8551_dev_s *priv, uint8_t regaddr, + FAR uint8_t *val, int num_char) +{ + struct i2c_config_s config; + int ret; + + /* Set up the I2C configuration */ + + config.frequency = priv->frequency; + config.address = priv->addr; + config.addrlen = 7; + + /* Write the register address */ + + ret = i2c_write(priv->i2c, &config, ®addr, 1); + if (ret < 0) + { + baterr("ERROR: i2c_write failed: %d\n", ret); + return ret; + } + + /* Restart and read 8-bit values from the register */ + + ret = i2c_read(priv->i2c, &config, val, num_char); + if (ret < 0) + { + baterr("ERROR: i2c_read failed: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: sc8551_putreg8 + * + * Description: + * Write a 8-bit value to a SC8551 register pair. + * + * START ACK ACK Data0 ACK Data1 ACK STOP + * + ****************************************************************************/ + +static int sc8551_putreg8(FAR struct sc8551_dev_s *priv, uint8_t regaddr, + uint8_t val) +{ + struct i2c_config_s config; + uint8_t buffer[2]; + + /* Set up the I2C configuration */ + + config.frequency = priv->frequency; + config.address = priv->addr; + config.addrlen = 7; + + batwarn("addr: %02x val: %08x\n", regaddr, val); + + /* Set up a message to send */ + + buffer[0] = regaddr; + buffer[1] = val; + + /* Write the register address followed by the data (no RESTART) */ + + return i2c_write(priv->i2c, &config, buffer, 2); +} + +#ifdef CONFIG_DEBUG_SC8551 +static void sc8551_show_registers(FAR struct sc8551_dev_s * priv) +{ + int i; + uint8_t value; + for (i = 0; i < SC8551_REG_MAX; i++) + { + sc8551_getreg8(priv, i, &value, 1); + batinfo("[ SC8551] Reg[%02x] = 0x%02x\r\n", i, value); + } +} + +static int sc8551_dump_regs(FAR struct sc8551_dev_s * priv) +{ + int ret; + uint8_t value = 0; + + ret = sc8551_getreg8(priv, SC8551_REG_00, &value, 1); + batinfo("REG#00: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_01, &value, 1); + batinfo("REG#01: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_02, &value, 1); + batinfo("REG#02: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_03, &value, 1); + batinfo("REG#03: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_04, &value, 1); + batinfo("REG#04: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_05, &value, 1); + batinfo("REG#05: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_06, &value, 1); + batinfo("REG#06: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_07, &value, 1); + batinfo("REG#07: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_08, &value, 1); + batinfo("REG#08: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_09, &value, 1); + batinfo("REG#09: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_0A, &value, 1); + batinfo("REG#0A: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_0B, &value, 1); + batinfo("REG#0B: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_0C, &value, 1); + batinfo("REG#0C: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_0D, &value, 1); + batinfo("REG#0D: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_0E, &value, 1); + batinfo("REG#0E: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_0F, &value, 1); + batinfo("REG#0F: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_10, &value, 1); + batinfo("REG#10: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_11, &value, 1); + batinfo("REG#11: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_12, &value, 1); + batinfo("REG#12: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_13, &value, 1); + batinfo("REG#13: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_14, &value, 1); + batinfo("REG#14: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_15, &value, 1); + batinfo("REG#15: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_16, &value, 1); + batinfo("REG#16: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_17, &value, 1); + batinfo("REG#17: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_18, &value, 1); + batinfo("REG#18: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_19, &value, 1); + batinfo("REG#19: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_1A, &value, 1); + batinfo("REG#1A: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_1B, &value, 1); + batinfo("REG#1B: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_1C, &value, 1); + batinfo("REG#1C: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_1D, &value, 1); + batinfo("REG#1D: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_1E, &value, 1); + batinfo("REG#1E: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_1F, &value, 1); + batinfo("REG#1F: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_20, &value, 1); + batinfo("REG#20: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_21, &value, 1); + batinfo("REG#21: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_22, &value, 1); + batinfo("REG#22: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_23, &value, 1); + batinfo("REG#23: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_24, &value, 1); + batinfo("REG#24: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_25, &value, 1); + batinfo("REG#25: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_26, &value, 1); + batinfo("REG#26: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_27, &value, 1); + batinfo("REG#27: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_28, &value, 1); + batinfo("REG#28: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_29, &value, 1); + batinfo("REG#29: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_2A, &value, 1); + batinfo("REG#2A: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_2B, &value, 1); + batinfo("REG#2B: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_2C, &value, 1); + batinfo("REG#2C: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_2D, &value, 1); + batinfo("REG#2D: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_2E, &value, 1); + batinfo("REG#2E: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_2F, &value, 1); + batinfo("REG#2F: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_30, &value, 1); + batinfo("REG#30: 0x%08X\n", value); + ret = sc8551_getreg8(priv, SC8551_REG_31, &value, 1); + batinfo("REG#31: 0x%08X\n", value); + + /* Not reading fault register. */ + + ret = sc8551_getreg8(priv, SC8551_REG_34, &value, 1); + batinfo("REG#34: 0x%08X\n", value); + + return ret; +} +#endif + +/**************************************************************************** + * Name: sc8551_detect_device + * + * Description: + * detect the SC8551 + * + ****************************************************************************/ + +static int sc8551_detect_device(FAR struct sc8551_dev_s *priv) +{ + uint8_t val; + int ret; + + ret = sc8551_getreg8(priv, SC8551_REG_13, &val, 1); + if (ret < 0) + { + return 1; + } + + priv->stat.part_no = (val & SC8551_DEV_ID_MASK); + priv->stat.part_no >>= SC8551_DEV_ID_SHIFT; + + return 0; +} + +static int sc8551_set_ss_timeout(FAR struct sc8551_dev_s *priv, int timeout) +{ + int ret; + uint8_t val; + uint8_t val_r; + + switch (timeout) + { + case 0: + val = SC8551_SS_TIMEOUT_DISABLE; + break; + case 12: + val = SC8551_SS_TIMEOUT_12P5MS; + break; + case 25: + val = SC8551_SS_TIMEOUT_25MS; + break; + case 50: + val = SC8551_SS_TIMEOUT_50MS; + break; + case 100: + val = SC8551_SS_TIMEOUT_100MS; + break; + case 400: + val = SC8551_SS_TIMEOUT_400MS; + break; + case 1500: + val = SC8551_SS_TIMEOUT_1500MS; + break; + case 100000: + val = SC8551_SS_TIMEOUT_100000MS; + break; + default: + val = SC8551_SS_TIMEOUT_DISABLE; + break; + } + + val <<= SC8551_SS_TIMEOUT_SET_SHIFT; + val &= SC8551_SS_TIMEOUT_SET_MASK; + + ret = sc8551_getreg8(priv, SC8551_REG_2B, &val_r, 1); + val |= val_r; + + ret = sc8551_putreg8(priv, SC8551_REG_2B, val); + + return ret; +} + +/**/ + +static int sc8551_set_sense_resistor(FAR struct sc8551_dev_s *priv, + int r_mohm) +{ + int ret; + uint8_t val; + uint8_t val_r; + + if (r_mohm == 2) + val = SC8551_SET_IBAT_SNS_RES_2MHM; + else if (r_mohm == 5) + val = SC8551_SET_IBAT_SNS_RES_5MHM; + else + { + return -1; + } + + val <<= SC8551_SET_IBAT_SNS_RES_SHIFT; + val &= SC8551_SET_IBAT_SNS_RES_MASK; + + ret = sc8551_getreg8(priv, SC8551_REG_2B, &val_r, 1); + val |= val_r; + + ret = sc8551_putreg8(priv, SC8551_REG_2B, val); + + return ret; +} + +static int sc8551_update_bits(FAR struct sc8551_dev_s *priv, + uint8_t reg, + uint8_t mask, + uint8_t val) +{ + int ret; + uint8_t val_r; + + ret = sc8551_getreg8(priv, reg, &val_r, 1); + if (ret < 0) + { + baterr("[ SC8551] Failed: reg=%02X\r\n", reg); + return -1; + } + + val &= mask; + val |= val_r; + + ret = sc8551_putreg8(priv, reg, val); + if (ret < 0) + { + baterr("[ SC8551] Failed: reg=%02X\r\n", reg); + return -1; + } + + return 0; +} + +static int sc8551_enable_batovp(FAR struct sc8551_dev_s *priv, bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BAT_OVP_ENABLE; + else + val = SC8551_BAT_OVP_DISABLE; + + val <<= SC8551_BAT_OVP_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_00, + SC8551_BAT_OVP_DIS_MASK, val); + return ret; +} + +static int sc8551_set_batovp_th(FAR struct sc8551_dev_s *priv, int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BAT_OVP_BASE) + threshold = SC8551_BAT_OVP_BASE; + + val = (threshold - SC8551_BAT_OVP_BASE) / SC8551_BAT_OVP_LSB; + + val <<= SC8551_BAT_OVP_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_00, + SC8551_BAT_OVP_MASK, val); + return ret; +} + +static int sc8551_enable_batovp_alarm(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BAT_OVP_ALM_ENABLE; + else + val = SC8551_BAT_OVP_ALM_DISABLE; + + val <<= SC8551_BAT_OVP_ALM_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_01, + SC8551_BAT_OVP_ALM_DIS_MASK, val); + return ret; +} + +static int sc8551_set_batovp_alarm_th(FAR struct sc8551_dev_s *priv, + int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BAT_OVP_ALM_BASE) + threshold = SC8551_BAT_OVP_ALM_BASE; + + val = (threshold - SC8551_BAT_OVP_ALM_BASE) / SC8551_BAT_OVP_ALM_LSB; + + val <<= SC8551_BAT_OVP_ALM_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_01, + SC8551_BAT_OVP_ALM_MASK, val); + return ret; +} + +static int sc8551_enable_batocp(FAR struct sc8551_dev_s *priv, bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BAT_OCP_ENABLE; + else + val = SC8551_BAT_OCP_DISABLE; + + val <<= SC8551_BAT_OCP_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_02, + SC8551_BAT_OCP_DIS_MASK, val); + return ret; +} + +static int sc8551_set_batocp_th(FAR struct sc8551_dev_s *priv, int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BAT_OCP_BASE) + threshold = SC8551_BAT_OCP_BASE; + + val = (threshold - SC8551_BAT_OCP_BASE) / SC8551_BAT_OCP_LSB; + + val <<= SC8551_BAT_OCP_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_02, + SC8551_BAT_OCP_MASK, val); + return ret; +} + +static int sc8551_enable_batocp_alarm(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BAT_OCP_ALM_ENABLE; + else + val = SC8551_BAT_OCP_ALM_DISABLE; + + val <<= SC8551_BAT_OCP_ALM_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_03, + SC8551_BAT_OCP_ALM_DIS_MASK, val); + return ret; +} + +static int sc8551_set_batocp_alarm_th(FAR struct sc8551_dev_s *priv, + int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BAT_OCP_ALM_BASE) + threshold = SC8551_BAT_OCP_ALM_BASE; + + val = (threshold - SC8551_BAT_OCP_ALM_BASE) / SC8551_BAT_OCP_ALM_LSB; + + val <<= SC8551_BAT_OCP_ALM_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_03, + SC8551_BAT_OCP_ALM_MASK, val); + return ret; +} + +static int sc8551_set_busovp_th(FAR struct sc8551_dev_s *priv, int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BUS_OVP_BASE) + threshold = SC8551_BUS_OVP_BASE; + + val = (threshold - SC8551_BUS_OVP_BASE) / SC8551_BUS_OVP_LSB; + + val <<= SC8551_BUS_OVP_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_06, + SC8551_BUS_OVP_MASK, val); + return ret; +} + +static int sc8551_enable_busovp_alarm(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BUS_OVP_ALM_ENABLE; + else + val = SC8551_BUS_OVP_ALM_DISABLE; + + val <<= SC8551_BUS_OVP_ALM_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_07, + SC8551_BUS_OVP_ALM_DIS_MASK, val); + return ret; +} + +static int sc8551_set_busovp_alarm_th(FAR struct sc8551_dev_s *priv, + int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BUS_OVP_ALM_BASE) + threshold = SC8551_BUS_OVP_ALM_BASE; + + val = (threshold - SC8551_BUS_OVP_ALM_BASE) + / SC8551_BUS_OVP_ALM_LSB; + + val <<= SC8551_BUS_OVP_ALM_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_07, + SC8551_BUS_OVP_ALM_MASK, val); + return ret; +} + +static int sc8551_enable_busocp(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BUS_OCP_ENABLE; + else + val = SC8551_BUS_OCP_DISABLE; + + val <<= SC8551_BUS_OCP_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_08, + SC8551_BUS_OCP_DIS_MASK, val); + return ret; +} + +static int sc8551_set_busocp_th(FAR struct sc8551_dev_s *priv, int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BUS_OCP_BASE) + threshold = SC8551_BUS_OCP_BASE; + + val = (threshold - SC8551_BUS_OCP_BASE) / SC8551_BUS_OCP_LSB; + + val <<= SC8551_BUS_OCP_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_08, + SC8551_BUS_OCP_MASK, val); + return ret; +} + +static int sc8551_enable_busocp_alarm(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BUS_OCP_ALM_ENABLE; + else + val = SC8551_BUS_OCP_ALM_DISABLE; + + val <<= SC8551_BUS_OCP_ALM_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_09, + SC8551_BUS_OCP_ALM_DIS_MASK, val); + return ret; +} + +static int sc8551_set_busocp_alarm_th(FAR struct sc8551_dev_s *priv, + int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BUS_OCP_ALM_BASE) + threshold = SC8551_BUS_OCP_ALM_BASE; + + val = (threshold - SC8551_BUS_OCP_ALM_BASE) / SC8551_BUS_OCP_ALM_LSB; + + val <<= SC8551_BUS_OCP_ALM_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_09, + SC8551_BUS_OCP_ALM_MASK, val); + return ret; +} + +static int sc8551_enable_batucp_alarm(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_BAT_UCP_ALM_ENABLE; + else + val = SC8551_BAT_UCP_ALM_DISABLE; + + val <<= SC8551_BAT_UCP_ALM_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_04, + SC8551_BAT_UCP_ALM_DIS_MASK, val); + return ret; +} + +static int sc8551_set_batucp_alarm_th(FAR struct sc8551_dev_s *priv, + int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_BAT_UCP_ALM_BASE) + threshold = SC8551_BAT_UCP_ALM_BASE; + + val = (threshold - SC8551_BAT_UCP_ALM_BASE) / SC8551_BAT_UCP_ALM_LSB; + + val <<= SC8551_BAT_UCP_ALM_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_04, + SC8551_BAT_UCP_ALM_MASK, val); + return ret; +} + +static int sc8551_set_acovp_th(FAR struct sc8551_dev_s *priv, + int threshold) +{ + int ret; + uint8_t val; + + if (threshold < SC8551_AC_OVP_BASE) + threshold = SC8551_AC_OVP_BASE; + + if (threshold == SC8551_AC_OVP_6P5V) + val = 0x07; + else + val = (threshold - SC8551_AC_OVP_BASE) / SC8551_AC_OVP_LSB; + + val <<= SC8551_AC_OVP_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_05, + SC8551_AC_OVP_MASK, val); + + return ret; +} + +static int sc8551_set_vdrop_th(FAR struct sc8551_dev_s *priv, int threshold) +{ + int ret; + uint8_t val; + + if (threshold == 300) + val = SC8551_VDROP_THRESHOLD_300MV; + else + val = SC8551_VDROP_THRESHOLD_400MV; + + val <<= SC8551_VDROP_THRESHOLD_SET_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_05, + SC8551_VDROP_THRESHOLD_SET_MASK, val); + + return ret; +} + +static int sc8551_set_vdrop_deglitch(FAR struct sc8551_dev_s *priv, int us) +{ + int ret; + uint8_t val; + + if (us == 8) + val = SC8551_VDROP_DEGLITCH_8US; + else + val = SC8551_VDROP_DEGLITCH_5MS; + + val <<= SC8551_VDROP_DEGLITCH_SET_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_05, + SC8551_VDROP_DEGLITCH_SET_MASK, val); + return ret; +} + +static int sc8551_enable_bat_therm(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_TSBAT_ENABLE; + else + val = SC8551_TSBAT_DISABLE; + + val <<= SC8551_TSBAT_DIS_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_0C, + SC8551_TSBAT_DIS_MASK, val); + return ret; +} + +static int sc8551_init_protection(FAR struct sc8551_dev_s *priv) +{ + int ret; + + ret = sc8551_enable_batovp(priv, (bool)!g_sc8551_cfg.bat_ovp_disable); + batinfo("[ SC8551] %s bat ovp %s\r\n", + g_sc8551_cfg.bat_ovp_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_batocp(priv, (bool)!g_sc8551_cfg.bat_ocp_disable); + batinfo("[ SC8551] %s bat ocp %s\r\n", + g_sc8551_cfg.bat_ocp_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_batovp_alarm(priv, + (bool)!g_sc8551_cfg.bat_ovp_alm_disable); + batinfo("[ SC8551] %s bat ovp alarm %s\r\n", + g_sc8551_cfg.bat_ovp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_batocp_alarm(priv, + (bool)!g_sc8551_cfg.bat_ocp_alm_disable); + batinfo("[ SC8551] %s bat ocp alarm %s\r\n", + g_sc8551_cfg.bat_ocp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_batucp_alarm(priv, + (bool)!g_sc8551_cfg.bat_ucp_alm_disable); + batinfo("[ SC8551] %s bat ocp alarm %s\r\n", + g_sc8551_cfg.bat_ucp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_busovp_alarm(priv, + (bool)!g_sc8551_cfg.bus_ovp_alm_disable); + batinfo("[ SC8551] %s bus ovp alarm %s\r\n", + g_sc8551_cfg.bus_ovp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_busocp(priv, (bool)!g_sc8551_cfg.bus_ocp_disable); + batinfo("[ SC8551] %s bus ocp %s\r\n", + g_sc8551_cfg.bus_ocp_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_busocp_alarm(priv, + (bool)!g_sc8551_cfg.bus_ocp_alm_disable); + batinfo("[ SC8551] %s bus ocp alarm %s\r\n", + g_sc8551_cfg.bus_ocp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_bat_therm(priv, (bool)!g_sc8551_cfg.bat_therm_disable); + batinfo("[ SC8551] %s bat therm %s\r\n", + g_sc8551_cfg.bat_therm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_enable_bus_therm(priv, (bool)!g_sc8551_cfg.bus_therm_disable); + batinfo("[ SC8551] %s bus therm %s\r\n", + g_sc8551_cfg.bus_therm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = sc8551_set_batovp_th(priv, g_sc8551_cfg.bat_ovp_th); + batinfo("[ SC8551] set bat ovp th %d %s\r\n", + g_sc8551_cfg.bat_ovp_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_batovp_alarm_th(priv, g_sc8551_cfg.bat_ovp_alm_th); + batinfo("[ SC8551] set bat ovp alarm threshold %d %s\r\n", + g_sc8551_cfg.bat_ovp_alm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_batocp_th(priv, g_sc8551_cfg.bat_ocp_th); + batinfo("[ SC8551] set bat ocp threshold %d %s\r\n", + g_sc8551_cfg.bat_ocp_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_batocp_alarm_th(priv, g_sc8551_cfg.bat_ocp_alm_th); + batinfo("[ SC8551] set bat ocp alarm threshold %d %s\r\n", + g_sc8551_cfg.bat_ocp_alm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_busovp_th(priv, g_sc8551_cfg.bus_ovp_th); + batinfo("[ SC8551] set bus ovp threshold %d %s\r\n", + g_sc8551_cfg.bus_ovp_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_busovp_alarm_th(priv, g_sc8551_cfg.bus_ovp_alm_th); + batinfo("[ SC8551] set bus ovp alarm threshold %d %s\r\n", + g_sc8551_cfg.bus_ovp_alm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_busocp_th(priv, g_sc8551_cfg.bus_ocp_th); + batinfo("[ SC8551] set bus ocp threshold %d %s\r\n", + g_sc8551_cfg.bus_ocp_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_busocp_alarm_th(priv, g_sc8551_cfg.bus_ocp_alm_th); + batinfo("[ SC8551] set bus ocp alarm th %d %s\r\n", + g_sc8551_cfg.bus_ocp_alm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_batucp_alarm_th(priv, g_sc8551_cfg.bat_ucp_alm_th); + batinfo("[ SC8551] set bat ucp threshold %d %s\r\n", + g_sc8551_cfg.bat_ucp_alm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_bat_therm_th(priv, g_sc8551_cfg.bat_therm_th); + batinfo("[ SC8551] set die therm threshold %d %s\r\n", + g_sc8551_cfg.bat_therm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_bus_therm_th(priv, g_sc8551_cfg.bus_therm_th); + batinfo("[ SC8551] set bus therm threshold %d %s\r\n", + g_sc8551_cfg.bus_therm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_die_therm_th(priv, g_sc8551_cfg.die_therm_th); + batinfo("[ SC8551] set die therm threshold %d %s\r\n", + g_sc8551_cfg.die_therm_th, + !ret ? "successfully" : "failed"); + + ret = sc8551_set_acovp_th(priv, g_sc8551_cfg.ac_ovp_th); + batinfo("[ SC8551] set ac ovp threshold %d %s\r\n", + g_sc8551_cfg.ac_ovp_th, + !ret ? "successfully" : "failed"); + + return 0; +} + +static int sc8551_set_adc_scanrate(FAR struct sc8551_dev_s *priv, + bool oneshot) +{ + int ret; + uint8_t val; + + if (oneshot) + val = SC8551_ADC_RATE_ONESHOT; + else + val = SC8551_ADC_RATE_CONTINOUS; + + val <<= SC8551_ADC_RATE_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_14, + SC8551_ADC_EN_MASK, val); + return ret; +} + +static int sc8551_set_adc_scan(FAR struct sc8551_dev_s *priv, + int channel, bool enable) +{ + int ret; + uint8_t reg; + uint8_t mask; + uint8_t shift; + uint8_t val; + + if (channel > ADC_MAX_NUM) + { + return -1; + } + + if (channel == ADC_IBUS) + { + reg = SC8551_REG_14; + shift = SC8551_IBUS_ADC_DIS_SHIFT; + mask = SC8551_IBUS_ADC_DIS_MASK; + } + else + { + reg = SC8551_REG_15; + shift = 8 - channel; + mask = 1 << shift; + } + + if (enable) + val = 0 << shift; + else + val = 1 << shift; + + ret = sc8551_update_bits(priv, reg, mask, val); + + return ret; +} + +static int sc8551_init_adc(FAR struct sc8551_dev_s *priv) +{ + sc8551_set_adc_scanrate(priv, false); + sc8551_set_adc_scan(priv, ADC_IBUS, true); + sc8551_set_adc_scan(priv, ADC_VBUS, true); + sc8551_set_adc_scan(priv, ADC_VOUT, true); + sc8551_set_adc_scan(priv, ADC_VBAT, true); + sc8551_set_adc_scan(priv, ADC_IBAT, true); + sc8551_set_adc_scan(priv, ADC_TBUS, true); + sc8551_set_adc_scan(priv, ADC_TBAT, true); + sc8551_set_adc_scan(priv, ADC_TDIE, true); + sc8551_set_adc_scan(priv, ADC_VAC, true); + + sc8551_enable_adc(true); + + return 0; +} + +static int sc8551_set_alarm_int_mask(FAR struct sc8551_dev_s *priv, + uint8_t val) +{ + return sc8551_update_bits(priv, SC8551_REG_0F, val, val); +} + +/**************************************************************************** + * TODO:be careful ts bus and ts bat alarm bit mask is in + * fault mask register, so you need call + * sc8551_set_fault_int_mask for tsbus and tsbat alarm + ****************************************************************************/ + +static int sc8551_init_int_src(FAR struct sc8551_dev_s *priv) +{ + int ret; + + ret = sc8551_set_alarm_int_mask(priv, ADC_DONE | BAT_OVP_ALARM); /* | BAT_UCP_ALARM */ + if (ret) + { + baterr("[ SC8551] failed to set alarm mask:%d\r\n", ret); + return ret; + } + + return ret; +} + +static int sc8551_set_ibat_reg_th(FAR struct sc8551_dev_s *priv, int th_ma) +{ + int ret; + uint8_t val; + + if (th_ma == 200) + val = SC8551_IBAT_REG_200MA; + else if (th_ma == 300) + val = SC8551_IBAT_REG_300MA; + else if (th_ma == 400) + val = SC8551_IBAT_REG_400MA; + else if (th_ma == 500) + val = SC8551_IBAT_REG_500MA; + else + val = SC8551_IBAT_REG_500MA; + + val <<= SC8551_IBAT_REG_SHIFT; + ret = sc8551_update_bits(priv, SC8551_REG_2C, + SC8551_IBAT_REG_MASK, val); + + return ret; +} + +static int sc8551_set_vbat_reg_th(FAR struct sc8551_dev_s *priv, int th_mv) +{ + int ret; + uint8_t val; + + switch (th_mv) + { + case 50: + val = SC8551_VBAT_REG_50MV; + break; + case 100: + val = SC8551_VBAT_REG_100MV; + break; + case 150: + val = SC8551_VBAT_REG_150MV; + break; + default: + val = SC8551_VBAT_REG_200MV; + break; + } + + val <<= SC8551_VBAT_REG_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_2C, + SC8551_VBAT_REG_MASK, val); + + return ret; +} + +static int sc8551_enable_regulation(FAR struct sc8551_dev_s *priv, + bool enable) +{ + int ret; + uint8_t val; + + if (enable) + val = SC8551_EN_REGULATION_ENABLE; + else + val = SC8551_EN_REGULATION_DISABLE; + + val <<= SC8551_EN_REGULATION_SHIFT; + + ret = sc8551_update_bits(priv, SC8551_REG_2B, + SC8551_EN_REGULATION_MASK, val); + + return ret; +} + +static int sc8551_init_regulation(FAR struct sc8551_dev_s *priv) +{ + sc8551_set_ibat_reg_th(priv, 300); + sc8551_set_vbat_reg_th(priv, 100); + + sc8551_set_vdrop_deglitch(priv, 5000); + sc8551_set_vdrop_th(priv, 400); + + sc8551_enable_regulation(priv, false); /* test add */ + + sc8551_update_bits(priv, SC8551_REG_2E, 0x08, 0x08); + sc8551_update_bits(priv, SC8551_REG_34, 0x01, 0x01); + + return 0; +} + +/**************************************************************************** + * Name: sc8551_reset + * + * Description: + * Reset the SC8551 + * + ****************************************************************************/ + +static int sc8551_reset(FAR struct sc8551_dev_s *priv) +{ + int ret; + uint8_t val; + + /* Read current register value */ + + ret = sc8551_getreg8(priv, SC8551_REG_0B, &val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from SC8551! Error = %d\n", ret); + return ret; + } + + /* Send reset command */ + + val |= SC8551_REG_RST_ENABLE; + ret = sc8551_putreg8(priv, SC8551_REG_0B, val); + if (ret < 0) + { + baterr("ERROR: Error writing to SC8551! Error = %d\n", ret); + return ret; + } + + /* Wait a little bit to clear registers */ + + nxsig_usleep(500); + +#ifndef NOT_PMIC + /* Inherit from BQ2429, unknown useness for SC8551 */ + + /* Maybe there is a BUG in SC8551 */ + + val &= ~(SC8551_REG_RST_MASK); + ret = sc8551_putreg8(priv, SC8551_REG_01, val); + if (ret < 0) + { + baterr("ERROR: Error writing to SC8551! Error = %d\n", ret); + return ret; + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: sc8551_watchdog + * + * Description: + * Enable/Disable the SC8551 watchdog + * + ****************************************************************************/ + +static int sc8551_watchdog(FAR struct sc8551_dev_s *priv, bool enable) +{ + int ret; + uint8_t val; + + ret = sc8551_getreg8(priv, SC8551_REG_0B, &val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from SC8551! Error = %d\n", ret); + return ret; + } + + if (enable) + { + /* Hw Default is 40Sec so use that for time being */ + + val &= ~(SC8551_WATCHDOG_MASK); + val |= SC8551_WATCHDOG_30S; + } + else + { + /* 0 is disable */ + + val &= ~(SC8551_WATCHDOG_DIS_MASK); + } + + ret = sc8551_putreg8(priv, SC8551_REG_0B, val); + if (ret < 0) + { + baterr("ERROR: Error writing to SC8551! Error = %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: sc8551_sysoff + * + * Description: + * Turn the internal battery FET off in order to reduce the leakage from + * the BAT pin. Note that this disconnects the battery from the system. + * + ****************************************************************************/ + +static int sc8551_sysoff(FAR struct sc8551_dev_s *priv) +{ + #ifndef NOT_PMIC /* The chip does not support the function */ + int ret; + uint8_t value = 0; + + ret = sc8551_getreg8(priv, SC8551_REG_07, &value, 1); + batwarn("REG7 read value: 0x%08X\n", value); + value |= SC8551R7_BATFET_DISABLE; + ret |= sc8551_putreg8(priv, SC8551_REG_07, value); + + return ret; + #endif + + batwarn(" The chip does not support the function of sc8551_sysoff "); + + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_syson + * + * Description: + * Turn the internal battery FET on. + * + ****************************************************************************/ + +static int sc8551_syson(FAR struct sc8551_dev_s *priv) +{ + #ifndef NOT_PMIC /* The chip does not support the function */ + int ret; + uint8_t value = 0; + + ret = sc8551_getreg8(priv, SC8551_REG_07, &value, 1); + batwarn("REG7 read value: 0x%08X\n", value); + value &= ~SC8551R7_BATFET_DISABLE; + ret |= sc8551_putreg8(priv, SC8551_REG_07, value); + + return ret; + #endif + + batwarn(" The chip does not support the function of sc8551_syson "); + + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_en_term + * + * Description: + * Enable charger termination. When termination is disabled, there are no + * indications of the charger terminating (i.e. STAT pin or registers). + * + ****************************************************************************/ + +static int sc8551_en_term(FAR struct sc8551_dev_s *priv, bool state) +{ + #ifndef NOT_PMIC /* The chip does not support the function */ + uint8_t val; + int ret; + + ret = sc8551_getreg8(priv, SC8551_REG_05, &val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from SC8551 REG5! Error = %d\n", ret); + return ret; + } + + batwarn("en_term: REG05 %02X EN_TERM=%d\n", + val, !!(val & SC8551R5_EN_TERM)); + + /* Clear previous and set new value */ + + if (state) + { + val |= SC8551R5_EN_TERM; + } + else + { + val &= ~SC8551R5_EN_TERM; + } + + ret = sc8551_putreg8(priv, SC8551_REG_05, val); + if (ret < 0) + { + baterr("ERROR: Error writing to SC8551R5! Error = %d\n", ret); + return ret; + } + + return OK; + #endif + + batwarn("The chip does not support the function of sc8551_en_term"); + + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_en_hiz + * + * Description: + * Enable high-impedance mode. Sets the charger IC into low power standby + * mode. + * + ****************************************************************************/ + +static int sc8551_en_hiz(FAR struct sc8551_dev_s *priv, bool state) +{ + #ifndef NOT_PMIC /* The chip does not support the function */ + uint8_t val; + int ret; + + ret = sc8551_getreg8(priv, SC8551_REG_00, &val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from SC8551 REG0! Error = %d\n", ret); + return ret; + } + + batwarn("en_hiz: REG00 %02X EN_HIZ=%d\n", + val, !!(val & SC8551R1_EN_HIZ)); + + /* Clear previous and set new value */ + + if (state) + { + val |= SC8551R1_EN_HIZ; + } + else + { + val &= ~SC8551R1_EN_HIZ; + } + + ret = sc8551_putreg8(priv, SC8551_REG_00, val); + if (ret < 0) + { + baterr("ERROR: Error writing to SC8551R0! Error = %d\n", ret); + return ret; + } + + return OK; + #endif + + batwarn("The chip does not support the function of sc8551_en_hiz "); + + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_en_stat + * + * Description: + * Enable interrupts. + * + ****************************************************************************/ + +static int sc8551_en_stat(FAR struct sc8551_dev_s *priv, bool state) +{ + #ifndef NOT_PMIC /* The chip does not support the function */ + uint8_t val; + int ret; + + ret = sc8551_getreg8(priv, SC8551_REG_07, &val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from SC8551 REG7! Error = %d\n", ret); + return ret; + } + + batwarn("int stat: REG07 %02X INT_MASK1=%d INT_MASK0=%d\n", val, + !!(val & SC8551R7_INT_MASK1), !!(val & SC8551R7_INT_MASK0)); + + /* We always set or clear both interrupts together. */ + + if (state) + { + val |= (SC8551R7_INT_MASK0 | SC8551R7_INT_MASK1); + } + else + { + val &= ~(SC8551R7_INT_MASK0 | SC8551R7_INT_MASK1); + } + + ret = sc8551_putreg8(priv, SC8551_REG_07, val); + if (ret < 0) + { + baterr("ERROR: Error writing to SC8551R7! Error = %d\n", ret); + return ret; + } + + return OK; + #endif + + batwarn("The chip does not support the function of sc8551_en_stat "); + + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_setboost_otg_config + * + * Description: + * Set the device boost mode. + * + ****************************************************************************/ + +static int sc8551_setboost_otg_config(FAR struct sc8551_dev_s *priv, + bool state) +{ + #ifndef NOT_PMIC /* The chip does not support the function */ + uint8_t val; + int ret; + + ret = sc8551_getreg8(priv, SC8551_REG_01, &val, 1); + if (ret < 0) + { + baterr("ERROR: Error reading from SC8551! Error = %d\n", ret); + return ret; + } + + /* Clear previous current and set new value */ + + if (state) + { + /* Set to Boost disable Charge */ + + val = SC8551R1_OTG_CONFIG | (val & ~SC8551R1_CHG_CONFIG); + } + else + { + /* Set to Charge disable Boost */ + + val = SC8551R1_CHG_CONFIG | (val & ~SC8551R1_OTG_CONFIG); + } + + ret = sc8551_putreg8(priv, SC8551_REG_01, val); + if (ret < 0) + { + baterr("ERROR: Error writing to SC8551! Error = %d\n", ret); + return ret; + } + +#define BST_CONFIG_MASK (SC8551R1_CHG_CONFIG | SC8551R1_OTG_CONFIG) + batwarn("otg_config: REG01 %02X Boost=%d\n", val, + ((SC8551R1_OTG_CONFIG == (val & BST_CONFIG_MASK)) ? 1 : 0)); + + return OK; + #endif + + batwarn("The chip does not support the sc8551_setboost_otg_config "); + + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_state + * + * Description: + * Return the current battery management state + * + ****************************************************************************/ + +static int sc8551_state(FAR struct battery_charger_dev_s *dev, + FAR int *status) +{ + FAR struct sc8551_dev_s *priv = (FAR struct sc8551_dev_s *)dev; + uint8_t val; + bool isfault = false; + int ret; + + ret = sc8551_getreg8(priv, SC8551_REG_0D, &val, 1); + if (ret < 0) + { + *status = BATTERY_UNKNOWN; + return ret; + } + + if (ret & VBUS_INSERT) + { + priv->stat.vbus_present = true; + *status = BATTERY_CHARGING; + } + else + { + priv->stat.vbus_present = false; + *status = BATTERY_IDLE; + } + + return OK; +} + +/**************************************************************************** + * Name: sc8551_health + * + * Description: + * Return the current battery health state + * + * Note: if more than one fault happened the user needs to call this ioctl + * again to read a new fault, repeat until receive a BATTERY_HEALTH_GOOD. + * + ****************************************************************************/ + +static int sc8551_health(FAR struct battery_charger_dev_s *dev, + FAR int *health) +{ + batwarn("The chip does not support the function of sc8551_health "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_online + * + * Description: + * Return true if the battery is online + * + ****************************************************************************/ + +static int sc8551_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status) +{ + batwarn("The chip does not support the function of sc8551_online "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_powersupply + * + * Description: + * Set the Power Supply Current Limit. + * + ****************************************************************************/ + +static int sc8551_powersupply(FAR struct sc8551_dev_s *priv, int current) +{ + batwarn("The chip does not support the function of sc8551_powersupply "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_setvolt + * + * Description: + * Set the voltage level to charge the battery. Voltage value in mV. + * + ****************************************************************************/ + +static int sc8551_setvolt(FAR struct sc8551_dev_s *priv, int req_volts) +{ + batwarn("The chip does not support the function of sc8551_powersupply "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_setcurr + * + * Description: + * Set the current to charge the battery. Current value in mA. + * + ****************************************************************************/ + +static inline int sc8551_setcurr(FAR struct sc8551_dev_s *priv, + int req_current) +{ + batwarn("The chip does not support the function of sc8551_setcurr "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_voltage + * + * Description: + * Set battery charger voltage + * + ****************************************************************************/ + +static int sc8551_voltage(FAR struct battery_charger_dev_s *dev, int value) +{ + batwarn("The chip does not support the function of sc8551_voltage "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_current + * + * Description: + * Set the battery charger current rate for charging + ****************************************************************************/ + +static int sc8551_current(FAR struct battery_charger_dev_s *dev, int value) +{ + batwarn("The chip does not support the function of sc8551_current "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_input_current + * + * Description: + * Set the power-supply input current limit + * + ****************************************************************************/ + +static int sc8551_input_current(FAR struct battery_charger_dev_s *dev, + int value) +{ + batwarn("The chip does not support the function of sc8551_input_current "); + return ERROR; +} + +/**************************************************************************** + * Name: sc8551_operate + ****************************************************************************/ + +static int sc8551_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param) +{ + FAR struct sc8551_dev_s *priv = (FAR struct sc8551_dev_s *)dev; + FAR struct batio_operate_msg_s *msg = + (FAR struct batio_operate_msg_s *) param; + int op; + int value; + int ret = OK; + + sc8551_dump_regs(priv); + + op = msg->operate_type; + value = (int)msg->u32; + switch (op) + { + case BATIO_OPRTN_BOOST: + ret = sc8551_setboost_otg_config(priv, true); + break; + + case BATIO_OPRTN_CHARGE: + ret = sc8551_setboost_otg_config(priv, false); + break; + + case BATIO_OPRTN_EN_TERM: + ret = sc8551_en_term(priv, (bool)value); + break; + + case BATIO_OPRTN_HIZ: + ret = sc8551_en_hiz(priv, (bool)value); + + /* Also need to set to 100mA USB host if the battery above Vbatgd? */ + + break; + + case BATIO_OPRTN_SYSOFF: + ret = sc8551_sysoff(priv); + break; + + case BATIO_OPRTN_SYSON: + ret = sc8551_syson(priv); + break; + + case BATIO_OPRTN_RESET: + ret = sc8551_reset(priv); + break; + + case BATIO_OPRTN_WDOG: + ret = sc8551_watchdog(priv, (bool)value); + break; + + default: + baterr("Unsupported opt: 0x%X\n", op); + ret = -EINVAL; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: sc8551_initialize + * + * Description: + * Initialize the SC8551 battery driver and return an instance of the + * lower-half interface that may be used with battery_charger_register(). + * + * This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_SC8551 - And the driver must be explicitly selected. + * + * Input Parameters: + * i2c - An instance of the I2C interface to use to communicate with + * the SC8551 + * addr - The I2C address of the SC8551 (Better be 0x6B). + * frequency - The I2C frequency + * current - The input current our power-supply can offer to charger + * + * Returned Value: + * A pointer to the initialized lower-half driver instance. A NULL pointer + * is returned on a failure to initialize the SC8551 lower half. + * + ****************************************************************************/ + +FAR struct battery_charger_dev_s * + sc8551_initialize(FAR struct i2c_master_s *i2c, uint8_t addr, + uint32_t frequency, int current) +{ + FAR struct sc8551_dev_s *priv; + int ret; + + /* Initialize the SC8551 device structure */ + + priv = kmm_zalloc(sizeof(struct sc8551_dev_s)); + if (priv) + { + /* Initialize the SC8551 device structure */ + + nxsem_init(&priv->batsem, 0, 1); + priv->ops = &g_sc8551ops; + priv->i2c = i2c; + priv->addr = addr; + priv->frequency = frequency; + + /* Reset the SC8551 */ + + ret = sc8551_reset(priv); + if (ret < 0) + { + baterr("ERROR: Failed to reset the SC8551: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Disable watchdog otherwise SC8551 returns to StandAlone mode */ + + ret = sc8551_watchdog(priv, false); + if (ret < 0) + { + baterr("ERROR: Failed to disable SC8551 watchdog: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Define the current that our power supply can offer to the charger. */ + + ret = sc8551_powersupply(priv, current); + if (ret < 0) + { + baterr("ERROR: Failed to set SC8551 power supply: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Disable all interrupts. */ + + ret = sc8551_en_stat(priv, false); + if (ret < 0) + { + baterr("ERROR: Failed to disable SC8551 interrupts: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Detect the SC8551 and set part_no */ + + ret = sc8551_detect_device(priv); + if (ret < 0) + { + baterr("ERROR: Failed to detect_device: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* disable watchdog */ + + ret = sc8551_watchdog(priv, false); + if (ret < 0) + { + baterr("ERROR: Failed to disable watchdog: %d\n", ret); + kmm_free(priv); + return NULL; + } + + /* Adjust timeout to rise to threshold */ + + ret = sc8551_set_ss_timeout(priv, 100000); + if (ret < 0) + { + baterr("ERROR: Failed to Adjust timeout to \ + rise to threshold: %d\n", ret); + kmm_free(priv); + return NULL; + } + + ret = sc8551_set_sense_resistor(priv, g_sc8551_cfg.sense_r_mohm); + if (ret < 0) + { + baterr("ERROR: Failed to set sense resistor: %d\n", ret); + kmm_free(priv); + return NULL; + } + + ret = sc8551_init_protection(priv); + if (ret < 0) + { + baterr("ERROR: Failed to init protection: %d\n", ret); + kmm_free(priv); + return NULL; + } + + ret = sc8551_init_adc(priv); + if (ret < 0) + { + baterr("ERROR: Failed to init adc: %d\n", ret); + kmm_free(priv); + return NULL; + } + + ret = sc8551_init_int_src(priv); + if (ret < 0) + { + baterr("ERROR: Failed to init src: %d\n", ret); + kmm_free(priv); + return NULL; + } + + ret = sc8551_init_regulation(priv); + if (ret < 0) + { + baterr("ERROR: Failed to init regulation: %d\n", ret); + kmm_free(priv); + return NULL; + } + } + + return (FAR struct battery_charger_dev_s *)priv; +} diff --git a/drivers/power/sc8551.h b/drivers/power/sc8551.h new file mode 100644 index 00000000000..c7fab3b8485 --- /dev/null +++ b/drivers/power/sc8551.h @@ -0,0 +1,147 @@ +/**************************************************************************** + * drivers/power/sc8551.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_POWER_SC8551_H +#define __INCLUDE_NUTTX_POWER_SC8551_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct sc8551_cfg_s +{ + bool bat_ovp_disable; + bool bat_ocp_disable; + bool bat_ovp_alm_disable; + bool bat_ocp_alm_disable; + + int bat_ovp_th; + int bat_ovp_alm_th; + int bat_ocp_th; + int bat_ocp_alm_th; + + bool bus_ovp_alm_disable; + bool bus_ocp_disable; + bool bus_ocp_alm_disable; + + int bus_ovp_th; + int bus_ovp_alm_th; + int bus_ocp_th; + int bus_ocp_alm_th; + + bool bat_ucp_alm_disable; + + int bat_ucp_alm_th; + int ac_ovp_th; + + bool bat_therm_disable; + bool bus_therm_disable; + bool die_therm_disable; + + int bat_therm_th; /* in % */ + int bus_therm_th; /* in % */ + int die_therm_th; /* in degC */ + + int sense_r_mohm; +}; + +struct sc8551_stat_s +{ + int part_no; + int revision; + + int mode; + + bool batt_present; + bool vbus_present; + + bool usb_present; + bool charge_enabled; /* Register bit status */ + + /* ADC reading */ + + int vbat_volt; + int vbus_volt; + int vout_volt; + int vac_volt; + + int ibat_curr; + int ibus_curr; + + int bat_temp; + int bus_temp; + int die_temp; + + /* alarm/fault status */ + + bool bat_ovp_fault; + bool bat_ocp_fault; + bool bus_ovp_fault; + bool bus_ocp_fault; + + bool bat_ovp_alarm; + bool bat_ocp_alarm; + bool bus_ovp_alarm; + bool bus_ocp_alarm; + + bool bat_ucp_alarm; + + bool bat_therm_alarm; + bool bus_therm_alarm; + bool die_therm_alarm; + + bool bat_therm_fault; + bool bus_therm_fault; + bool die_therm_fault; + + bool therm_shutdown_flag; + bool therm_shutdown_stat; + + bool vbat_reg; + bool ibat_reg; + + int prev_alarm; + int prev_fault; + + int chg_ma; + int chg_mv; + + int charge_state; +}; + +typedef enum +{ + ADC_IBUS, + ADC_VBUS, + ADC_VAC, + ADC_VOUT, + ADC_VBAT, + ADC_IBAT, + ADC_TBUS, + ADC_TBAT, + ADC_TDIE, + ADC_MAX_NUM, +}ADC_CH; + +#endif diff --git a/drivers/power/sc8551_reg.h b/drivers/power/sc8551_reg.h new file mode 100644 index 00000000000..644677a857a --- /dev/null +++ b/drivers/power/sc8551_reg.h @@ -0,0 +1,786 @@ +/**************************************************************************** + * drivers/power/sc8551_reg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __SC8551_HEADER__ +#define __SC8551_HEADER__ + +/**************************************************************************** + + * Pre-processor Definitions + ****************************************************************************/ + +#define BAT_OVP_ALARM BIT(7) +#define BAT_OCP_ALARM BIT(6) +#define BUS_OVP_ALARM BIT(5) +#define BUS_OCP_ALARM BIT(4) +#define BAT_UCP_ALARM BIT(3) +#define VBUS_INSERT BIT(2) +#define VBAT_INSERT BIT(1) +#define ADC_DONE BIT(0) + +#define BAT_OVP_FAULT BIT(7) +#define BAT_OCP_FAULT BIT(6) +#define BUS_OVP_FAULT BIT(5) +#define BUS_OCP_FAULT BIT(4) +#define TBUS_TBAT_ALARM BIT(3) +#define TS_BAT_FAULT BIT(2) +#define TS_BUS_FAULT BIT(1) +#define TS_DIE_FAULT BIT(0) + +/* below used for comm with other module */ +#define BAT_OVP_FAULT_SHIFT 0 +#define BAT_OCP_FAULT_SHIFT 1 +#define BUS_OVP_FAULT_SHIFT 2 +#define BUS_OCP_FAULT_SHIFT 3 +#define BAT_THERM_FAULT_SHIFT 4 +#define BUS_THERM_FAULT_SHIFT 5 +#define DIE_THERM_FAULT_SHIFT 6 + +#define BAT_OVP_FAULT_MASK (1 << BAT_OVP_FAULT_SHIFT) +#define BAT_OCP_FAULT_MASK (1 << BAT_OCP_FAULT_SHIFT) +#define BUS_OVP_FAULT_MASK (1 << BUS_OVP_FAULT_SHIFT) +#define BUS_OCP_FAULT_MASK (1 << BUS_OCP_FAULT_SHIFT) +#define BAT_THERM_FAULT_MASK (1 << BAT_THERM_FAULT_SHIFT) +#define BUS_THERM_FAULT_MASK (1 << BUS_THERM_FAULT_SHIFT) +#define DIE_THERM_FAULT_MASK (1 << DIE_THERM_FAULT_SHIFT) + +#define BAT_OVP_ALARM_SHIFT 0 +#define BAT_OCP_ALARM_SHIFT 1 +#define BUS_OVP_ALARM_SHIFT 2 +#define BUS_OCP_ALARM_SHIFT 3 +#define BAT_THERM_ALARM_SHIFT 4 +#define BUS_THERM_ALARM_SHIFT 5 +#define DIE_THERM_ALARM_SHIFT 6 +#define BAT_UCP_ALARM_SHIFT 7 + +#define BAT_OVP_ALARM_MASK (1 << BAT_OVP_ALARM_SHIFT) +#define BAT_OCP_ALARM_MASK (1 << BAT_OCP_ALARM_SHIFT) +#define BUS_OVP_ALARM_MASK (1 << BUS_OVP_ALARM_SHIFT) +#define BUS_OCP_ALARM_MASK (1 << BUS_OCP_ALARM_SHIFT) +#define BAT_THERM_ALARM_MASK (1 << BAT_THERM_ALARM_SHIFT) +#define BUS_THERM_ALARM_MASK (1 << BUS_THERM_ALARM_SHIFT) +#define DIE_THERM_ALARM_MASK (1 << DIE_THERM_ALARM_SHIFT) +#define BAT_UCP_ALARM_MASK (1 << BAT_UCP_ALARM_SHIFT) + +#define VBAT_REG_STATUS_SHIFT 0 +#define IBAT_REG_STATUS_SHIFT 1 + +#define VBAT_REG_STATUS_MASK (1 << VBAT_REG_STATUS_SHIFT) +#define IBAT_REG_STATUS_MASK (1 << VBAT_REG_STATUS_SHIFT) + +/* Register 00h */ +#define SC8551_REG_00 0x00 +#define SC8551_BAT_OVP_DIS_MASK 0x80 +#define SC8551_BAT_OVP_DIS_SHIFT 7 +#define SC8551_BAT_OVP_ENABLE 0 +#define SC8551_BAT_OVP_DISABLE 1 + +#define SC8551_BAT_OVP_MASK 0x3F +#define SC8551_BAT_OVP_SHIFT 0 +#define SC8551_BAT_OVP_BASE 3500 +#define SC8551_BAT_OVP_LSB 25 + +/* Register 01h */ +#define SC8551_REG_01 0x01 +#define SC8551_BAT_OVP_ALM_DIS_MASK 0x80 +#define SC8551_BAT_OVP_ALM_DIS_SHIFT 7 +#define SC8551_BAT_OVP_ALM_ENABLE 0 +#define SC8551_BAT_OVP_ALM_DISABLE 1 + +#define SC8551_BAT_OVP_ALM_MASK 0x3F +#define SC8551_BAT_OVP_ALM_SHIFT 0 +#define SC8551_BAT_OVP_ALM_BASE 3500 +#define SC8551_BAT_OVP_ALM_LSB 25 + +/* Register 02h */ +#define SC8551_REG_02 0x02 +#define SC8551_BAT_OCP_DIS_MASK 0x80 +#define SC8551_BAT_OCP_DIS_SHIFT 7 +#define SC8551_BAT_OCP_ENABLE 0 +#define SC8551_BAT_OCP_DISABLE 1 + +#define SC8551_BAT_OCP_MASK 0x7F +#define SC8551_BAT_OCP_SHIFT 0 +#define SC8551_BAT_OCP_BASE 2000 +#define SC8551_BAT_OCP_LSB 100 + +/* Register 03h */ +#define SC8551_REG_03 0x03 +#define SC8551_BAT_OCP_ALM_DIS_MASK 0x80 +#define SC8551_BAT_OCP_ALM_DIS_SHIFT 7 +#define SC8551_BAT_OCP_ALM_ENABLE 0 +#define SC8551_BAT_OCP_ALM_DISABLE 1 + +#define SC8551_BAT_OCP_ALM_MASK 0x7F +#define SC8551_BAT_OCP_ALM_SHIFT 0 +#define SC8551_BAT_OCP_ALM_BASE 2000 +#define SC8551_BAT_OCP_ALM_LSB 100 + +/* Register 04h */ +#define SC8551_REG_04 0x04 +#define SC8551_BAT_UCP_ALM_DIS_MASK 0x80 +#define SC8551_BAT_UCP_ALM_DIS_SHIFT 7 +#define SC8551_BAT_UCP_ALM_ENABLE 0 +#define SC8551_BAT_UCP_ALM_DISABLE 1 + +#define SC8551_BAT_UCP_ALM_MASK 0x7F +#define SC8551_BAT_UCP_ALM_SHIFT 0 +#define SC8551_BAT_UCP_ALM_BASE 0 +#define SC8551_BAT_UCP_ALM_LSB 50 + +/* Register 05h */ +#define SC8551_REG_05 0x05 +#define SC8551_AC_OVP_STAT_MASK 0x80 +#define SC8551_AC_OVP_STAT_SHIFT 7 + +#define SC8551_AC_OVP_FLAG_MASK 0x40 +#define SC8551_AC_OVP_FLAG_SHIFT 6 + +#define SC8551_AC_OVP_MASK_MASK 0x20 +#define SC8551_AC_OVP_MASK_SHIFT 5 + +#define SC8551_VDROP_THRESHOLD_SET_MASK 0x10 +#define SC8551_VDROP_THRESHOLD_SET_SHIFT 4 +#define SC8551_VDROP_THRESHOLD_300MV 0 +#define SC8551_VDROP_THRESHOLD_400MV 1 + +#define SC8551_VDROP_DEGLITCH_SET_MASK 0x08 +#define SC8551_VDROP_DEGLITCH_SET_SHIFT 3 +#define SC8551_VDROP_DEGLITCH_8US 0 +#define SC8551_VDROP_DEGLITCH_5MS 1 + +#define SC8551_AC_OVP_MASK 0x07 +#define SC8551_AC_OVP_SHIFT 0 +#define SC8551_AC_OVP_BASE 11 +#define SC8551_AC_OVP_LSB 1 +#define SC8551_AC_OVP_6P5V 65 + +/* Register 06h */ +#define SC8551_REG_06 0x06 +#define SC8551_VBUS_PD_EN_MASK 0x80 +#define SC8551_VBUS_PD_EN_SHIFT 7 +#define SC8551_VBUS_PD_ENABLE 1 +#define SC8551_VBUS_PD_DISABLE 0 + +#define SC8551_BUS_OVP_MASK 0x7F +#define SC8551_BUS_OVP_SHIFT 0 +#define SC8551_BUS_OVP_BASE 6000 +#define SC8551_BUS_OVP_LSB 50 + +/* Register 07h */ +#define SC8551_REG_07 0x07 +#define SC8551_BUS_OVP_ALM_DIS_MASK 0x80 +#define SC8551_BUS_OVP_ALM_DIS_SHIFT 7 +#define SC8551_BUS_OVP_ALM_ENABLE 0 +#define SC8551_BUS_OVP_ALM_DISABLE 1 + +#define SC8551_BUS_OVP_ALM_MASK 0x7F +#define SC8551_BUS_OVP_ALM_SHIFT 0 +#define SC8551_BUS_OVP_ALM_BASE 6000 +#define SC8551_BUS_OVP_ALM_LSB 50 + +/* Register 08h */ +#define SC8551_REG_08 0x08 +#define SC8551_BUS_OCP_DIS_MASK 0x80 +#define SC8551_BUS_OCP_DIS_SHIFT 7 +#define SC8551_BUS_OCP_ENABLE 0 +#define SC8551_BUS_OCP_DISABLE 1 + +#define SC8551_IBUS_UCP_RISE_FLAG_MASK 0x40 +#define SC8551_IBUS_UCP_RISE_FLAG_SHIFT 6 + +#define SC8551_IBUS_UCP_RISE_MASK_MASK 0x20 +#define SC8551_IBUS_UCP_RISE_MASK_SHIFT 5 +#define SC8551_IBUS_UCP_RISE_MASK_ENABLE 1 +#define SC8551_IBUS_UCP_RISE_MASK_DISABLE 0 + +#define SC8551_IBUS_UCP_FALL_FLAG_MASK 0x10 +#define SC8551_IBUS_UCP_FALL_FLAG_SHIFT 4 + +#define SC8551_BUS_OCP_MASK 0x0F +#define SC8551_BUS_OCP_SHIFT 0 +#define SC8551_BUS_OCP_BASE 1000 +#define SC8551_BUS_OCP_LSB 250 + +/* Register 09h */ +#define SC8551_REG_09 0x09 +#define SC8551_BUS_OCP_ALM_DIS_MASK 0x80 +#define SC8551_BUS_OCP_ALM_DIS_SHIFT 7 +#define SC8551_BUS_OCP_ALM_ENABLE 0 +#define SC8551_BUS_OCP_ALM_DISABLE 1 + +#define SC8551_BUS_OCP_ALM_MASK 0x7F +#define SC8551_BUS_OCP_ALM_SHIFT 0 +#define SC8551_BUS_OCP_ALM_BASE 0 +#define SC8551_BUS_OCP_ALM_LSB 50 + +/* Register 0Ah */ +#define SC8551_REG_0A 0x0A +#define SC8551_TSHUT_FLAG_MASK 0x80 +#define SC8551_TSHUT_FLAG_SHIFT 7 + +#define SC8551_TSHUT_STAT_MASK 0x40 +#define SC8551_TSHUT_STAT_SHIFT 6 + +#define SC8551_VBUS_ERRORLO_STAT_MASK 0x20 +#define SC8551_VBUS_ERRORLO_STAT_SHIFT 5 + +#define SC8551_VBUS_ERRORHI_STAT_MASK 0x10 +#define SC8551_VBUS_ERRORHI_STAT_SHIFT 4 + +#define SC8551_SS_TIMEOUT_FLAG_MASK 0x08 +#define SC8551_SS_TIMEOUT_FLAG_SHIFT 3 + +#define SC8551_CONV_SWITCHING_STAT_MASK 0x04 +#define SC8551_CONV_SWITCHING_STAT_SHIFT 2 + +#define SC8551_CONV_OCP_FLAG_MASK 0x02 +#define SC8551_CONV_OCP_FLAG_SHIFT 1 + +#define SC8551_PIN_DIAG_FALL_FLAG_MASK 0x01 +#define SC8551_PIN_DIAG_FALL_FLAG_SHIFT 0 + +/* Register 0Bh */ +#define SC8551_REG_0B 0x0B +#define SC8551_REG_RST_MASK 0x80 +#define SC8551_REG_RST_SHIFT 7 +#define SC8551_REG_RST_ENABLE 1 +#define SC8551_REG_RST_DISABLE 0 + +#define SC8551_FSW_SET_MASK 0x70 +#define SC8551_FSW_SET_SHIFT 4 +#define SC8551_FSW_SET_300KHZ 0 +#define SC8551_FSW_SET_350KHZ 1 +#define SC8551_FSW_SET_400KHZ 2 +#define SC8551_FSW_SET_450KHZ 3 +#define SC8551_FSW_SET_500KHZ 4 +#define SC8551_FSW_SET_550KHZ 5 +#define SC8551_FSW_SET_600KHZ 6 +#define SC8551_FSW_SET_750KHZ 7 + +#define SC8551_WD_TIMEOUT_FLAG_MASK 0x08 +#define SC8551_WD_TIMEOUT_SHIFT 3 + +#define SC8551_WATCHDOG_DIS_MASK 0x04 +#define SC8551_WATCHDOG_DIS_SHIFT 2 +#define SC8551_WATCHDOG_ENABLE 0 +#define SC8551_WATCHDOG_DISABLE 1 + +#define SC8551_WATCHDOG_MASK 0x03 +#define SC8551_WATCHDOG_SHIFT 0 +#define SC8551_WATCHDOG_0P5S 0 +#define SC8551_WATCHDOG_1S 1 +#define SC8551_WATCHDOG_5S 2 +#define SC8551_WATCHDOG_30S 3 + +/* Register 0Ch */ +#define SC8551_REG_0C 0x0C +#define SC8551_CHG_EN_MASK 0x80 +#define SC8551_CHG_EN_SHIFT 7 +#define SC8551_CHG_ENABLE 1 +#define SC8551_CHG_DISABLE 0 + +#define SC8551_MS_MASK 0x60 +#define SC8551_MS_SHIFT 5 +#define SC8551_MS_STANDALONE 0 +#define SC8551_MS_SLAVE 1 +#define SC8551_MS_MASTER 2 + +#define SC8551_FREQ_SHIFT_MASK 0x18 +#define SC8551_FREQ_SHIFT_SHIFT 3 +#define SC8551_FREQ_SHIFT_NORMINAL 0 +#define SC8551_FREQ_SHIFT_POSITIVE10 1 +#define SC8551_FREQ_SHIFT_NEGATIVE10 2 +#define SC8551_FREQ_SHIFT_SPREAD_SPECTRUM 3 + +#define SC8551_TSBUS_DIS_MASK 0x04 +#define SC8551_TSBUS_DIS_SHIFT 2 +#define SC8551_TSBUS_ENABLE 0 +#define SC8551_TSBUS_DISABLE 1 + +#define SC8551_TSBAT_DIS_MASK 0x02 +#define SC8551_TSBAT_DIS_SHIFT 1 +#define SC8551_TSBAT_ENABLE 0 +#define SC8551_TSBAT_DISABLE 1 + +/* Register 0Dh */ +#define SC8551_REG_0D 0x0D +#define SC8551_BAT_OVP_ALM_STAT_MASK 0x80 +#define SC8551_BAT_OVP_ALM_STAT_SHIFT 7 + +#define SC8551_BAT_OCP_ALM_STAT_MASK 0x40 +#define SC8551_BAT_OCP_ALM_STAT_SHIFT 6 + +#define SC8551_BUS_OVP_ALM_STAT_MASK 0x20 +#define SC8551_BUS_OVP_ALM_STAT_SHIFT 5 + +#define SC8551_BUS_OCP_ALM_STAT_MASK 0x10 +#define SC8551_BUS_OCP_ALM_STAT_SHIFT 4 + +#define SC8551_BAT_UCP_ALM_STAT_MASK 0x08 +#define SC8551_BAT_UCP_ALM_STAT_SHIFT 3 + +#define SC8551_ADAPTER_INSERT_STAT_MASK 0x04 +#define SC8551_ADAPTER_INSERT_STAT_SHIFT 2 + +#define SC8551_VBAT_INSERT_STAT_MASK 0x02 +#define SC8551_VBAT_INSERT_STAT_SHIFT 1 + +#define SC8551_ADC_DONE_STAT_MASK 0x01 +#define SC8551_ADC_DONE_STAT_SHIFT 0 +#define SC8551_ADC_DONE_STAT_COMPLETE 1 +#define SC8551_ADC_DONE_STAT_NOTCOMPLETE 0 + +/* Register 0Eh */ +#define SC8551_REG_0E 0x0E +#define SC8551_BAT_OVP_ALM_FLAG_MASK 0x80 +#define SC8551_BAT_OVP_ALM_FLAG_SHIFT 7 + +#define SC8551_BAT_OCP_ALM_FLAG_MASK 0x40 +#define SC8551_BAT_OCP_ALM_FLAG_SHIFT 6 + +#define SC8551_BUS_OVP_ALM_FLAG_MASK 0x20 +#define SC8551_BUS_OVP_ALM_FLAG_SHIFT 5 + +#define SC8551_BUS_OCP_ALM_FLAG_MASK 0x10 +#define SC8551_BUS_OCP_ALM_FLAG_SHIFT 4 + +#define SC8551_BAT_UCP_ALM_FLAG_MASK 0x08 +#define SC8551_BAT_UCP_ALM_FLAG_SHIFT 3 + +#define SC8551_ADAPTER_INSERT_FLAG_MASK 0x04 +#define SC8551_ADAPTER_INSERT_FLAG_SHIFT 2 + +#define SC8551_VBAT_INSERT_FLAG_MASK 0x02 +#define SC8551_VBAT_INSERT_FLAG_SHIFT 1 + +#define SC8551_ADC_DONE_FLAG_MASK 0x01 +#define SC8551_ADC_DONE_FLAG_SHIFT 0 +#define SC8551_ADC_DONE_FLAG_COMPLETE 1 +#define SC8551_ADC_DONE_FLAG_NOTCOMPLETE 0 + +/* Register 0Fh */ +#define SC8551_REG_0F 0x0F +#define SC8551_BAT_OVP_ALM_MASK_MASK 0x80 +#define SC8551_BAT_OVP_ALM_MASK_SHIFT 7 +#define SC8551_BAT_OVP_ALM_MASK_ENABLE 1 +#define SC8551_BAT_OVP_ALM_MASK_DISABLE 0 + +#define SC8551_BAT_OCP_ALM_MASK_MASK 0x40 +#define SC8551_BAT_OCP_ALM_MASK_SHIFT 6 +#define SC8551_BAT_OCP_ALM_MASK_ENABLE 1 +#define SC8551_BAT_OCP_ALM_MASK_DISABLE 0 + +#define SC8551_BUS_OVP_ALM_MASK_MASK 0x20 +#define SC8551_BUS_OVP_ALM_MASK_SHIFT 5 +#define SC8551_BUS_OVP_ALM_MASK_ENABLE 1 +#define SC8551_BUS_OVP_ALM_MASK_DISABLE 0 + +#define SC8551_BUS_OCP_ALM_MASK_MASK 0x10 +#define SC8551_BUS_OCP_ALM_MASK_SHIFT 4 +#define SC8551_BUS_OCP_ALM_MASK_ENABLE 1 +#define SC8551_BUS_OCP_ALM_MASK_DISABLE 0 + +#define SC8551_BAT_UCP_ALM_MASK_MASK 0x08 +#define SC8551_BAT_UCP_ALM_MASK_SHIFT 3 +#define SC8551_BAT_UCP_ALM_MASK_ENABLE 1 +#define SC8551_BAT_UCP_ALM_MASK_DISABLE 0 + +#define SC8551_ADAPTER_INSERT_MASK_MASK 0x04 +#define SC8551_ADAPTER_INSERT_MASK_SHIFT 2 +#define SC8551_ADAPTER_INSERT_MASK_ENABLE 1 +#define SC8551_ADAPTER_INSERT_MASK_DISABLE 0 + +#define SC8551_VBAT_INSERT_MASK_MASK 0x02 +#define SC8551_VBAT_INSERT_MASK_SHIFT 1 +#define SC8551_VBAT_INSERT_MASK_ENABLE 1 +#define SC8551_VBAT_INSERT_MASK_DISABLE 0 + +#define SC8551_ADC_DONE_MASK_MASK 0x01 +#define SC8551_ADC_DONE_MASK_SHIFT 0 +#define SC8551_ADC_DONE_MASK_ENABLE 1 +#define SC8551_ADC_DONE_MASK_DISABLE 0 + +/* Register 10h */ +#define SC8551_REG_10 0x10 +#define SC8551_BAT_OVP_FLT_STAT_MASK 0x80 +#define SC8551_BAT_OVP_FLT_STAT_SHIFT 7 + +#define SC8551_BAT_OCP_FLT_STAT_MASK 0x40 +#define SC8551_BAT_OCP_FLT_STAT_SHIFT 6 + +#define SC8551_BUS_OVP_FLT_STAT_MASK 0x20 +#define SC8551_BUS_OVP_FLT_STAT_SHIFT 5 + +#define SC8551_BUS_OCP_FLT_STAT_MASK 0x10 +#define SC8551_BUS_OCP_FLT_STAT_SHIFT 4 + +#define SC8551_TSBUS_TSBAT_ALM_STAT_MASK 0x08 +#define SC8551_TSBUS_TSBAT_ALM_STAT_SHIFT 3 + +#define SC8551_TSBAT_FLT_STAT_MASK 0x04 +#define SC8551_TSBAT_FLT_STAT_SHIFT 2 + +#define SC8551_TSBUS_FLT_STAT_MASK 0x02 +#define SC8551_TSBUS_FLT_STAT_SHIFT 1 + +#define SC8551_TDIE_ALM_STAT_MASK 0x01 +#define SC8551_TDIE_ALM_STAT_SHIFT 0 + +/* Register 11h */ +#define SC8551_REG_11 0x11 +#define SC8551_BAT_OVP_FLT_FLAG_MASK 0x80 +#define SC8551_BAT_OVP_FLT_FLAG_SHIFT 7 + +#define SC8551_BAT_OCP_FLT_FLAG_MASK 0x40 +#define SC8551_BAT_OCP_FLT_FLAG_SHIFT 6 + +#define SC8551_BUS_OVP_FLT_FLAG_MASK 0x20 +#define SC8551_BUS_OVP_FLT_FLAG_SHIFT 5 + +#define SC8551_BUS_OCP_FLT_FLAG_MASK 0x10 +#define SC8551_BUS_OCP_FLT_FLAG_SHIFT 4 + +#define SC8551_TSBUS_TSBAT_ALM_FLAG_MASK 0x08 +#define SC8551_TSBUS_TSBAT_ALM_FLAG_SHIFT 3 + +#define SC8551_TSBAT_FLT_FLAG_MASK 0x04 +#define SC8551_TSBAT_FLT_FLAG_SHIFT 2 + +#define SC8551_TSBUS_FLT_FLAG_MASK 0x02 +#define SC8551_TSBUS_FLT_FLAG_SHIFT 1 + +#define SC8551_TDIE_ALM_FLAG_MASK 0x01 +#define SC8551_TDIE_ALM_FLAG_SHIFT 0 + +/* Register 12h */ +#define SC8551_REG_12 0x12 +#define SC8551_BAT_OVP_FLT_MASK_MASK 0x80 +#define SC8551_BAT_OVP_FLT_MASK_SHIFT 7 +#define SC8551_BAT_OVP_FLT_MASK_ENABLE 1 +#define SC8551_BAT_OVP_FLT_MASK_DISABLE 0 + +#define SC8551_BAT_OCP_FLT_MASK_MASK 0x40 +#define SC8551_BAT_OCP_FLT_MASK_SHIFT 6 +#define SC8551_BAT_OCP_FLT_MASK_ENABLE 1 +#define SC8551_BAT_OCP_FLT_MASK_DISABLE 0 + +#define SC8551_BUS_OVP_FLT_MASK_MASK 0x20 +#define SC8551_BUS_OVP_FLT_MASK_SHIFT 5 +#define SC8551_BUS_OVP_FLT_MASK_ENABLE 1 +#define SC8551_BUS_OVP_FLT_MASK_DISABLE 0 + +#define SC8551_BUS_OCP_FLT_MASK_MASK 0x10 +#define SC8551_BUS_OCP_FLT_MASK_SHIFT 4 +#define SC8551_BUS_OCP_FLT_MASK_ENABLE 1 +#define SC8551_BUS_OCP_FLT_MASK_DISABLE 0 + +#define SC8551_TSBUS_TSBAT_ALM_MASK_MASK 0x08 +#define SC8551_TSBUS_TSBAT_ALM_MASK_SHIFT 3 +#define SC8551_TSBUS_TSBAT_ALM_MASK_ENABLE 1 +#define SC8551_TSBUS_TSBAT_ALM_MASK_DISABLE 0 + +#define SC8551_TSBAT_FLT_MASK_MASK 0x04 +#define SC8551_TSBAT_FLT_MASK_SHIFT 2 +#define SC8551_TSBAT_FLT_MASK_ENABLE 1 +#define SC8551_TSBAT_FLT_MASK_DISABLE 0 + +#define SC8551_TSBUS_FLT_MASK_MASK 0x02 +#define SC8551_TSBUS_FLT_MASK_SHIFT 1 +#define SC8551_TSBUS_FLT_MASK_ENABLE 1 +#define SC8551_TSBUS_FLT_MASK_DISABLE 0 + +#define SC8551_TDIE_ALM_MASK_MASK 0x01 +#define SC8551_TDIE_ALM_MASK_SHIFT 0 +#define SC8551_TDIE_ALM_MASK_ENABLE 1 +#define SC8551_TDIE_ALM_MASK_DISABLE 0 + +/* Register 13h */ +#define SC8551_REG_13 0x13 +#define SC8551_DEV_ID_MASK 0x0F +#define SC8551_DEV_ID_SHIFT 0 + +/* Register 14h */ +#define SC8551_REG_14 0x14 +#define SC8551_ADC_EN_MASK 0x80 +#define SC8551_ADC_EN_SHIFT 7 +#define SC8551_ADC_ENABLE 1 +#define SC8551_ADC_DISABLE 0 + +#define SC8551_ADC_RATE_MASK 0x40 +#define SC8551_ADC_RATE_SHIFT 6 +#define SC8551_ADC_RATE_CONTINOUS 0 +#define SC8551_ADC_RATE_ONESHOT 1 + +#define SC8551_IBUS_ADC_DIS_MASK 0x01 +#define SC8551_IBUS_ADC_DIS_SHIFT 0 +#define SC8551_IBUS_ADC_ENABLE 0 +#define SC8551_IBUS_ADC_DISABLE 1 + +/* Register 15h */ +#define SC8551_REG_15 0x15 +#define SC8551_VBUS_ADC_DIS_MASK 0x80 +#define SC8551_VBUS_ADC_DIS_SHIFT 7 +#define SC8551_VBUS_ADC_ENABLE 0 +#define SC8551_VBUS_ADC_DISABLE 1 + +#define SC8551_VAC_ADC_DIS_MASK 0x40 +#define SC8551_VAC_ADC_DIS_SHIFT 6 +#define SC8551_VAC_ADC_ENABLE 0 +#define SC8551_VAC_ADC_DISABLE 1 + +#define SC8551_VOUT_ADC_DIS_MASK 0x20 +#define SC8551_VOUT_ADC_DIS_SHIFT 5 +#define SC8551_VOUT_ADC_ENABLE 0 +#define SC8551_VOUT_ADC_DISABLE 1 + +#define SC8551_VBAT_ADC_DIS_MASK 0x10 +#define SC8551_VBAT_ADC_DIS_SHIFT 4 +#define SC8551_VBAT_ADC_ENABLE 0 +#define SC8551_VBAT_ADC_DISABLE 1 + +#define SC8551_IBAT_ADC_DIS_MASK 0x08 +#define SC8551_IBAT_ADC_DIS_SHIFT 3 +#define SC8551_IBAT_ADC_ENABLE 0 +#define SC8551_IBAT_ADC_DISABLE 1 + +#define SC8551_TSBUS_ADC_DIS_MASK 0x04 +#define SC8551_TSBUS_ADC_DIS_SHIFT 2 +#define SC8551_TSBUS_ADC_ENABLE 0 +#define SC8551_TSBUS_ADC_DISABLE 1 + +#define SC8551_TSBAT_ADC_DIS_MASK 0x02 +#define SC8551_TSBAT_ADC_DIS_SHIFT 1 +#define SC8551_TSBAT_ADC_ENABLE 0 +#define SC8551_TSBAT_ADC_DISABLE 1 + +#define SC8551_TDIE_ADC_DIS_MASK 0x01 +#define SC8551_TDIE_ADC_DIS_SHIFT 0 +#define SC8551_TDIE_ADC_ENABLE 0 +#define SC8551_TDIE_ADC_DISABLE 1 + +/* Register 16h */ +#define SC8551_REG_16 0x16 +#define SC8551_IBUS_POL_H_MASK 0x0F +#define SC8551_IBUS_ADC_LSB 1.5625 + +/* Register 17h */ +#define SC8551_REG_17 0x17 +#define SC8551_IBUS_POL_L_MASK 0xFF + +/* Register 18h */ +#define SC8551_REG_18 0x18 +#define SC8551_VBUS_POL_H_MASK 0x0F +#define SC8551_VBUS_ADC_LSB 3.75 + +/* Register 19h */ +#define SC8551_REG_19 0x19 +#define SC8551_VBUS_POL_L_MASK 0xFF + +/* Register 1Ah */ +#define SC8551_REG_1A 0x1A +#define SC8551_VAC_POL_H_MASK 0x0F +#define SC8551_VAC_ADC_LSB 5 + +/* Register 1Bh */ +#define SC8551_REG_1B 0x1B +#define SC8551_VAC_POL_L_MASK 0xFF + +/* Register 1Ch */ +#define SC8551_REG_1C 0x1C +#define SC8551_VOUT_POL_H_MASK 0x0F +#define SC8551_VOUT_ADC_LSB 1.25 + +/* Register 1Dh */ +#define SC8551_REG_1D 0x1D +#define SC8551_VOUT_POL_L_MASK 0x0F + +/* Register 1Eh */ +#define SC8551_REG_1E 0x1E +#define SC8551_VBAT_POL_H_MASK 0x0F +#define SC8551_VBAT_ADC_LSB 1.25*1.005 + +/* Register 1Fh */ +#define SC8551_REG_1F 0x1F +#define SC8551_VBAT_POL_L_MASK 0xFF + +/* Register 20h */ +#define SC8551_REG_20 0x20 +#define SC8551_IBAT_POL_H_MASK 0x0F +#define SC8551_IBAT_ADC_LSB 3.125 + +/* Register 21h */ +#define SC8551_REG_21 0x21 +#define SC8551_IBAT_POL_L_MASK 0xFF + +/* Register 22h */ +#define SC8551_REG_22 0x22 +#define SC8551_TSBUS_POL_H_MASK 0x03 +#define SC8551_TSBUS_ADC_LSB 0.09766 + +/* Register 23h */ +#define SC8551_REG_23 0x23 +#define SC8551_TSBUS_POL_L_MASK 0xFF + +/* Register 24h */ +#define SC8551_REG_24 0x24 +#define SC8551_TSBAT_POL_H_MASK 0x03 +#define SC8551_TSBAT_ADC_LSB 0.09766 + +/* Register 25h */ +#define SC8551_REG_25 0x25 +#define SC8551_TSBAT_POL_L_MASK 0xFF + +/* Register 26h */ +#define SC8551_REG_26 0x26 +#define SC8551_TDIE_POL_H_MASK 0x01 +#define SC8551_TDIE_ADC_LSB 0.5 + +/* Register 27h */ +#define SC8551_REG_27 0x27 +#define SC8551_TDIE_POL_L_MASK 0xFF + +/* Register 28h */ +#define SC8551_REG_28 0x28 +#define SC8551_TSBUS_FLT1_MASK 0xFF +#define SC8551_TSBUS_FLT1_SHIFT 0 +#define SC8551_TSBUS_FLT1_BASE 0 +#define SC8551_TSBUS_FLT1_LSB 0.19531 + +/* Register 29h */ +#define SC8551_REG_29 0x29 +#define SC8551_TSBAT_FLT0_MASK 0xFF +#define SC8551_TSBAT_FLT0_SHIFT 0 +#define SC8551_TSBAT_FLT0_BASE 0 +#define SC8551_TSBAT_FLT0_LSB 0.19531 + +/* Register 2Ah */ +#define SC8551_REG_2A 0x2A +#define SC8551_TDIE_ALM_MASK 0xFF +#define SC8551_TDIE_ALM_SHIFT 0 +#define SC8551_TDIE_ALM_BASE 25 +#define SC8551_TDIE_ALM_LSB 5 /* careful multiply is used for calc */ + +/* Register 2Bh */ +#define SC8551_REG_2B 0x2B +#define SC8551_SS_TIMEOUT_SET_MASK 0xE0 +#define SC8551_SS_TIMEOUT_SET_SHIFT 5 +#define SC8551_SS_TIMEOUT_DISABLE 0 +#define SC8551_SS_TIMEOUT_12P5MS 1 +#define SC8551_SS_TIMEOUT_25MS 2 +#define SC8551_SS_TIMEOUT_50MS 3 +#define SC8551_SS_TIMEOUT_100MS 4 +#define SC8551_SS_TIMEOUT_400MS 5 +#define SC8551_SS_TIMEOUT_1500MS 6 +#define SC8551_SS_TIMEOUT_100000MS 7 + +#define SC8551_EN_REGULATION_MASK 0x10 +#define SC8551_EN_REGULATION_SHIFT 4 +#define SC8551_EN_REGULATION_ENABLE 1 +#define SC8551_EN_REGULATION_DISABLE 0 + +#define SC8551_VOUT_OVP_DIS_MASK 0x08 +#define SC8551_VOUT_OVP_DIS_SHIFT 3 +#define SC8551_VOUT_OVP_ENABLE 1 +#define SC8551_VOUT_OVP_DISABLE 0 + +#define SC8551_IBUS_UCP_RISE_TH_MASK 0x04 +#define SC8551_IBUS_UCP_RISE_TH_SHIFT 2 +#define SC8551_IBUS_UCP_RISE_150MA 0 +#define SC8551_IBUS_UCP_RISE_250MA 1 + +#define SC8551_SET_IBAT_SNS_RES_MASK 0x02 +#define SC8551_SET_IBAT_SNS_RES_SHIFT 1 +#define SC8551_SET_IBAT_SNS_RES_2MHM 0 +#define SC8551_SET_IBAT_SNS_RES_5MHM 1 + +#define SC8551_VAC_PD_EN_MASK 0x01 +#define SC8551_VAC_PD_EN_SHIFT 0 +#define SC8551_VAC_PD_ENABLE 1 +#define SC8551_VAC_PD_DISABLE 0 + +/* Register 2Ch */ +#define SC8551_REG_2C 0x2C +#define SC8551_IBAT_REG_MASK 0xC0 +#define SC8551_IBAT_REG_SHIFT 6 +#define SC8551_IBAT_REG_200MA 0 +#define SC8551_IBAT_REG_300MA 1 +#define SC8551_IBAT_REG_400MA 2 +#define SC8551_IBAT_REG_500MA 3 +#define SC8551_VBAT_REG_MASK 0x30 +#define SC8551_VBAT_REG_SHIFT 4 +#define SC8551_VBAT_REG_50MV 0 +#define SC8551_VBAT_REG_100MV 1 +#define SC8551_VBAT_REG_150MV 2 +#define SC8551_VBAT_REG_200MV 3 + +#define SC8551_VBAT_REG_ACTIVE_STAT_MASK 0x08 +#define SC8551_IBAT_REG_ACTIVE_STAT_MASK 0x04 +#define SC8551_VDROP_OVP_ACTIVE_STAT_MASK 0x02 +#define SC8551_VOUT_OVP_ACTIVE_STAT_MASK 0x01 + +#define SC8551_REG_2D 0x2D +#define SC8551_VBAT_REG_ACTIVE_FLAG_MASK 0x80 +#define SC8551_IBAT_REG_ACTIVE_FLAG_MASK 0x40 +#define SC8551_VDROP_OVP_FLAG_MASK 0x20 +#define SC8551_VOUT_OVP_FLAG_MASK 0x10 +#define SC8551_VBAT_REG_ACTIVE_MASK_MASK 0x08 +#define SC8551_IBAT_REG_ACTIVE_MASK_MASK 0x04 +#define SC8551_VDROP_OVP_MASK_MASK 0x02 +#define SC8551_VOUT_OVP_MASK_MASK 0x01 + +#define SC8551_REG_2E 0x2E +#define SC8551_IBUS_LOW_DG_MASK 0x08 +#define SC8551_IBUS_LOW_DG_SHIFT 3 +#define SC8551_IBUS_LOW_DG_10US 0 +#define SC8551_IBUS_LOW_DG_5MS 1 + +#define SC8551_REG_2F 0x2F +#define SC8551_PMID2OUT_UVP_FLAG_MASK 0x08 +#define SC8551_PMID2OUT_OVP_FLAG_MASK 0x04 +#define SC8551_PMID2OUT_UVP_STAT_MASK 0x02 +#define SC8551_PMID2OUT_OVP_STAT_MASK 0x01 + +#define SC8551_REG_30 0x30 +#define SC8551_IBUS_REG_EN_MASK 0x80 +#define SC8551_IBUS_REG_EN_SHIFT 7 +#define SC8551_IBUS_REG_ENABLE 1 +#define SC8551_IBUS_REG_DISABLE 0 +#define SC8551_IBUS_REG_ACTIVE_STAT_MASK 0x40 +#define SC8551_IBUS_REG_ACTIVE_FLAG_MASK 0x20 +#define SC8551_IBUS_REG_ACTIVE_MASK_MASK 0x10 +#define SC8551_IBUS_REG_ACTIVE_MASK_SHIFT 4 +#define SC8551_IBUS_REG_ACTIVE_NOT_MASK 0 +#define SC8551_IBUS_REG_ACTIVE_MASK 1 +#define SC8551_IBUS_REG_MASK 0x0F +#define SC8551_IBUS_REG_SHIFT 0 +#define SC8551_IBUS_REG_BASE 1000 +#define SC8551_IBUS_REG_LSB 250 + +#define SC8551_REG_31 0x31 +#define SC8551_CHARGE_MODE_MASK 0x01 +#define SC8551_CHARGE_MODE_SHIFT 0 +#define SC8551_CHARGE_MODE_2_1 0 +#define SC8551_CHARGE_MODE_1_1 1 + +#define SC8551_REG_34 0x34 +#define SC8551_REG_MAX 0x35 + +#endif diff --git a/include/nuttx/power/battery_charger.h b/include/nuttx/power/battery_charger.h index af3dc1db660..907c2509790 100644 --- a/include/nuttx/power/battery_charger.h +++ b/include/nuttx/power/battery_charger.h @@ -324,6 +324,44 @@ FAR struct battery_charger_dev_s *bq25618_initialize( int current); #endif +/**************************************************************************** + * Name: sc8551_initialize + * + * Description: + * Initialize the SC8551 (pump charger) charger driver and return + * an instance of the lower-half interface that may be used with + * battery_charger_register(). + * + * This is for: + * SC8551 + * + * This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery charger driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_SC8551 - And the driver must be explicitly selected. + * + * Input Parameters: + * i2c - An instance of the I2C interface to use to communicate with + * the SC8551 + * addr - The I2C address of the SC8551 (Better be 0x66). + * frequency - The I2C frequency + * current - The input current our power-supply can offer to charger + * + * Returned Value: + * A pointer to the initialized battery driver instance. A NULL pointer + * is returned on a failure to initialize the SC8551 lower half. + * + ****************************************************************************/ + +#if defined(CONFIG_I2C) && defined(CONFIG_I2C_SC8551) + +struct i2c_master_s; +FAR struct battery_charger_dev_s * + sc8551_initialize(FAR struct i2c_master_s *i2c, uint8_t addr, + uint32_t frequency, int current); +#endif + #undef EXTERN #ifdef __cplusplus }