Files
nuttx/drivers/power/sc8551.c
T
zhangguoliang a87fbef0f1 feat: charge: initialize pump charger sc8551a driver
CHAMPION-25

Change-Id: I32bf77d04fc5c67f52dcc7ec8081a3feb4b08795
Signed-off-by: zhangguoliang <zhangguoliang3@xiaomi.com>
2021-09-22 19:13:02 +08:00

1946 lines
53 KiB
C

/****************************************************************************
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/signal.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/power/battery_charger.h>
#include <nuttx/power/battery_ioctl.h>
#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 <I2C write address> ACK <Reg address> ACK
* REPEATED-START <I2C read address> 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, &regaddr, 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 <I2C write address> ACK <Reg address> 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;
}