2592 lines
66 KiB
C
2592 lines
66 KiB
C
#include <linux/kernel.h>
|
|
#include <linux/device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/types.h>
|
|
#include <linux/device.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/pinctrl/consumer.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/debugfs.h>
|
|
#include <mtk_charger_intf.h>
|
|
|
|
/* NU2105 Registers */
|
|
#define NU2105_REG_BAT_OVP (0x00)
|
|
#define NU2105_REG_BAT_OVP_ALM (0x01)
|
|
#define NU2105_REG_BAT_OCP (0x02)
|
|
#define NU2105_REG_BAT_OCP_ALM (0x03)
|
|
#define NU2105_REG_BAT_UCP_ALM (0x04)
|
|
#define NU2105_REG_AC_PROTECTION (0x05)
|
|
#define NU2105_REG_BUS_OVP (0x06)
|
|
#define NU2105_REG_BUS_OVP_ALM (0x07)
|
|
#define NU2105_REG_BUS_OCP_UCP (0x08)
|
|
#define NU2105_REG_BUS_OCP_ALM (0x09)
|
|
#define NU2105_REG_CONVERTER_STATE (0x0A)
|
|
#define NU2105_REG_CONTROL (0x0B)
|
|
#define NU2105_REG_CHRG_CTRL (0x0C)
|
|
#define NU2105_REG_INT_STAT (0x0D)
|
|
#define NU2105_REG_INT_FLAG (0x0E)
|
|
#define NU2105_REG_INT_MASK (0x0F)
|
|
#define NU2105_REG_FLT_STAT (0x10)
|
|
#define NU2105_REG_FLT_FLAG (0x11)
|
|
#define NU2105_REG_FLT_MASK (0x12)
|
|
#define NU2105_REG_PART_INFO (0x13)
|
|
#define NU2105_REG_ADC_CTRL (0x14)
|
|
#define NU2105_REG_ADC_FN_DISABLE (0x15)
|
|
#define NU2105_REG_IBUS_ADC1 (0x16)
|
|
#define NU2105_REG_IBUS_ADC0 (0x17)
|
|
#define NU2105_REG_VBUS_ADC1 (0x18)
|
|
#define NU2105_REG_VBUS_ADC0 (0x19)
|
|
#define NU2105_REG_VAC_ADC1 (0x1A)
|
|
#define NU2105_REG_VAC_ADC0 (0x1B)
|
|
#define NU2105_REG_VOUT_ADC1 (0x1C)
|
|
#define NU2105_REG_VOUT_ADC0 (0x1D)
|
|
#define NU2105_REG_VBAT_ADC1 (0x1E)
|
|
#define NU2105_REG_VBAT_ADC0 (0x1F)
|
|
#define NU2105_REG_IBAT_ADC1 (0x20)
|
|
#define NU2105_REG_IBAT_ADC0 (0x21)
|
|
#define NU2105_REG_TSBUS_ADC1 (0x22)
|
|
#define NU2105_REG_TSBUS_ADC0 (0x23)
|
|
#define NU2105_REG_TSBAT_ADC1 (0x24)
|
|
#define NU2105_REG_TSBAT_ADC0 (0x25)
|
|
#define NU2105_REG_TDIE_ADC1 (0x26)
|
|
#define NU2105_REG_TDIE_ADC0 (0x27)
|
|
#define NU2105_REG_TSBUS_FLT1 (0x28)
|
|
#define NU2105_REG_TSBAT_FLT0 (0x29)
|
|
#define NU2105_REG_TDIE_ALM (0x2A)
|
|
#define NU2105_REG_REG_CTRL (0x2B)
|
|
#define NU2105_REG_REG_THRESHOLD (0x2C)
|
|
#define NU2105_REG_REG_FLAG_MASK (0x2D)
|
|
#define NU2105_REG_DEGLITCH (0x2E)
|
|
#define NU2105_REG_CHGMODE (0x2F)
|
|
|
|
/* NU2105_REG_BAT_OVP */
|
|
#define NU2105_BAT_OVP_DIS_MASK BIT(7)
|
|
#define NU2105_BAT_OVP_DIS_SHIFT (7)
|
|
#define NU2105_BAT_OVP_MASK (0x3F)
|
|
|
|
/* NU2105_REG_BAT_OVP_ALM */
|
|
#define NU2105_BAT_OVP_ALM_DIS_MASK BIT(7)
|
|
#define NU2105_BAT_OVP_ALM_DIS_SHIFT (7)
|
|
#define NU2105_BAT_OVP_ALM_MASK (0x3F)
|
|
|
|
/* NU2105_REG_BAT_OCP */
|
|
#define NU2105_BAT_OCP_DIS_MASK BIT(7)
|
|
#define NU2105_BAT_OCP_DIS_SHIFT (7)
|
|
#define NU2105_BAT_OCP_MASK (0x7F)
|
|
|
|
/* NU2105_REG_BAT_OCP_ALM */
|
|
#define NU2105_BAT_OCP_ALM_DIS_MASK BIT(7)
|
|
#define NU2105_BAT_OCP_ALM_DIS_SHIFT (7)
|
|
#define NU2105_BAT_OCP_ALM_MASK (0x7F)
|
|
|
|
/* NU2105_REG_BAT_UCP_ALM */
|
|
#define NU2105_BAT_UCP_ALM_DIS_MASK BIT(7)
|
|
#define NU2105_BAT_UCP_ALM_DIS_SHIFT (7)
|
|
#define NU2105_BAT_UCP_ALM_MASK (0x7F)
|
|
|
|
/* NU2105_REG_AC_PROTECTION */
|
|
#define NU2105_AC_OVP_STAT_MASK BIT(7)
|
|
#define NU2105_AC_OVP_FLAG_MASK BIT(6)
|
|
#define NU2105_AC_OVP_MASK (0x07)
|
|
|
|
/* NU2105_REG_BUS_OVP */
|
|
#define NU2105_BUS_OVP_MASK (0x7F)
|
|
|
|
/* NU2105_REG_BUS_OVP_ALM */
|
|
#define NU2105_BUS_OVP_ALM_MASK (0x7F)
|
|
#define NU2105_BUS_OVP_ALM_DIS_MASK BIT(7)
|
|
#define NU2105_BUS_OVP_ALM_DIS_SHIFT (7)
|
|
|
|
/* NU2105_REG_BUS_OCP_UCP */
|
|
#define NU2105_IBUS_UCP_RISE_FLAG_MASK BIT(6)
|
|
#define NU2105_IBUS_UCP_FALL_FLAG_MASK BIT(4)
|
|
#define NU2105_BUS_OCP_MASK (0x0F)
|
|
|
|
/* NU2105_REG_BUS_OCP_ALM */
|
|
#define NU2105_BUS_OCP_ALM_MASK (0x7F)
|
|
|
|
/* NU2105_REG_CONVERTER_STATE */
|
|
#define NU2105_TSHUT_FLAG_MASK BIT(7)
|
|
#define NU2105_TSHUT_STAT_MASK BIT(6)
|
|
#define NU2105_VBUS_ERRORLO_STAT_MASK BIT(5)
|
|
#define NU2105_VBUS_ERRORHI_STAT_MASK BIT(4)
|
|
#define NU2105_SS_TIMEOUT_FLAG_MASK BIT(3)
|
|
#define NU2105_CONV_SWITCHING_STAT_MASK BIT(2)
|
|
#define NU2105_CONV_OCP_FLAG_MASK BIT(1)
|
|
#define NU2105_PIN_DIAG_FAIL_FLAG_MASK BIT(0)
|
|
|
|
/* NU2105_REG_CONTROL */
|
|
#define NU2105_FSW_SET_MASK (0x70)
|
|
#define NU2105_FSW_SET_SHIFT (4)
|
|
#define NU2105_WD_TIMEOUT_FLAG_MASK BIT(3)
|
|
#define NU2105_WATCHDOG_DIS_MASK BIT(2)
|
|
#define NU2105_WATCHDOG_MASK (0x03)
|
|
|
|
/* NU2105_REG_CHRG_CTRL */
|
|
#define NU2105_CHG_EN_MASK BIT(7)
|
|
#define NU2105_TSBUS_DIS_MASK BIT(2)
|
|
#define NU2105_TSBAT_DIS_MASK BIT(1)
|
|
#define NU2105_TDIE_DIS_MASK BIT(0)
|
|
|
|
/* NU2105_REG_INT_STAT */
|
|
#define NU2105_BAT_OVP_ALM_STAT_MASK BIT(7)
|
|
#define NU2105_BAT_OCP_ALM_STAT_MASK BIT(6)
|
|
#define NU2105_BUS_OVP_ALM_STAT_MASK BIT(5)
|
|
#define NU2105_BUS_OCP_ALM_STAT_MASK BIT(4)
|
|
#define NU2105_BAT_UCP_ALM_STAT_MASK BIT(3)
|
|
#define NU2105_ADAPTER_INSERT_STAT_MASK BIT(2)
|
|
#define NU2105_VBAT_INSERT_STAT_MASK BIT(1)
|
|
#define NU2105_ADC_DONE_STAT_MASK BIT(0)
|
|
|
|
/* NU2105_REG_INT_FLAG */
|
|
#define NU2105_BAT_OVP_ALM_FLAG_MASK BIT(7)
|
|
#define NU2105_BAT_OCP_ALM_FLAG_MASK BIT(6)
|
|
#define NU2105_BUS_OVP_ALM_FLAG_MASK BIT(5)
|
|
#define NU2105_BUS_OCP_ALM_FLAG_MASK BIT(4)
|
|
#define NU2105_BAT_UCP_ALM_FLAG_MASK BIT(3)
|
|
#define NU2105_ADAPTER_INSERT_FLAG_MASK BIT(2)
|
|
#define NU2105_VBAT_INSERT_FLAG_MASK BIT(1)
|
|
#define NU2105_ADC_DONE_FLAG_MASK BIT(0)
|
|
|
|
/* NU2105_REG_FLT_STAT */
|
|
#define NU2105_BAT_OVP_FLT_STAT_MASK BIT(7)
|
|
#define NU2105_BAT_OCP_FLT_STAT_MASK BIT(6)
|
|
#define NU2105_BUS_OVP_FLT_STAT_MASK BIT(5)
|
|
#define NU2105_BUS_OCP_FLT_STAT_MASK BIT(4)
|
|
#define NU2105_TSBUS_TSBAT_ALM_STAT_MASK BIT(3)
|
|
#define NU2105_TSBAT_FLT_STAT_MASK BIT(2)
|
|
#define NU2105_TSBUS_FLT_STAT_MASK BIT(1)
|
|
#define NU2105_TDIE_ALM_STAT_MASK BIT(0)
|
|
|
|
/* NU2105_REG_FLT_FLAG */
|
|
#define NU2105_BAT_OVP_FLT_FLAG_MASK BIT(7)
|
|
#define NU2105_BAT_OCP_FLT_FLAG_MASK BIT(6)
|
|
#define NU2105_BUS_OVP_FLT_FLAG_MASK BIT(5)
|
|
#define NU2105_BUS_OCP_FLT_FLAG_MASK BIT(4)
|
|
#define NU2105_TSBUS_TSBAT_ALM_FLAG_MASK BIT(3)
|
|
#define NU2105_TSBAT_FLT_FLAG_MASK BIT(2)
|
|
#define NU2105_TSBUS_FLT_FLAG_MASK BIT(1)
|
|
#define NU2105_TDIE_ALM_FLAG_MASK BIT(0)
|
|
|
|
/* NU2105_REG_ADC_CTRL */
|
|
#define NU2105_ADC_EN_MASK BIT(7)
|
|
#define NU2105_ADC_RATE_MASK BIT(6)
|
|
#define NU2105_ADC_RATE_SHIFT (6)
|
|
#define NU2105_IBUS_ADC_DIS_MASK BIT(0)
|
|
|
|
/* NU2105_REG_ADC_FN_DISABLE */
|
|
#define NU2105_VBUS_ADC_DIS_MASK BIT(7)
|
|
#define NU2105_VAC_ADC_DIS_MASK BIT(6)
|
|
#define NU2105_VOUT_ADC_DIS_MASK BIT(5)
|
|
#define NU2105_VBAT_ADC_DIS_MASK BIT(4)
|
|
#define NU2105_IBAT_ADC_DIS_MASK BIT(3)
|
|
#define NU2105_TSBUS_ADC_DIS_MASK BIT(2)
|
|
#define NU2105_TSBAT_ADC_DIS_MASK BIT(1)
|
|
#define NU2105_TDIE_ADC_DIS_MASK BIT(0)
|
|
|
|
/* NU2105_REG_REG_CTRL */
|
|
#define NU2105_SS_TIMEOUT_SET_MASK (0xE0)
|
|
#define NU2105_SS_TIMEOUT_SET_SHIFT (5)
|
|
#define NU2105_SET_IBAT_SNS_RES_MASK BIT(1)
|
|
|
|
/* NU2105_REG_REG_THRESHOLD */
|
|
#define NU2105_VBATREG_ACTIVE_STAT_MASK BIT(3)
|
|
#define NU2105_IBATREG_ACTIVE_STAT_MASK BIT(2)
|
|
#define NU2105_VDROP_OVP_STAT_MASK BIT(1)
|
|
#define NU2105_VOUT_OVP_STAT_MASK BIT(0)
|
|
|
|
/* NU2105_REG_REG_FLAG_MASK */
|
|
#define NU2105_VBATREG_ACTIVE_FLAG_MASK BIT(7)
|
|
#define NU2105_IBATREG_ACTIVE_FLAG_MASK BIT(6)
|
|
#define NU2105_VDROP_OVP_FLAG_MASK BIT(5)
|
|
#define NU2105_VOUT_OVP_FLAG_MASK BIT(4)
|
|
|
|
/* NU2105_REG_DEGLITCH */
|
|
#define NU2105_VBUS_ERROR_LO_DG_SET_MASK BIT(4)
|
|
#define NU2105_IBUS_LOW_DG_SET_MASK BIT(3)
|
|
|
|
#define NU2105_BAT_OVP_MIN_UV (3475000)
|
|
#define NU2105_BAT_OVP_MAX_UV (5050000)
|
|
#define NU2105_BAT_OVP_STEP_UV (25000)
|
|
#define NU2105_BAT_OVP_ALM_MIN_UV (3500000)
|
|
#define NU2105_BAT_OVP_ALM_MAX_UV (5075000)
|
|
#define NU2105_BAT_OVP_ALM_STEP_UV (25000)
|
|
#define NU2105_BAT_OCP_MIN_UA (2000000)
|
|
#define NU2105_BAT_OCP_MAX_UA (10000000)
|
|
#define NU2105_BAT_OCP_STEP_UA (100000)
|
|
#define NU2105_BAT_OCP_ALM_MIN_UA (2000000)
|
|
#define NU2105_BAT_OCP_ALM_MAX_UA (14700000)
|
|
#define NU2105_BAT_OCP_ALM_STEP_UA (100000)
|
|
#define NU2105_BAT_UCP_ALM_MIN_UA (2000000)
|
|
#define NU2105_BAT_UCP_ALM_MAX_UA (8300000)
|
|
#define NU2105_BAT_UCP_ALM_STEP_UA (50000)
|
|
#define NU2105_AC_OVP_MIN_UV (11000000)
|
|
#define NU2105_AC_OVP_MAX_UV (17000000)
|
|
#define NU2105_AC_OVP_STEP_UV (1000000)
|
|
#define NU2105_BUS_OVP_MIN_UV (5950000)
|
|
#define NU2105_BUS_OVP_MAX_UV (12300000)
|
|
#define NU2105_BUS_OVP_STEP_UV (50000)
|
|
#define NU2105_BUS_OVP_ALM_MIN_UV (6000000)
|
|
#define NU2105_BUS_OVP_ALM_MAX_UV (12350000)
|
|
#define NU2105_BUS_OVP_ALM_STEP_UV (50000)
|
|
#define NU2105_BUS_OCP_MIN_UA (1000000)
|
|
#define NU2105_BUS_OCP_MAX_UA (4750000)
|
|
#define NU2105_BUS_OCP_STEP_UA (250000)
|
|
#define NU2105_BUS_OCP_ALM_MIN_UA (0)
|
|
#define NU2105_BUS_OCP_ALM_MAX_UA (6350000)
|
|
#define NU2105_BUS_OCP_ALM_STEP_UA (50000)
|
|
|
|
#define NU2105_DEVID 0x08
|
|
|
|
static bool adc_con = true;
|
|
static bool irq_log = false;
|
|
|
|
int nu2105_exist = 0;
|
|
static u8 chg_id = 0;
|
|
|
|
enum {
|
|
NU2105_MASTER,
|
|
NU2105_SLAVE,
|
|
NU2105_STANDALONE,
|
|
};
|
|
|
|
enum {
|
|
NU2105_ADC_CONTINUOUS,
|
|
NU2105_ADC_ONESHOT,
|
|
};
|
|
|
|
enum {
|
|
NU2105_ADC_IBUS = 0,
|
|
NU2105_ADC_VBUS,
|
|
NU2105_ADC_VAC,
|
|
NU2105_ADC_VOUT,
|
|
NU2105_ADC_VBAT,
|
|
NU2105_ADC_IBAT,
|
|
NU2105_ADC_TSBUS,
|
|
NU2105_ADC_TSBAT,
|
|
NU2105_ADC_TDIE,
|
|
};
|
|
|
|
static const char *nu2105_adc_name[] = {
|
|
[NU2105_ADC_IBUS] = "ibus",
|
|
[NU2105_ADC_VBUS] = "vbus",
|
|
[NU2105_ADC_VAC] = "vac",
|
|
[NU2105_ADC_VOUT] = "vout",
|
|
[NU2105_ADC_VBAT] = "vbat",
|
|
[NU2105_ADC_IBAT] = "ibat",
|
|
[NU2105_ADC_TSBUS] = "tsbus",
|
|
[NU2105_ADC_TSBAT] = "tsbat",
|
|
[NU2105_ADC_TDIE] = "tdie",
|
|
};
|
|
|
|
#define NU2105_IRQFLAG(x) NU2105_IRQFLAG_##x
|
|
#define NU2105_STAT(x) NU2105_STAT_##x
|
|
#define NU2105_IRQFLAG_STAT(x) NU2105_IRQFLAG(x), \
|
|
NU2105_STAT(x) = NU2105_IRQFLAG(x)
|
|
|
|
enum {
|
|
NU2105_IRQFLAG_STAT(AC_OVP), /* index 0 */ /* Byte 0 */
|
|
NU2105_IRQFLAG(IBUS_UCP_RISE), /* index 1 */
|
|
NU2105_IRQFLAG(IBUS_UCP_FALL), /* index 2 */
|
|
NU2105_IRQFLAG_STAT(TSHUT), /* index 3 */
|
|
NU2105_STAT(VBUS_ERRORLO), /* index 4 */ /* Byte 1 */
|
|
NU2105_STAT(VBUS_ERRORHI), /* index 5 */
|
|
NU2105_IRQFLAG(SS_TIMEOUT), /* index 6 */
|
|
NU2105_STAT(CONV_SWITCHING), /* index 7 */
|
|
NU2105_IRQFLAG(CONV_OCP), /* index 8 */ /* Byte 2 */
|
|
NU2105_IRQFLAG(PIN_DIAG_FAIL), /* index 9 */
|
|
NU2105_IRQFLAG(WD_TIMEOUT), /* index 10 */
|
|
NU2105_IRQFLAG_STAT(BAT_OVP_ALM), /* index 11 */
|
|
NU2105_IRQFLAG_STAT(BAT_OCP_ALM), /* index 12 */ /* Byte 3 */
|
|
NU2105_IRQFLAG_STAT(BUS_OVP_ALM), /* index 13 */
|
|
NU2105_IRQFLAG_STAT(BUS_OCP_ALM), /* index 14 */
|
|
NU2105_IRQFLAG_STAT(BAT_UCP_ALM), /* index 15 */
|
|
NU2105_IRQFLAG_STAT(ADAPTER_INSERT), /* index 16 */ /* Byte 4 */
|
|
NU2105_IRQFLAG_STAT(VBAT_INSERT), /* index 17 */
|
|
NU2105_IRQFLAG_STAT(ADC_DONE), /* index 18 */
|
|
NU2105_IRQFLAG_STAT(BAT_OVP_FLT), /* index 19 */
|
|
NU2105_IRQFLAG_STAT(BAT_OCP_FLT), /* index 20 */ /* Byte 5 */
|
|
NU2105_IRQFLAG_STAT(BUS_OVP_FLT), /* index 21 */
|
|
NU2105_IRQFLAG_STAT(BUS_OCP_FLT), /* index 22 */
|
|
NU2105_IRQFLAG_STAT(TSBUS_TSBAT_ALM), /* index 23 */
|
|
NU2105_IRQFLAG_STAT(TSBAT_FLT), /* index 24 */ /* Byte 6 */
|
|
NU2105_IRQFLAG_STAT(TSBUS_FLT), /* index 25 */
|
|
NU2105_IRQFLAG_STAT(TDIE_ALM), /* index 26 */
|
|
NU2105_IRQFLAG_STAT(VBATREG_ACTIVE), /* index 27 */
|
|
NU2105_IRQFLAG_STAT(IBATREG_ACTIVE), /* index 28 */ /* Byte 7 */
|
|
NU2105_IRQFLAG_STAT(VDROP_OVP), /* index 29 */
|
|
NU2105_IRQFLAG_STAT(VOUT_OVP), /* index 30 */
|
|
};
|
|
|
|
static const u32 irqmask_default = ~(u32)BIT(NU2105_IRQFLAG_ADC_DONE);
|
|
|
|
struct nu2105_cfg {
|
|
/* household */
|
|
const char *chg_name;
|
|
unsigned int ac_ovp;
|
|
unsigned int bat_ucp_alm;
|
|
unsigned int fsw_set;
|
|
unsigned int ibat_sns_res;
|
|
unsigned int ss_timeout;
|
|
unsigned int ibus_low_dg_set;
|
|
/* watchdog */
|
|
bool watchdog_dis;
|
|
unsigned int watchdog;
|
|
/* protection */
|
|
bool bat_ovp_dis;
|
|
bool bat_ovp_alm_dis;
|
|
bool bat_ocp_dis;
|
|
bool bat_ocp_alm_dis;
|
|
bool bat_ucp_alm_dis;
|
|
bool bus_ovp_alm_dis;
|
|
bool bus_ocp_dis;
|
|
bool bus_ocp_alm_dis;
|
|
bool tsbus_dis;
|
|
bool tsbat_dis;
|
|
bool tdie_dis;
|
|
/* adc */
|
|
u16 adc_fn_dis;
|
|
/* irq */
|
|
u32 irqmask;
|
|
};
|
|
|
|
struct nu2105 {
|
|
struct i2c_client *client;
|
|
struct device *dev;
|
|
struct nu2105_cfg cfg;
|
|
|
|
struct mutex rw_lock;
|
|
struct mutex ops_lock;
|
|
struct mutex adc_lock;
|
|
|
|
u32 irqmask;
|
|
struct completion adc_done;
|
|
|
|
struct charger_device *chg_dev;
|
|
struct charger_properties chg_prop;
|
|
|
|
struct dentry *debugfs;
|
|
u8 debug_addr;
|
|
};
|
|
|
|
static int __nu2105_read(struct nu2105 *chip, u8 reg, u8 *val)
|
|
{
|
|
struct i2c_client *client = chip->client;
|
|
s32 ret;
|
|
|
|
ret = i2c_smbus_read_byte_data(client, reg);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
*val = (ret & 0xFF);
|
|
|
|
return ret < 0 ? ret : 0;
|
|
}
|
|
|
|
static int __nu2105_write(struct nu2105 *chip, u8 reg, u8 val)
|
|
{
|
|
struct i2c_client *client = chip->client;
|
|
s32 ret;
|
|
|
|
ret = i2c_smbus_write_byte_data(client, reg, val);
|
|
|
|
return ret < 0 ? ret : 0;
|
|
}
|
|
|
|
static int __nu2105_update_bits(struct nu2105 *chip, u8 reg, u8 mask, u8 val)
|
|
{
|
|
u8 tmp;
|
|
s32 ret = 0;
|
|
|
|
mutex_lock(&chip->rw_lock);
|
|
|
|
ret = __nu2105_read(chip, reg, &tmp);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
tmp = (val & mask) | (tmp & (~mask));
|
|
ret = __nu2105_write(chip, reg, tmp);
|
|
|
|
out:
|
|
mutex_unlock(&chip->rw_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int __nu2105_set_bits(struct nu2105 *chip, u8 reg, u8 bits)
|
|
{
|
|
return __nu2105_update_bits(chip, reg, bits, 0xFF);
|
|
}
|
|
|
|
static int __nu2105_clr_bits(struct nu2105 *chip, u8 reg, u8 bits)
|
|
{
|
|
return __nu2105_update_bits(chip, reg, bits, 0);
|
|
}
|
|
|
|
static bool __nu2105_check_bits(struct nu2105 *chip, u8 reg, u8 bits)
|
|
{
|
|
u8 val;
|
|
int ret;
|
|
|
|
ret = __nu2105_read(chip, reg, &val);
|
|
if (ret < 0)
|
|
return false;
|
|
|
|
return (val & bits) ? true : false;
|
|
}
|
|
|
|
static int __nu2105_read_word(struct nu2105 *chip, u8 reg, u16 *val)
|
|
{
|
|
struct i2c_client *client = chip->client;
|
|
s32 ret;
|
|
|
|
ret = i2c_smbus_read_word_data(client, reg);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
*val = (u16)ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __nu2105_write_word(struct nu2105 *chip, u8 reg, u16 val)
|
|
{
|
|
struct i2c_client *client = chip->client;
|
|
s32 ret;
|
|
|
|
ret = i2c_smbus_write_word_data(client, reg, val);
|
|
|
|
return ret < 0 ? ret : 0;
|
|
}
|
|
#if 1
|
|
static void __maybe_unused __nu2105_dump_register(struct nu2105 *chip)
|
|
{
|
|
u8 reg, val;
|
|
int ret;
|
|
|
|
for (reg = NU2105_REG_BAT_OVP; reg <= NU2105_REG_CHGMODE; reg++) {
|
|
ret = __nu2105_read(chip, reg, &val);
|
|
if (ret < 0) {
|
|
dev_info(chip->dev, "[DUMP] 0x%02x = error\n", reg);
|
|
continue;
|
|
}
|
|
dev_info(chip->dev, "[DUMP] 0x%02x = 0x%02x\n", reg, val);
|
|
}
|
|
}
|
|
#endif
|
|
static int __nu2105_set_bat_ovp(struct nu2105 *chip, unsigned int uV)
|
|
{
|
|
u8 val = (uV - NU2105_BAT_OVP_MIN_UV)
|
|
/ NU2105_BAT_OVP_STEP_UV;
|
|
|
|
if (uV < NU2105_BAT_OVP_MIN_UV)
|
|
val = 0x0;
|
|
if (uV > NU2105_BAT_OVP_MAX_UV)
|
|
val = 0x3F;
|
|
dev_info(chip->dev, "%s %d(0x%02X)\n", __func__, uV, val);
|
|
return __nu2105_update_bits(chip, NU2105_REG_BAT_OVP,
|
|
NU2105_BAT_OVP_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_bat_ovp_alm(struct nu2105 *chip, unsigned int uV)
|
|
{
|
|
u8 val = (uV - NU2105_BAT_OVP_ALM_MIN_UV)
|
|
/ NU2105_BAT_OVP_ALM_STEP_UV;
|
|
|
|
if (uV < NU2105_BAT_OVP_ALM_MIN_UV)
|
|
val = 0x0;
|
|
if (uV > NU2105_BAT_OVP_ALM_MAX_UV)
|
|
val = 0x3F;
|
|
dev_dbg(chip->dev, "%s %d(0x%02X)\n", __func__, uV, val);
|
|
return __nu2105_update_bits(chip, NU2105_REG_BAT_OVP_ALM,
|
|
NU2105_BAT_OVP_ALM_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_bat_ocp(struct nu2105 *chip, unsigned int uA)
|
|
{
|
|
u8 val = (uA - NU2105_BAT_OCP_MIN_UA)
|
|
/ NU2105_BAT_OCP_STEP_UA;
|
|
val += 500000;
|
|
|
|
if (uA < NU2105_BAT_OCP_MIN_UA)
|
|
val = 0x0;
|
|
if (uA > NU2105_BAT_OCP_MAX_UA)
|
|
val = 0x7F;
|
|
dev_info(chip->dev, "%s %d(0x%02X)\n", __func__, uA, val);
|
|
return __nu2105_update_bits(chip, NU2105_REG_BAT_OCP,
|
|
NU2105_BAT_OCP_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_bat_ocp_alm(struct nu2105 *chip, unsigned int uA)
|
|
{
|
|
u8 val = (uA - NU2105_BAT_OCP_ALM_MIN_UA)
|
|
/ NU2105_BAT_OCP_ALM_STEP_UA;
|
|
|
|
if (uA < NU2105_BAT_OCP_ALM_MIN_UA)
|
|
val = 0x0;
|
|
if (uA > NU2105_BAT_OCP_ALM_MAX_UA)
|
|
val = 0x7F;
|
|
dev_dbg(chip->dev, "%s %d(0x%02X)\n", __func__, uA, val);
|
|
return __nu2105_update_bits(chip, NU2105_REG_BAT_OCP_ALM,
|
|
NU2105_BAT_OCP_ALM_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_bat_ucp_alm(struct nu2105 *chip, unsigned int uA)
|
|
{
|
|
u8 val = (uA - NU2105_BAT_UCP_ALM_MIN_UA)
|
|
/ NU2105_BAT_UCP_ALM_STEP_UA;
|
|
|
|
if (uA < NU2105_BAT_UCP_ALM_MIN_UA)
|
|
val = 0x0;
|
|
if (uA > NU2105_BAT_UCP_ALM_MAX_UA)
|
|
val = 0x7F;
|
|
|
|
return __nu2105_update_bits(chip, NU2105_REG_BAT_UCP_ALM,
|
|
NU2105_BAT_UCP_ALM_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_ac_ovp(struct nu2105 *chip, unsigned int uV)
|
|
{
|
|
u8 val = (uV - NU2105_AC_OVP_MIN_UV) / NU2105_AC_OVP_STEP_UV;
|
|
|
|
if (uV < NU2105_AC_OVP_MIN_UV)
|
|
val = 0x7;
|
|
if (uV > NU2105_AC_OVP_MAX_UV)
|
|
val = 0x6;
|
|
|
|
return __nu2105_update_bits(chip, NU2105_REG_AC_PROTECTION,
|
|
NU2105_AC_OVP_MASK, val);
|
|
}
|
|
|
|
|
|
static int __nu2105_set_bus_ovp(struct nu2105 *chip, unsigned int uV)
|
|
{
|
|
u8 val = (uV - NU2105_BUS_OVP_MIN_UV)
|
|
/ NU2105_BUS_OVP_STEP_UV;
|
|
|
|
if (uV < NU2105_BUS_OVP_MIN_UV)
|
|
val = 0x0;
|
|
if (uV > NU2105_BUS_OVP_MAX_UV)
|
|
val = 0x7F;
|
|
|
|
dev_dbg(chip->dev, "%s %d(0x%02X)\n", __func__, uV, val);
|
|
return __nu2105_update_bits(chip, NU2105_REG_BUS_OVP,
|
|
NU2105_BUS_OVP_MASK, val);
|
|
}
|
|
|
|
|
|
static int __nu2105_set_bus_ovp_alm(struct nu2105 *chip, unsigned int uV)
|
|
{
|
|
u8 val = (uV - NU2105_BUS_OVP_ALM_MIN_UV)
|
|
/ NU2105_BUS_OVP_ALM_STEP_UV;
|
|
|
|
if (uV < NU2105_BUS_OVP_ALM_MIN_UV)
|
|
val = 0x0;
|
|
if (uV > NU2105_BUS_OVP_ALM_MAX_UV)
|
|
val = 0x7F;
|
|
dev_dbg(chip->dev, "%s %d(0x%02X)\n", __func__, uV, val);
|
|
return __nu2105_update_bits(chip, NU2105_REG_BUS_OVP_ALM,
|
|
NU2105_BUS_OVP_ALM_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_bus_ocp(struct nu2105 *chip, unsigned int uA)
|
|
{
|
|
u8 val = (uA - NU2105_BUS_OCP_MIN_UA)
|
|
/ NU2105_BUS_OCP_STEP_UA;
|
|
|
|
if (uA < NU2105_BUS_OCP_MIN_UA)
|
|
val = 0x0;
|
|
if (uA > NU2105_BUS_OCP_MAX_UA)
|
|
val = 0x0F;
|
|
|
|
dev_dbg(chip->dev, "%s %d(0x%02X)\n", __func__, uA, val);
|
|
|
|
return __nu2105_update_bits(chip, NU2105_REG_BUS_OCP_UCP,
|
|
NU2105_BUS_OCP_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_bus_ocp_alm(struct nu2105 *chip, unsigned int uA)
|
|
{
|
|
u8 val = (uA - NU2105_BUS_OCP_ALM_MIN_UA)
|
|
/ NU2105_BUS_OCP_ALM_STEP_UA;
|
|
|
|
if (uA < NU2105_BUS_OCP_ALM_MIN_UA)
|
|
val = 0x0;
|
|
if (uA > NU2105_BUS_OCP_ALM_MAX_UA)
|
|
val = 0x7F;
|
|
|
|
dev_dbg(chip->dev, "%s %d(0x%02X)\n", __func__, uA, val);
|
|
return __nu2105_update_bits(chip, NU2105_REG_BUS_OCP_ALM,
|
|
NU2105_BUS_OCP_ALM_MASK, val);
|
|
}
|
|
|
|
static int __nu2105_set_fsw(struct nu2105 *chip, unsigned int hz)
|
|
{
|
|
const unsigned int fsw_set[] = {
|
|
187500, 250000, 300000, 375000, 500000, 750000
|
|
};
|
|
u8 val;
|
|
|
|
for (val = 0; val < ARRAY_SIZE(fsw_set) - 1; val++) {
|
|
if (hz <= fsw_set[val])
|
|
break;
|
|
}
|
|
|
|
return __nu2105_update_bits(chip, NU2105_REG_CONTROL,
|
|
NU2105_FSW_SET_MASK,
|
|
val << NU2105_FSW_SET_SHIFT);
|
|
}
|
|
|
|
static int __nu2105_enable_watchdog(struct nu2105 *chip, bool en)
|
|
{
|
|
return (en ? __nu2105_clr_bits : __nu2105_set_bits)
|
|
(chip, NU2105_REG_CONTROL, NU2105_WATCHDOG_DIS_MASK);
|
|
}
|
|
|
|
static int __nu2105_set_watchdog(struct nu2105 *chip, unsigned int usec)
|
|
{
|
|
const unsigned int watchdog[] = {
|
|
500000, 1000000, 5000000, 30000000
|
|
};
|
|
u8 val;
|
|
|
|
for (val = 0; val < ARRAY_SIZE(watchdog) - 1; val++) {
|
|
if (usec <= watchdog[val])
|
|
break;
|
|
}
|
|
|
|
return __nu2105_update_bits(chip, NU2105_REG_CONTROL,
|
|
NU2105_WATCHDOG_MASK, val);
|
|
}
|
|
|
|
static bool __nu2105_is_chg_enabled(struct nu2105 *chip)
|
|
{
|
|
return __nu2105_check_bits(chip, NU2105_REG_CHRG_CTRL,
|
|
NU2105_CHG_EN_MASK);
|
|
}
|
|
|
|
static int __nu2105_enable_chg(struct nu2105 *chip, bool en)
|
|
{
|
|
return (en ? __nu2105_set_bits : __nu2105_clr_bits)
|
|
(chip, NU2105_REG_CHRG_CTRL, NU2105_CHG_EN_MASK);
|
|
}
|
|
|
|
static bool __nu2105_is_adc_done(struct nu2105 *chip)
|
|
{
|
|
return __nu2105_check_bits(chip, NU2105_REG_INT_STAT,
|
|
NU2105_ADC_DONE_STAT_MASK);
|
|
}
|
|
|
|
static bool __nu2105_is_adc_oneshot(struct nu2105 *chip)
|
|
{
|
|
return __nu2105_check_bits(chip, NU2105_REG_ADC_CTRL,
|
|
NU2105_ADC_RATE_MASK);
|
|
}
|
|
|
|
static int __nu2105_set_adc_oneshot(struct nu2105 *chip, bool oneshot)
|
|
{
|
|
return (oneshot ? __nu2105_set_bits : __nu2105_clr_bits)
|
|
(chip, NU2105_REG_ADC_CTRL, NU2105_ADC_RATE_MASK);
|
|
}
|
|
|
|
static bool __nu2105_is_adc_enabled(struct nu2105 *chip)
|
|
{
|
|
return __nu2105_check_bits(chip, NU2105_REG_ADC_CTRL,
|
|
NU2105_ADC_EN_MASK);
|
|
}
|
|
|
|
static int __nu2105_enable_adc(struct nu2105 *chip, bool en)
|
|
{
|
|
return (en ? __nu2105_set_bits : __nu2105_clr_bits)
|
|
(chip, NU2105_REG_ADC_CTRL, NU2105_ADC_EN_MASK);
|
|
}
|
|
|
|
static int __nu2105_set_adc_fn_dis(struct nu2105 *chip, u16 adc_fn_dis)
|
|
{
|
|
u16 val = ((adc_fn_dis & 0xFF) << 8) | ((adc_fn_dis >> 8) & 0xFF);
|
|
|
|
return __nu2105_write_word(chip, NU2105_REG_ADC_CTRL, val);
|
|
}
|
|
|
|
static int __nu2105_set_ss_timeout(struct nu2105 *chip, unsigned int us)
|
|
{
|
|
const unsigned int timeout[] = {
|
|
0, 12500, 25000, 50000, 100000, 400000, 1500000, 100000000
|
|
};
|
|
u8 val;
|
|
|
|
for (val = 0; val < ARRAY_SIZE(timeout); val++) {
|
|
if (us <= timeout[val])
|
|
break;
|
|
}
|
|
|
|
return __nu2105_update_bits(chip, NU2105_REG_REG_CTRL,
|
|
NU2105_SS_TIMEOUT_SET_MASK,
|
|
val << NU2105_SS_TIMEOUT_SET_SHIFT);
|
|
}
|
|
|
|
static int __nu2105_set_ibat_sns_res(struct nu2105 *chip, unsigned int ohm)
|
|
{
|
|
return ((ohm == 5) ? __nu2105_set_bits : __nu2105_clr_bits)
|
|
(chip, NU2105_REG_REG_CTRL,
|
|
NU2105_SET_IBAT_SNS_RES_MASK);
|
|
}
|
|
|
|
static int __nu2105_set_ibus_low_dg_set(struct nu2105 *chip, unsigned int us)
|
|
{
|
|
return ((us == 5000) ? __nu2105_set_bits : __nu2105_clr_bits)
|
|
(chip, NU2105_REG_DEGLITCH,
|
|
NU2105_IBUS_LOW_DG_SET_MASK);
|
|
}
|
|
|
|
static int __nu2105_convert_adc(struct nu2105 *chip, int channel, u16 val)
|
|
{
|
|
s16 sval = (s16)val;
|
|
int conv_val = 0;
|
|
|
|
switch (channel) {
|
|
case NU2105_ADC_VBUS:
|
|
case NU2105_ADC_VAC:
|
|
case NU2105_ADC_VOUT:
|
|
case NU2105_ADC_VBAT:
|
|
/* in micro volt */
|
|
conv_val = sval * 1000;
|
|
dev_err(chip->dev, "%s adc: %duV (0x%04x)\n",
|
|
nu2105_adc_name[channel], conv_val, val);
|
|
break;
|
|
case NU2105_ADC_IBUS:
|
|
case NU2105_ADC_IBAT:
|
|
/* in micro amp */
|
|
conv_val = sval * 1000;
|
|
dev_err(chip->dev, "%s adc: %duA (0x%04x)\n",
|
|
nu2105_adc_name[channel], conv_val, val);
|
|
break;
|
|
case NU2105_ADC_TDIE:
|
|
/* in degreeC */
|
|
conv_val = (10 + sval) >> 1;
|
|
//conv_val = sval >> 1;
|
|
dev_err(chip->dev, "%s adc: %d.%cdegC (0x%04x)\n",
|
|
nu2105_adc_name[channel],
|
|
conv_val, (sval & 0x1 ? '5' : '0'), val);
|
|
break;
|
|
case NU2105_ADC_TSBAT:
|
|
case NU2105_ADC_TSBUS:
|
|
/* in percent */
|
|
conv_val = sval * 100 / 1024;
|
|
dev_err(chip->dev, "%s adc: %d%% (0x%04x)\n",
|
|
nu2105_adc_name[channel], conv_val, val);
|
|
break;
|
|
}
|
|
|
|
return conv_val;
|
|
}
|
|
|
|
static inline int __nu2105_wait_for_adc_done(struct nu2105 *chip)
|
|
{
|
|
unsigned long ret;
|
|
|
|
if (!__nu2105_is_adc_oneshot(chip)) {
|
|
msleep(300);
|
|
|
|
if (!__nu2105_is_adc_enabled(chip))
|
|
return -EIO;
|
|
|
|
return 0;
|
|
}
|
|
|
|
ret = wait_for_completion_timeout(&chip->adc_done,
|
|
msecs_to_jiffies(300));
|
|
if (ret == 0) {
|
|
if (__nu2105_is_adc_done(chip))
|
|
return 0;
|
|
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_get_adc_data(struct nu2105 *bq, int channel, int *result)
|
|
{
|
|
int ret;
|
|
u16 temp;
|
|
u8 val_l, val_h;
|
|
|
|
if (channel < NU2105_ADC_IBUS || channel > NU2105_ADC_TDIE)
|
|
return -EINVAL;
|
|
|
|
usleep_range(12000,15000);
|
|
switch (channel) {
|
|
case NU2105_ADC_IBUS:
|
|
ret = __nu2105_read(bq, 0x16, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x17, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_VBUS:
|
|
ret = __nu2105_read(bq, 0x18, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x19, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_VAC:
|
|
ret = __nu2105_read(bq, 0x1A, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x1B, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_VOUT:
|
|
ret = __nu2105_read(bq, 0x1C, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x1D, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_VBAT:
|
|
ret = __nu2105_read(bq, 0x1E, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x1F, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_IBAT:
|
|
ret = __nu2105_read(bq, 0x20, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x21, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_TSBUS:
|
|
ret = __nu2105_read(bq, 0x22, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x23, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_TSBAT:
|
|
ret = __nu2105_read(bq, 0x24, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x25, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case NU2105_ADC_TDIE:
|
|
ret = __nu2105_read(bq, 0x26, &val_h);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = __nu2105_read(bq, 0x27, &val_l);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
default:
|
|
dev_err(bq->dev, "failed to enable adc\n");
|
|
break;
|
|
}
|
|
|
|
//temp = val_l + (val_h << 8);
|
|
temp = val_h*256 + val_l;
|
|
|
|
*result = __nu2105_convert_adc(bq, channel, temp);
|
|
|
|
dev_dbg(bq->dev, "get %s adc, reg: %2x, channel:%d, val:%4x\n",
|
|
nu2105_adc_name[channel], (NU2105_REG_IBUS_ADC1 + (channel << 1)),
|
|
channel, temp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int __nu2105_get_adc(struct nu2105 *chip, int channel, int *data)
|
|
{
|
|
u16 val = 0;
|
|
bool oneshot = false, wait_for_adc_done = false;
|
|
int try;
|
|
int ret;
|
|
|
|
if (channel < NU2105_ADC_IBUS || channel > NU2105_ADC_TDIE)
|
|
return -EINVAL;
|
|
if (!adc_con)
|
|
{
|
|
mutex_lock(&chip->adc_lock);
|
|
|
|
if (!adc_con)
|
|
{
|
|
if (!__nu2105_is_chg_enabled(chip))
|
|
oneshot = true;
|
|
|
|
for (try = 0; try < 5; try++) {
|
|
if (oneshot || !__nu2105_is_adc_enabled(chip)) {
|
|
wait_for_adc_done = true;
|
|
reinit_completion(&chip->adc_done);
|
|
}
|
|
|
|
ret = __nu2105_set_adc_oneshot(chip, oneshot);
|
|
if (ret) {
|
|
dev_err(chip->dev, "failed to set adc rate\n");
|
|
continue;
|
|
}
|
|
|
|
ret = __nu2105_enable_adc(chip, true);
|
|
if (ret) {
|
|
dev_err(chip->dev, "failed to enable adc\n");
|
|
continue;
|
|
}
|
|
|
|
if (wait_for_adc_done) {
|
|
ret = __nu2105_wait_for_adc_done(chip);
|
|
if (ret) {
|
|
dev_err(chip->dev, "error waiting adc done\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (!ret) {
|
|
ret = __nu2105_read_word(chip,
|
|
NU2105_REG_IBUS_ADC1 + (channel << 1), &val);
|
|
if (ret < 0)
|
|
dev_err(chip->dev, "failed to read adc\n");
|
|
}
|
|
|
|
/* adc running in continuous mode. left adc enabled */
|
|
if (oneshot) {
|
|
if (__nu2105_enable_adc(chip, false))
|
|
dev_err(chip->dev, "failed to disable adc\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (__nu2105_is_chg_enabled(chip))
|
|
{
|
|
ret = __nu2105_read_word(chip,
|
|
NU2105_REG_IBUS_ADC1 + (channel << 1), &val);
|
|
dev_dbg(chip->dev, "get %s adc, reg: %2x, channel:%d, val:%4x\n",
|
|
nu2105_adc_name[channel], (NU2105_REG_IBUS_ADC1 + (channel << 1)),
|
|
channel,val);
|
|
}
|
|
else
|
|
dev_err(chip->dev, "charger is disable\n");
|
|
}
|
|
|
|
mutex_unlock(&chip->adc_lock);
|
|
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to get %s adc (%d)\n",
|
|
nu2105_adc_name[channel], ret);
|
|
return ret;
|
|
}
|
|
|
|
val = ((val & 0xFF) << 8) | ((val >> 8) & 0xFF);
|
|
*data = __nu2105_convert_adc(chip, channel, val);
|
|
}
|
|
else
|
|
{
|
|
mutex_lock(&chip->adc_lock);
|
|
nu2105_get_adc_data(chip, channel, data);
|
|
mutex_unlock(&chip->adc_lock);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u32 __to_flag(u8 reg, u8 val)
|
|
{
|
|
u32 flag = 0;
|
|
|
|
switch (reg) {
|
|
case NU2105_REG_AC_PROTECTION:
|
|
if (val & NU2105_AC_OVP_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_AC_OVP);
|
|
break;
|
|
case NU2105_REG_BUS_OCP_UCP:
|
|
if (val & NU2105_IBUS_UCP_RISE_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_IBUS_UCP_RISE);
|
|
if (val & NU2105_IBUS_UCP_FALL_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_IBUS_UCP_FALL);
|
|
break;
|
|
case NU2105_REG_CONVERTER_STATE:
|
|
if (val & NU2105_TSHUT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_TSHUT);
|
|
if (val & NU2105_SS_TIMEOUT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_SS_TIMEOUT);
|
|
if (val & NU2105_CONV_OCP_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_CONV_OCP);
|
|
if (val & NU2105_PIN_DIAG_FAIL_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_PIN_DIAG_FAIL);
|
|
break;
|
|
case NU2105_REG_CONTROL:
|
|
if (val & NU2105_WD_TIMEOUT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_WD_TIMEOUT);
|
|
break;
|
|
case NU2105_REG_INT_FLAG:
|
|
if (val & NU2105_BAT_OVP_ALM_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BAT_OVP_ALM);
|
|
if (val & NU2105_BAT_OCP_ALM_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BAT_OCP_ALM);
|
|
if (val & NU2105_BUS_OVP_ALM_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BUS_OVP_ALM);
|
|
if (val & NU2105_BUS_OCP_ALM_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BUS_OCP_ALM);
|
|
if (val & NU2105_BAT_UCP_ALM_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BAT_UCP_ALM);
|
|
if (val & NU2105_ADAPTER_INSERT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_ADAPTER_INSERT);
|
|
if (val & NU2105_VBAT_INSERT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_VBAT_INSERT);
|
|
if (val & NU2105_ADC_DONE_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_ADC_DONE);
|
|
break;
|
|
case NU2105_REG_FLT_FLAG:
|
|
if (val & NU2105_BAT_OVP_FLT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BAT_OVP_FLT);
|
|
if (val & NU2105_BAT_OCP_FLT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BAT_OCP_FLT);
|
|
if (val & NU2105_BUS_OVP_FLT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BUS_OVP_FLT);
|
|
if (val & NU2105_BUS_OCP_FLT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_BUS_OCP_FLT);
|
|
if (val & NU2105_TSBUS_TSBAT_ALM_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_TSBUS_TSBAT_ALM);
|
|
if (val & NU2105_TSBAT_FLT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_TSBAT_FLT);
|
|
if (val & NU2105_TSBUS_FLT_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_TSBUS_FLT);
|
|
if (val & NU2105_TDIE_ALM_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_TDIE_ALM);
|
|
break;
|
|
case NU2105_REG_REG_FLAG_MASK:
|
|
if (val & NU2105_VBATREG_ACTIVE_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_VBATREG_ACTIVE);
|
|
if (val & NU2105_IBATREG_ACTIVE_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_IBATREG_ACTIVE);
|
|
if (val & NU2105_VDROP_OVP_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_VDROP_OVP);
|
|
if (val & NU2105_VOUT_OVP_FLAG_MASK)
|
|
flag |= BIT(NU2105_IRQFLAG_VOUT_OVP);
|
|
break;
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
|
|
static u32 __nu2105_get_flag(struct nu2105 *chip)
|
|
{
|
|
const u8 reg[] = {
|
|
NU2105_REG_AC_PROTECTION,
|
|
NU2105_REG_BUS_OCP_UCP,
|
|
NU2105_REG_CONVERTER_STATE,
|
|
NU2105_REG_CONTROL,
|
|
NU2105_REG_INT_FLAG,
|
|
NU2105_REG_FLT_FLAG,
|
|
NU2105_REG_REG_FLAG_MASK
|
|
};
|
|
u8 val;
|
|
u32 flag = 0;
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
mutex_lock(&chip->rw_lock);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(reg); i++) {
|
|
ret = __nu2105_read(chip, reg[i], &val);
|
|
if (ret) {
|
|
dev_err(chip->dev, "failed to read flag reg %02xh\n",
|
|
reg[i]);
|
|
continue;
|
|
}
|
|
flag |= __to_flag(reg[i], val);
|
|
}
|
|
|
|
mutex_unlock(&chip->rw_lock);
|
|
|
|
return flag;
|
|
}
|
|
|
|
static u32 __to_stat(u8 reg, u8 val)
|
|
{
|
|
u32 stat = 0;
|
|
|
|
switch (reg) {
|
|
case NU2105_REG_AC_PROTECTION:
|
|
if (val & NU2105_AC_OVP_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_AC_OVP);
|
|
break;
|
|
case NU2105_REG_CONVERTER_STATE:
|
|
if (val & NU2105_TSHUT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_TSHUT);
|
|
if (val & NU2105_VBUS_ERRORLO_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_VBUS_ERRORLO);
|
|
if (val & NU2105_VBUS_ERRORHI_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_VBUS_ERRORHI);
|
|
if (val & NU2105_CONV_SWITCHING_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_CONV_SWITCHING);
|
|
break;
|
|
case NU2105_REG_INT_STAT:
|
|
if (val & NU2105_BAT_OVP_ALM_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BAT_OVP_ALM);
|
|
if (val & NU2105_BAT_OCP_ALM_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BAT_OCP_ALM);
|
|
if (val & NU2105_BUS_OVP_ALM_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BUS_OVP_ALM);
|
|
if (val & NU2105_BUS_OCP_ALM_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BUS_OCP_ALM);
|
|
if (val & NU2105_BAT_UCP_ALM_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BAT_UCP_ALM);
|
|
if (val & NU2105_ADAPTER_INSERT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_ADAPTER_INSERT);
|
|
if (val & NU2105_VBAT_INSERT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_VBAT_INSERT);
|
|
if (val & NU2105_ADC_DONE_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_ADC_DONE);
|
|
break;
|
|
case NU2105_REG_FLT_STAT:
|
|
if (val & NU2105_BAT_OVP_FLT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BAT_OVP_FLT);
|
|
if (val & NU2105_BAT_OCP_FLT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BAT_OCP_FLT);
|
|
if (val & NU2105_BUS_OVP_FLT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BUS_OVP_FLT);
|
|
if (val & NU2105_BUS_OCP_FLT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_BUS_OCP_FLT);
|
|
if (val & NU2105_TSBUS_TSBAT_ALM_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_TSBUS_TSBAT_ALM);
|
|
if (val & NU2105_TSBAT_FLT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_TSBAT_FLT);
|
|
if (val & NU2105_TSBUS_FLT_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_TSBUS_FLT);
|
|
if (val & NU2105_TDIE_ALM_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_TDIE_ALM);
|
|
break;
|
|
case NU2105_REG_REG_THRESHOLD:
|
|
if (val & NU2105_VBATREG_ACTIVE_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_VBATREG_ACTIVE);
|
|
if (val & NU2105_IBATREG_ACTIVE_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_IBATREG_ACTIVE);
|
|
if (val & NU2105_VDROP_OVP_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_VDROP_OVP);
|
|
if (val & NU2105_VOUT_OVP_STAT_MASK)
|
|
stat |= BIT(NU2105_STAT_VOUT_OVP);
|
|
break;
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
static u32 __nu2105_get_stat(struct nu2105 *chip)
|
|
{
|
|
const u8 reg[] = {
|
|
NU2105_REG_AC_PROTECTION,
|
|
NU2105_REG_CONVERTER_STATE,
|
|
NU2105_REG_INT_STAT,
|
|
NU2105_REG_FLT_STAT,
|
|
NU2105_REG_REG_THRESHOLD
|
|
};
|
|
u8 val;
|
|
u32 stat = 0;
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
mutex_lock(&chip->rw_lock);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(reg); i++) {
|
|
ret = __nu2105_read(chip, reg[i], &val);
|
|
if (ret) {
|
|
dev_err(chip->dev, "failed to read stat "
|
|
"reg 0x%02x\n", reg[i]);
|
|
continue;
|
|
}
|
|
stat |= __to_stat(reg[i], val);
|
|
}
|
|
|
|
mutex_unlock(&chip->rw_lock);
|
|
|
|
return stat;
|
|
}
|
|
|
|
static int __nu2105_set_irqmask(struct nu2105 *chip, u32 irqmask)
|
|
{
|
|
const u8 reg[] = {
|
|
NU2105_REG_AC_PROTECTION,
|
|
NU2105_REG_BUS_OCP_UCP,
|
|
NU2105_REG_INT_MASK,
|
|
NU2105_REG_FLT_MASK,
|
|
NU2105_REG_REG_FLAG_MASK,
|
|
};
|
|
u8 mask[] = {
|
|
BIT(5), /* NU2105_REG_AC_PROTECTION */
|
|
BIT(5), /* NU2105_REG_BUS_OCP_UCP */
|
|
(0xFF), /* NU2105_REG_INT_MASK */
|
|
(0xFF), /* NU2105_REG_FLT_MASK */
|
|
(0x0F), /* NU2105_REG_REG_FLAG_MASK */
|
|
};
|
|
u8 val[] = {
|
|
/* NU2105_REG_AC_PROTECTION */
|
|
(irqmask & BIT(NU2105_IRQFLAG_AC_OVP) ? BIT(5) : 0),
|
|
/* NU2105_REG_BUS_OCP_UCP */
|
|
(irqmask & BIT(NU2105_IRQFLAG_IBUS_UCP_RISE) ? BIT(5) : 0),
|
|
/* NU2105_REG_INT_MASK */
|
|
((irqmask & BIT(NU2105_IRQFLAG_BAT_OVP_ALM) ? BIT(7) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_BAT_OCP_ALM) ? BIT(6) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_BUS_OVP_ALM) ? BIT(5) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_BUS_OCP_ALM) ? BIT(4) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_BAT_UCP_ALM) ? BIT(3) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_ADAPTER_INSERT) ? BIT(2) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_VBAT_INSERT) ? BIT(1) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_ADC_DONE) ? BIT(0) : 0)),
|
|
/* NU2105_REG_FLT_MASK */
|
|
((irqmask & BIT(NU2105_IRQFLAG_BAT_OVP_FLT) ? BIT(7) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_BAT_OCP_FLT) ? BIT(6) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_BUS_OVP_FLT) ? BIT(5) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_BUS_OCP_FLT) ? BIT(4) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_TSBUS_TSBAT_ALM) ? BIT(3) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_TSBAT_FLT) ? BIT(2) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_TSBUS_FLT) ? BIT(1) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_TDIE_ALM) ? BIT(0) : 0)),
|
|
/* NU2105_REG_REG_FLAG_MASK */
|
|
((irqmask & BIT(NU2105_IRQFLAG_VBATREG_ACTIVE) ? BIT(3) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_IBATREG_ACTIVE) ? BIT(2) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_VDROP_OVP) ? BIT(1) : 0)
|
|
| (irqmask & BIT(NU2105_IRQFLAG_VOUT_OVP) ? BIT(0) : 0)),
|
|
};
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(reg); i++) {
|
|
ret = __nu2105_update_bits(chip, reg[i], mask[i], val[i]);
|
|
if (ret) {
|
|
dev_err(chip->dev, "failed to set irqmask "
|
|
"reg 0x%02x\n", reg[i]);
|
|
}
|
|
}
|
|
|
|
chip->irqmask = irqmask;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __nu2105_set_protection(struct nu2105 *chip)
|
|
{
|
|
const u8 reg[] = {
|
|
NU2105_REG_BAT_OVP,
|
|
NU2105_REG_BAT_OVP_ALM,
|
|
NU2105_REG_BAT_OCP,
|
|
NU2105_REG_BAT_OCP_ALM,
|
|
NU2105_REG_BAT_UCP_ALM,
|
|
NU2105_REG_BUS_OVP_ALM,
|
|
NU2105_REG_BUS_OCP_UCP,
|
|
NU2105_REG_BUS_OCP_ALM,
|
|
NU2105_REG_CHRG_CTRL,
|
|
};
|
|
u8 mask[] = {
|
|
BIT(7), /* NU2105_REG_BAT_OVP */
|
|
BIT(7), /* NU2105_REG_BAT_OVP_ALM */
|
|
BIT(7), /* NU2105_REG_BAT_OCP */
|
|
BIT(7), /* NU2105_REG_BAT_OCP_ALM */
|
|
BIT(7), /* NU2105_REG_BAT_UCP_ALM */
|
|
BIT(7), /* NU2105_REG_BUS_OVP_ALM */
|
|
BIT(7), /* NU2105_REG_BUS_OCP_UCP */
|
|
BIT(7), /* NU2105_REG_BUS_OCP_ALM */
|
|
BIT(2) | BIT(1) | BIT(0), /* NU2105_REG_CHRG_CTRL */
|
|
};
|
|
u8 val[] = {
|
|
/* NU2105_REG_BAT_OVP */
|
|
(chip->cfg.bat_ovp_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_BAT_OVP_ALM */
|
|
(chip->cfg.bat_ovp_alm_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_BAT_OCP */
|
|
(chip->cfg.bat_ocp_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_BAT_OCP_ALM */
|
|
(chip->cfg.bat_ocp_alm_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_BAT_UCP_ALM */
|
|
(chip->cfg.bat_ucp_alm_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_BUS_OVP_ALM */
|
|
(chip->cfg.bus_ovp_alm_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_BUS_OCP_UCP */
|
|
(chip->cfg.bus_ocp_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_BUS_OCP_ALM */
|
|
(chip->cfg.bus_ocp_alm_dis ? BIT(7) : 0),
|
|
/* NU2105_REG_CHRG_CTRL */
|
|
((chip->cfg.tsbus_dis ? BIT(2) : 0)
|
|
| (chip->cfg.tsbat_dis ? BIT(1) : 0)
|
|
| (chip->cfg.tdie_dis ? BIT(0) : 0)),
|
|
};
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(reg); i++) {
|
|
ret = __nu2105_update_bits(chip, reg[i], mask[i], val[i]);
|
|
if (ret) {
|
|
dev_err(chip->dev, "failed to set protection "
|
|
"reg 0x%02x\n", reg[i]);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* irq handlers */
|
|
static void nu2105_irq_ac_ovp(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_AC_OVP)))
|
|
return;
|
|
|
|
dev_err(chip->dev, "ac_ovp\n");
|
|
}
|
|
|
|
static void nu2105_irq_ibus_ucp_rise(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_info(chip->dev, "ibus_ucp_rise\n");
|
|
}
|
|
|
|
static void nu2105_irq_ibus_ucp_fall(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_warn(chip->dev, "ibus_ucp_fall\n");
|
|
|
|
if (!chip->chg_dev)
|
|
return;
|
|
|
|
charger_dev_notify(chip->chg_dev, CHARGER_DEV_NOTIFY_IBUSUCP_FALL);
|
|
}
|
|
|
|
static void nu2105_irq_tshut(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_TSHUT)))
|
|
return;
|
|
|
|
dev_err(chip->dev, "tshut\n");
|
|
}
|
|
|
|
static void nu2105_irq_ss_timeout(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "ss_timeout\n");
|
|
}
|
|
|
|
static void nu2105_irq_conv_ocp(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "conv_ocp\n");
|
|
}
|
|
|
|
static void nu2105_irq_pin_diag_fail(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "pin_diag_fial\n");
|
|
}
|
|
|
|
static void nu2105_irq_wd_timeout(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "wd_timeout\n");
|
|
}
|
|
|
|
static void nu2105_irq_bat_ovp_alm(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_BAT_OVP_ALM)))
|
|
return;
|
|
|
|
dev_info(chip->dev, "bat_ovp_alm\n");
|
|
|
|
if (!chip->chg_dev)
|
|
return;
|
|
charger_dev_notify(chip->chg_dev, CHARGER_DEV_NOTIFY_VBATOVP_ALARM);
|
|
}
|
|
|
|
static void nu2105_irq_bat_ocp_alm(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_BAT_OCP_ALM)))
|
|
return;
|
|
|
|
dev_info(chip->dev, "bat_ocp_alm\n");
|
|
}
|
|
|
|
static void nu2105_irq_bus_ovp_alm(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_BUS_OVP_ALM)))
|
|
return;
|
|
|
|
dev_info(chip->dev, "bus_ovp_alm\n");
|
|
|
|
if (!chip->chg_dev)
|
|
return;
|
|
charger_dev_notify(chip->chg_dev, CHARGER_DEV_NOTIFY_VBUSOVP_ALARM);
|
|
}
|
|
|
|
static void nu2105_irq_bus_ocp_alm(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_BUS_OCP_ALM)))
|
|
return;
|
|
|
|
dev_info(chip->dev, "bus_ocp_alm\n");
|
|
}
|
|
|
|
static void nu2105_irq_bat_ucp_alm(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_BAT_UCP_ALM)))
|
|
return;
|
|
|
|
dev_info(chip->dev, "bat_ucp_alm\n");
|
|
}
|
|
|
|
static void nu2105_irq_adc_done(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_ADC_DONE)))
|
|
return;
|
|
|
|
complete(&chip->adc_done);
|
|
}
|
|
|
|
static void nu2105_irq_bat_ovp_flt(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "bat_ovp_flt\n");
|
|
}
|
|
|
|
static void nu2105_irq_bat_ocp_flt(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "bat_ocp_flt\n");
|
|
|
|
if (!chip->chg_dev)
|
|
return;
|
|
charger_dev_notify(chip->chg_dev, CHARGER_DEV_NOTIFY_IBATOCP);
|
|
}
|
|
|
|
static void nu2105_irq_bus_ovp_flt(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "bus_ovp_flt\n");
|
|
}
|
|
|
|
static void nu2105_irq_bus_ocp_flt(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "bus_ocp_flt\n");
|
|
|
|
if (!chip->chg_dev)
|
|
return;
|
|
charger_dev_notify(chip->chg_dev, CHARGER_DEV_NOTIFY_IBUSOCP);
|
|
}
|
|
|
|
static void nu2105_irq_tsbus_tsbat_alm(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_TSBUS_TSBAT_ALM)))
|
|
return;
|
|
|
|
dev_info(chip->dev, "tsbus_tsbat_alm\n");
|
|
}
|
|
|
|
static void nu2105_irq_tsbat_flt(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "tsbat_flt\n");
|
|
}
|
|
|
|
static void nu2105_irq_tsbus_flt(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "tsbus_flt\n");
|
|
}
|
|
|
|
static void nu2105_irq_tdie_alm(struct nu2105 *chip, u32 stat)
|
|
{
|
|
if (!(stat & BIT(NU2105_STAT_TDIE_ALM)))
|
|
return;
|
|
|
|
dev_info(chip->dev, "tdie_alm\n");
|
|
}
|
|
|
|
static void nu2105_irq_vdrop_ovp(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "vdrop_ovp\n");
|
|
|
|
if (!chip->chg_dev)
|
|
return;
|
|
charger_dev_notify(chip->chg_dev, CHARGER_DEV_NOTIFY_VOUTOVP);
|
|
}
|
|
|
|
static void nu2105_irq_vout_ovp(struct nu2105 *chip, u32 stat)
|
|
{
|
|
dev_err(chip->dev, "vout_ovp\n");
|
|
|
|
if (!chip->chg_dev)
|
|
return;
|
|
charger_dev_notify(chip->chg_dev, CHARGER_DEV_NOTIFY_VDROVP);
|
|
}
|
|
#if 1
|
|
static void nu2105_dump_important_regs(struct nu2105 *bq)
|
|
{
|
|
|
|
int ret;
|
|
u8 val;
|
|
|
|
ret = __nu2105_read(bq, 0x0A, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump converter state Reg [%02X] = 0x%02X\n",
|
|
0x0A, val);
|
|
|
|
ret = __nu2105_read(bq, 0x0D, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump int stat Reg[%02X] = 0x%02X\n",
|
|
0x0D, val);
|
|
|
|
ret = __nu2105_read(bq, 0x0E, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump int flag Reg[%02X] = 0x%02X\n",
|
|
0x0E, val);
|
|
|
|
ret = __nu2105_read(bq, 0x02, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump fault stat Reg[%02X] = 0x%02X\n",
|
|
0x02, val);
|
|
|
|
ret = __nu2105_read(bq, 0x10, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump fault stat Reg[%02X] = 0x%02X\n",
|
|
0x10, val);
|
|
|
|
ret = __nu2105_read(bq, 0x11, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump fault flag Reg[%02X] = 0x%02X\n",
|
|
0x11, val);
|
|
|
|
ret = __nu2105_read(bq, 0x2B, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump regulation flag Reg[%02X] = 0x%02X\n",
|
|
0x2B, val);
|
|
|
|
ret = __nu2105_read(bq, 0x2D, &val);
|
|
if (!ret)
|
|
dev_err(bq->dev,"dump regulation flag Reg[%02X] = 0x%02X\n",
|
|
0x2D, val);
|
|
}
|
|
#endif
|
|
static void nu2105_check_alarm_status(struct nu2105 *bq)
|
|
{
|
|
int ret;
|
|
u8 flag = 0;
|
|
u8 stat = 0;
|
|
|
|
ret = __nu2105_read(bq, 0x08, &flag);
|
|
if (!ret && (flag & 0x10))
|
|
dev_err(bq->dev,"UCP_FLAG =0x%02X\n",
|
|
!!(flag & 0x10));
|
|
|
|
ret = __nu2105_read(bq, 0x2D, &flag);
|
|
if (!ret && (flag & 0x20))
|
|
dev_err(bq->dev,"VDROP_OVP_FLAG =0x%02X\n",
|
|
!!(flag & 0x20));
|
|
|
|
/*read to clear alarm flag*/
|
|
ret = __nu2105_read(bq, 0x0E, &flag);
|
|
if (!ret && flag)
|
|
dev_err(bq->dev,"INT_FLAG =0x%02X\n", flag);
|
|
|
|
ret = __nu2105_read(bq, 0x0D, &stat);
|
|
if (!ret) {
|
|
dev_err(bq->dev,"INT_STAT = 0X%02x\n", stat);
|
|
}
|
|
|
|
ret = __nu2105_read(bq, 0x08, &stat);
|
|
if (!ret && (stat & 0x50))
|
|
dev_err(bq->dev,"Reg[08]BUS_UCPOVP = 0x%02X\n", stat);
|
|
|
|
ret = __nu2105_read(bq, 0x0A, &stat);
|
|
if (!ret && (stat & 0x02))
|
|
dev_err(bq->dev,"Reg[0A]CONV_OCP = 0x%02X\n", stat);
|
|
|
|
}
|
|
|
|
static void nu2105_check_fault_status(struct nu2105 *bq)
|
|
{
|
|
int ret;
|
|
u8 flag = 0;
|
|
u8 stat = 0;
|
|
|
|
ret = __nu2105_read(bq, 0x10, &stat);
|
|
if (!ret && stat)
|
|
dev_err(bq->dev,"FAULT_STAT = 0x%02X\n", stat);
|
|
|
|
ret = __nu2105_read(bq, 0x11, &flag);
|
|
if (!ret && flag)
|
|
dev_err(bq->dev,"FAULT_FLAG = 0x%02X\n", flag);
|
|
}
|
|
|
|
|
|
static void (*nu2105_irq_handlers[])(struct nu2105 *chip, u32 stat) = {
|
|
[NU2105_IRQFLAG_AC_OVP] = nu2105_irq_ac_ovp,
|
|
[NU2105_IRQFLAG_IBUS_UCP_RISE] = nu2105_irq_ibus_ucp_rise,
|
|
[NU2105_IRQFLAG_IBUS_UCP_FALL] = nu2105_irq_ibus_ucp_fall,
|
|
[NU2105_IRQFLAG_TSHUT] = nu2105_irq_tshut,
|
|
[NU2105_IRQFLAG_SS_TIMEOUT] = nu2105_irq_ss_timeout,
|
|
[NU2105_IRQFLAG_CONV_OCP] = nu2105_irq_conv_ocp,
|
|
[NU2105_IRQFLAG_PIN_DIAG_FAIL] = nu2105_irq_pin_diag_fail,
|
|
[NU2105_IRQFLAG_WD_TIMEOUT] = nu2105_irq_wd_timeout,
|
|
[NU2105_IRQFLAG_BAT_OVP_ALM] = nu2105_irq_bat_ovp_alm,
|
|
[NU2105_IRQFLAG_BAT_OCP_ALM] = nu2105_irq_bat_ocp_alm,
|
|
[NU2105_IRQFLAG_BUS_OVP_ALM] = nu2105_irq_bus_ovp_alm,
|
|
[NU2105_IRQFLAG_BUS_OCP_ALM] = nu2105_irq_bus_ocp_alm,
|
|
[NU2105_IRQFLAG_BAT_UCP_ALM] = nu2105_irq_bat_ucp_alm,
|
|
[NU2105_IRQFLAG_ADAPTER_INSERT] = NULL,
|
|
[NU2105_IRQFLAG_VBAT_INSERT] = NULL,
|
|
[NU2105_IRQFLAG_ADC_DONE] = nu2105_irq_adc_done,
|
|
[NU2105_IRQFLAG_BAT_OVP_FLT] = nu2105_irq_bat_ovp_flt,
|
|
[NU2105_IRQFLAG_BAT_OCP_FLT] = nu2105_irq_bat_ocp_flt,
|
|
[NU2105_IRQFLAG_BUS_OVP_FLT] = nu2105_irq_bus_ovp_flt,
|
|
[NU2105_IRQFLAG_BUS_OCP_FLT] = nu2105_irq_bus_ocp_flt,
|
|
[NU2105_IRQFLAG_TSBUS_TSBAT_ALM] = nu2105_irq_tsbus_tsbat_alm,
|
|
[NU2105_IRQFLAG_TSBAT_FLT] = nu2105_irq_tsbat_flt,
|
|
[NU2105_IRQFLAG_TSBUS_FLT] = nu2105_irq_tsbus_flt,
|
|
[NU2105_IRQFLAG_TDIE_ALM] = nu2105_irq_tdie_alm,
|
|
[NU2105_IRQFLAG_VBATREG_ACTIVE] = NULL,
|
|
[NU2105_IRQFLAG_IBATREG_ACTIVE] = NULL,
|
|
[NU2105_IRQFLAG_VDROP_OVP] = nu2105_irq_vdrop_ovp,
|
|
[NU2105_IRQFLAG_VOUT_OVP] = nu2105_irq_vout_ovp,
|
|
};
|
|
|
|
static irqreturn_t nu2105_irq_handler(int irq, void *data)
|
|
{
|
|
struct nu2105 *chip = data;
|
|
u32 flag, mask, stat;
|
|
unsigned int i;
|
|
|
|
if (irq_log)
|
|
{
|
|
flag = __nu2105_get_flag(chip);
|
|
stat = __nu2105_get_stat(chip);
|
|
mask = ~chip->irqmask;
|
|
|
|
dev_err(chip->dev, "flag: 0x%08x (0x%08x), stat: 0x%08x\n",
|
|
flag, mask, stat);
|
|
flag &= mask;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(nu2105_irq_handlers); i++) {
|
|
if ((flag & BIT(i)) && nu2105_irq_handlers[i])
|
|
nu2105_irq_handlers[i](chip, stat);
|
|
}
|
|
}else{
|
|
nu2105_dump_important_regs(chip);
|
|
// __nu2105_dump_register(chip);
|
|
nu2105_check_alarm_status(chip);
|
|
nu2105_check_fault_status(chip);
|
|
}
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/* charger interface */
|
|
static int nu2105_enable_chg(struct charger_device *chg_dev, bool en)
|
|
{
|
|
static const u32 fault = BIT(NU2105_STAT_AC_OVP)
|
|
| BIT(NU2105_STAT_BAT_OVP_FLT)
|
|
| BIT(NU2105_STAT_BUS_OVP_FLT)
|
|
| BIT(NU2105_STAT_TSBAT_FLT)
|
|
| BIT(NU2105_STAT_TSBUS_FLT);
|
|
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
u32 stat;
|
|
int ret;
|
|
|
|
dev_err(chip->dev, "nu2105 enable: %d\n", en);
|
|
if (!en) {
|
|
ret = __nu2105_set_irqmask(chip, irqmask_default);
|
|
if (ret < 0)
|
|
dev_err(chip->dev, "failed to set irqmask\n");
|
|
|
|
ret = __nu2105_enable_chg(chip, false);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to disable chg\n");
|
|
return ret;
|
|
}
|
|
|
|
if (!adc_con)
|
|
{
|
|
mutex_lock(&chip->adc_lock);
|
|
|
|
ret = __nu2105_enable_adc(chip, false);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to disable adc\n");
|
|
return ret;
|
|
}
|
|
|
|
mutex_unlock(&chip->adc_lock);
|
|
}
|
|
|
|
goto out;
|
|
}
|
|
|
|
stat = __nu2105_get_stat(chip);
|
|
if (stat & fault) {
|
|
dev_err(chip->dev, "cannot enable chg. fault = 0x%08x\n",
|
|
stat & fault);
|
|
return -EPERM;
|
|
}
|
|
|
|
/* clear irqs */
|
|
__nu2105_get_flag(chip);
|
|
|
|
ret = __nu2105_set_irqmask(chip, chip->cfg.irqmask);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set irqmask\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_enable_chg(chip, true);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to enable chg\n");
|
|
return ret;
|
|
}
|
|
|
|
|
|
stat = __nu2105_get_stat(chip);
|
|
if (stat & fault) {
|
|
dev_err(chip->dev, "222 cannot enable chg. fault = 0x%08x\n",
|
|
stat & fault);
|
|
return -EPERM;
|
|
}
|
|
|
|
|
|
if (en && !__nu2105_is_chg_enabled(chip)) {
|
|
dev_err(chip->dev, "chg not enabled\n");
|
|
return -EIO;
|
|
}
|
|
|
|
out:
|
|
if (chip->cfg.watchdog_dis)
|
|
return 0;
|
|
|
|
ret = __nu2105_enable_watchdog(chip, false);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to enable watchdog\n");
|
|
return ret;
|
|
}
|
|
dev_err(chip->dev, "nu2105 dump all register\n");
|
|
__nu2105_dump_register(chip);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int nu2105_enable_adc(struct charger_device *chg_dev, bool en)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
dev_err(chip->dev,"%s en:%d\n",__func__, en);
|
|
mutex_lock(&chip->adc_lock);
|
|
if(en)
|
|
__nu2105_write(chip, 0x14, 0xa8);
|
|
else
|
|
__nu2105_write(chip, 0x14, 0x0);
|
|
mutex_unlock(&chip->adc_lock);
|
|
// msleep(30);
|
|
// __nu2105_dump_register(chip);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int nu2105_is_chg_enabled(struct charger_device *chg_dev, bool *en)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
*en = __nu2105_is_chg_enabled(chip);
|
|
pr_info("%s() en = %d\n",__func__,*en);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_get_adc(struct charger_device *chg_dev,
|
|
enum adc_channel chan, int *min, int *max)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
int channel;
|
|
int ret;
|
|
dev_err(chip->dev,"%s() entry.\n",__func__);
|
|
|
|
switch (chan) {
|
|
case ADC_CHANNEL_VBUS:
|
|
channel = NU2105_ADC_VBUS;
|
|
break;
|
|
case ADC_CHANNEL_VBAT:
|
|
channel = NU2105_ADC_VBAT;
|
|
break;
|
|
case ADC_CHANNEL_IBUS:
|
|
channel = NU2105_ADC_IBUS;
|
|
break;
|
|
case ADC_CHANNEL_IBAT:
|
|
channel = NU2105_ADC_IBAT;
|
|
break;
|
|
case ADC_CHANNEL_TEMP_JC:
|
|
channel = NU2105_ADC_TDIE;
|
|
break;
|
|
case ADC_CHANNEL_VOUT:
|
|
channel = NU2105_ADC_VOUT;
|
|
break;
|
|
default:
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
if (!min || !max)
|
|
return -EINVAL;
|
|
|
|
ret = __nu2105_get_adc(chip, channel, max);
|
|
//dev_err(chip->dev, "%s------max=%d\n",__func__,*max);
|
|
if(*max < 0)
|
|
*max = *max - 2*(*max);
|
|
if (ret < 0)
|
|
*max = 0;
|
|
#if 0
|
|
switch (chan) {
|
|
case ADC_CHANNEL_VBAT:
|
|
*max = battery_get_bat_voltage() * 1000;
|
|
dev_err(chip->dev, "%s------vbat max=%d\n",__func__,*max);
|
|
break;
|
|
case ADC_CHANNEL_IBAT:
|
|
*max = battery_get_bat_current() * 1000;
|
|
dev_err(chip->dev, "%s------ibat max=%d\n",__func__,*max);
|
|
break;
|
|
default:
|
|
return -ENOTSUPP;
|
|
}
|
|
#endif
|
|
|
|
*min = *max;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int nu2105_get_adc_accuracy(struct charger_device *chg_dev,
|
|
enum adc_channel chan, int *min, int *max)
|
|
{
|
|
pr_info("%s()\n",__func__);
|
|
switch (chan) {
|
|
case ADC_CHANNEL_VBUS:
|
|
*min = 35000;
|
|
*max = 35000;
|
|
break;
|
|
case ADC_CHANNEL_VBAT:
|
|
*min = 20000;
|
|
*max = 20000;
|
|
break;
|
|
case ADC_CHANNEL_IBUS:
|
|
*min = 150000;
|
|
*max = 150000;
|
|
break;
|
|
case ADC_CHANNEL_IBAT:
|
|
*min = 200000;
|
|
*max = 200000;
|
|
break;
|
|
case ADC_CHANNEL_TEMP_JC:
|
|
*min = 4;
|
|
*max = 4;
|
|
break;
|
|
case ADC_CHANNEL_VOUT:
|
|
*min = 20000;
|
|
*max = 20000;
|
|
break;
|
|
default:
|
|
*min = 0;
|
|
*max = 0;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_set_vbusovp(struct charger_device *chg_dev, u32 uV)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
pr_info("%s()\n",__func__);
|
|
return __nu2105_set_bus_ovp(chip, uV);
|
|
}
|
|
|
|
static int nu2105_set_ibusocp(struct charger_device *chg_dev, u32 uA)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
pr_info("%s()\n",__func__);
|
|
/* uA will be 110% of target */
|
|
__nu2105_set_bus_ocp_alm(chip, uA / 110 * 100);
|
|
|
|
return __nu2105_set_bus_ocp(chip, uA);
|
|
}
|
|
|
|
static int nu2105_set_vbatovp(struct charger_device *chg_dev, u32 uV)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
pr_info("%s()\n",__func__);
|
|
return __nu2105_set_bat_ovp(chip, uV);
|
|
}
|
|
|
|
static int nu2105_set_vbatovp_alarm(struct charger_device *chg_dev, u32 uV)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
int ret;
|
|
pr_info("%s()\n",__func__);
|
|
mutex_lock(&chip->ops_lock);
|
|
|
|
ret = __nu2105_set_bat_ovp_alm(chip, uV);
|
|
|
|
mutex_unlock(&chip->ops_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int nu2105_reset_vbatovp_alarm(struct charger_device *chg_dev)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
pr_info("%s()\n",__func__);
|
|
mutex_lock(&chip->ops_lock);
|
|
|
|
__nu2105_set_bits(chip, NU2105_REG_BAT_OVP_ALM,
|
|
NU2105_BAT_OVP_ALM_DIS_MASK);
|
|
__nu2105_clr_bits(chip, NU2105_REG_BAT_OVP_ALM,
|
|
NU2105_BAT_OVP_ALM_DIS_MASK);
|
|
|
|
mutex_unlock(&chip->ops_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_set_vbusovp_alarm(struct charger_device *chg_dev, u32 uV)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
int ret;
|
|
pr_info("%s()\n",__func__);
|
|
mutex_lock(&chip->ops_lock);
|
|
|
|
ret = __nu2105_set_bus_ovp_alm(chip, uV);
|
|
|
|
mutex_unlock(&chip->ops_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
static int nu2105_is_vbuslowerr(struct charger_device *chg_dev, bool *err)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
u32 stat = __nu2105_get_stat(chip);
|
|
|
|
*err = false;
|
|
if (stat & BIT(NU2105_STAT_VBUS_ERRORLO))
|
|
*err = true;
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
#define VBUS_ERROR_LO BIT(5)
|
|
|
|
static int nu2105_is_vbuslowerr(struct charger_device *chg_dev, bool *err)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
int ret;
|
|
u8 stat = 0;
|
|
*err = false;
|
|
pr_info("%s()\n",__func__);
|
|
ret = __nu2105_read(chip, 0x0A, &stat);
|
|
if (!ret)
|
|
{
|
|
dev_err(chip->dev,"nu2105_is_vbuslowerr,NU2105_REG_0A: 0x%02X\n", stat);
|
|
|
|
if (stat & VBUS_ERROR_LO)
|
|
*err = true;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
static int nu2105_reset_vbusovp_alarm(struct charger_device *chg_dev)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
pr_info("%s()\n",__func__);
|
|
mutex_lock(&chip->ops_lock);
|
|
|
|
__nu2105_set_bits(chip, NU2105_REG_BUS_OVP_ALM,
|
|
NU2105_BUS_OVP_ALM_DIS_MASK);
|
|
__nu2105_clr_bits(chip, NU2105_REG_BUS_OVP_ALM,
|
|
NU2105_BUS_OVP_ALM_DIS_MASK);
|
|
|
|
mutex_unlock(&chip->ops_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_init_chip(struct charger_device *chg_dev)
|
|
{
|
|
// nu2105_enable_chg(chg_dev, true);
|
|
pr_info("%s()\n",__func__);
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_set_ibatocp(struct charger_device *chg_dev, u32 uA)
|
|
{
|
|
struct nu2105 *chip = charger_get_data(chg_dev);
|
|
pr_info("%s()\n",__func__);
|
|
/* uA will be 110% of target */
|
|
__nu2105_set_bat_ocp_alm(chip, uA / 110 * 100);
|
|
|
|
return __nu2105_set_bat_ocp(chip, uA);
|
|
}
|
|
|
|
static const struct charger_ops nu2105_chg_ops = {
|
|
.enable = nu2105_enable_chg,
|
|
.is_enabled = nu2105_is_chg_enabled,
|
|
.get_adc = nu2105_get_adc,
|
|
.set_vbusovp = nu2105_set_vbusovp,
|
|
.set_ibusocp = nu2105_set_ibusocp,
|
|
.set_vbatovp = nu2105_set_vbatovp,
|
|
.set_ibatocp = nu2105_set_ibatocp,
|
|
.init_chip = nu2105_init_chip,
|
|
.set_vbatovp_alarm = nu2105_set_vbatovp_alarm,
|
|
.reset_vbatovp_alarm = nu2105_reset_vbatovp_alarm,
|
|
.set_vbusovp_alarm = nu2105_set_vbusovp_alarm,
|
|
.reset_vbusovp_alarm = nu2105_reset_vbusovp_alarm,
|
|
.is_vbuslowerr = nu2105_is_vbuslowerr,
|
|
.get_adc_accuracy = nu2105_get_adc_accuracy,
|
|
};
|
|
|
|
/* debugfs interface */
|
|
static int debugfs_get_data(void *data, u64 *val)
|
|
{
|
|
struct nu2105 *chip = data;
|
|
int ret;
|
|
u8 temp;
|
|
|
|
ret = __nu2105_read(chip, chip->debug_addr, &temp);
|
|
if (ret)
|
|
return -EAGAIN;
|
|
|
|
*val = temp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int debugfs_set_data(void *data, u64 val)
|
|
{
|
|
struct nu2105 *chip = data;
|
|
int ret;
|
|
u8 temp;
|
|
|
|
temp = (u8)val;
|
|
ret = __nu2105_write(chip, chip->debug_addr, temp);
|
|
if (ret)
|
|
return -EAGAIN;
|
|
|
|
return 0;
|
|
}
|
|
DEFINE_SIMPLE_ATTRIBUTE(data_debugfs_ops,
|
|
debugfs_get_data, debugfs_set_data, "0x%02llx\n");
|
|
|
|
static int dump_debugfs_show(struct seq_file *m, void *start)
|
|
{
|
|
struct nu2105 *chip = m->private;
|
|
u8 reg, val;
|
|
int ret;
|
|
|
|
for (reg = NU2105_REG_BAT_OVP; reg <= NU2105_REG_CHGMODE; reg++) {
|
|
ret = __nu2105_read(chip, reg, &val);
|
|
if (ret) {
|
|
seq_printf(m, "0x%02x = error\n", reg);
|
|
continue;
|
|
}
|
|
|
|
seq_printf(m, "0x%02x = 0x%02x\n", reg, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dump_debugfs_open(struct inode *inode, struct file *file)
|
|
{
|
|
struct nu2105 *chip = inode->i_private;
|
|
|
|
return single_open(file, dump_debugfs_show, chip);
|
|
}
|
|
|
|
static const struct file_operations dump_debugfs_ops = {
|
|
.owner = THIS_MODULE,
|
|
.open = dump_debugfs_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static int create_debugfs_entries(struct nu2105 *chip)
|
|
{
|
|
struct dentry *ent;
|
|
|
|
chip->debugfs = debugfs_create_dir(chip->chg_prop.alias_name, NULL);
|
|
if (!chip->debugfs) {
|
|
dev_err(chip->dev, "failed to create debugfs\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
ent = debugfs_create_x8("addr", S_IFREG | S_IWUSR | S_IRUGO,
|
|
chip->debugfs, &chip->debug_addr);
|
|
if (!ent)
|
|
dev_err(chip->dev, "failed to create addr debugfs\n");
|
|
|
|
ent = debugfs_create_file("data", S_IFREG | S_IWUSR | S_IRUGO,
|
|
chip->debugfs, chip, &data_debugfs_ops);
|
|
if (!ent)
|
|
dev_err(chip->dev, "failed to create data debugfs\n");
|
|
|
|
ent = debugfs_create_file("dump", S_IFREG | S_IRUGO,
|
|
chip->debugfs, chip, &dump_debugfs_ops);
|
|
if (!ent)
|
|
dev_err(chip->dev, "failed to create dump debugfs\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_charger_device_register(struct nu2105 *chip)
|
|
{
|
|
#if 0
|
|
chip->chg_prop.alias_name = chip->desc->chg_name;
|
|
chip->chg_dev = charger_device_register(chip->desc->chg_name,
|
|
chip->dev, chip, &nu2105_chg_ops, &chip->chg_prop);
|
|
|
|
chip->chg_prop.alias_name = "nu2105_standalone";
|
|
chip->chg_dev = charger_device_register("primary_divider_chg",
|
|
chip->dev, chip, &nu2105_chg_ops, &chip->chg_prop);
|
|
#endif
|
|
chip->chg_prop.alias_name = chip->cfg.chg_name;
|
|
chip->chg_dev = charger_device_register(chip->cfg.chg_name,
|
|
chip->dev, chip, &nu2105_chg_ops, &chip->chg_prop);
|
|
|
|
|
|
|
|
if (!chip->chg_dev)
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nu2105_irq_init(struct nu2105 *chip)
|
|
{
|
|
// struct device_node *np = chip->dev->of_node;
|
|
struct gpio_desc *irq_gpio;
|
|
int irq;
|
|
int ret = 0;
|
|
irq_gpio = devm_gpiod_get(chip->dev, "nu2105,intr", GPIOD_IN);
|
|
if (IS_ERR(irq_gpio))
|
|
return PTR_ERR(irq_gpio);
|
|
|
|
irq = gpiod_to_irq(irq_gpio);
|
|
if (irq < 0) {
|
|
dev_err(chip->dev, "%s irq mapping fail(%d)\n", __func__, irq);
|
|
return ret;
|
|
}
|
|
dev_info(chip->dev, "%s irq = %d\n", __func__, irq);
|
|
|
|
|
|
ret = devm_request_threaded_irq(chip->dev, irq, NULL,
|
|
nu2105_irq_handler,
|
|
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
|
"nu2105_irq", chip);
|
|
if (ret) {
|
|
dev_err(chip->dev, "failed to request irq %d\n", irq);
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int nu2105_hw_init(struct nu2105 *chip)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = __nu2105_set_bat_ucp_alm(chip, 2000000);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set bat_ucp_alm\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_ac_ovp(chip, chip->cfg.ac_ovp);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set ac_ovp\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_fsw(chip, chip->cfg.fsw_set);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set fsw\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_watchdog(chip, chip->cfg.watchdog);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set watchdog\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_enable_watchdog(chip, false);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to disable watchdog\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_adc_fn_dis(chip, chip->cfg.adc_fn_dis);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set adc channel\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_ibat_sns_res(chip, chip->cfg.ibat_sns_res);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set ibat_sns_res\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_ss_timeout(chip, chip->cfg.ss_timeout);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set ss_timeout\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_ibus_low_dg_set(chip, chip->cfg.ibus_low_dg_set);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set ibus_low_dg_set\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_irqmask(chip, irqmask_default);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set mask\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = __nu2105_set_protection(chip);
|
|
if (ret < 0) {
|
|
dev_err(chip->dev, "failed to set protection\n");
|
|
return ret;
|
|
}
|
|
|
|
/* clear irqs */
|
|
__nu2105_get_flag(chip);
|
|
|
|
/********for nu2105********/
|
|
ret = __nu2105_write(chip, 0x00, 0x29);
|
|
ret = __nu2105_write(chip, 0x01, 0x24);
|
|
ret = __nu2105_write(chip, 0x02, 0x34);
|
|
ret = __nu2105_write(chip, 0x03, 0x28);
|
|
ret = __nu2105_write(chip, 0x04, 0x14);
|
|
ret = __nu2105_write(chip, 0x05, 0x18);
|
|
ret = __nu2105_write(chip, 0x06, 0x50);
|
|
ret = __nu2105_write(chip, 0x07, 0x3C);
|
|
ret = __nu2105_write(chip, 0x08, 0x0D);
|
|
ret = __nu2105_write(chip, 0x09, 0x50);
|
|
ret = __nu2105_write(chip, 0x0B, 0x44);
|
|
ret = __nu2105_write(chip, 0x0C, 0x16);
|
|
ret = __nu2105_write(chip, 0x0F, 0xC9);
|
|
ret = __nu2105_write(chip, 0x12, 0x0e);
|
|
ret = __nu2105_write(chip, 0x14, 0x0);
|
|
ret = __nu2105_write(chip, 0x15, 0x06);
|
|
ret = __nu2105_write(chip, 0x28, 0x28);
|
|
ret = __nu2105_write(chip, 0x29, 0x28);
|
|
ret = __nu2105_write(chip, 0x2A, 0xC8);
|
|
ret = __nu2105_write(chip, 0x2B, 0xC2);
|
|
ret = __nu2105_write(chip, 0x2C, 0x00);
|
|
ret = __nu2105_write(chip, 0x2D, 0x00);
|
|
ret = __nu2105_write(chip, 0x2E, 0x18);
|
|
ret = __nu2105_write(chip, 0x2F, 0x00);
|
|
/********for nu2105********/
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void nu2105_parse_dt_adc(struct nu2105 *chip, struct device_node *np)
|
|
{
|
|
chip->cfg.adc_fn_dis = 0;
|
|
|
|
if (of_property_read_bool(np, "ibus_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(8);
|
|
if (of_property_read_bool(np, "vbus_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(7);
|
|
if (of_property_read_bool(np, "vac_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(6);
|
|
if (of_property_read_bool(np, "vout_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(5);
|
|
if (of_property_read_bool(np, "vbat_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(4);
|
|
if (of_property_read_bool(np, "ibat_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(3);
|
|
if (of_property_read_bool(np, "tsbus_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(2);
|
|
if (of_property_read_bool(np, "tsbat_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(1);
|
|
if (of_property_read_bool(np, "tdie_adc_dis"))
|
|
chip->cfg.adc_fn_dis |= BIT(0);
|
|
}
|
|
|
|
static void nu2105_parse_dt_irq(struct nu2105 *chip, struct device_node *np)
|
|
{
|
|
chip->cfg.irqmask = 0;
|
|
|
|
if (of_property_read_bool(np, "ac_ovp_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_AC_OVP);
|
|
if (of_property_read_bool(np, "ibus_ucp_rise_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_IBUS_UCP_RISE);
|
|
if (of_property_read_bool(np, "bat_ovp_alm_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BAT_OVP_ALM);
|
|
if (of_property_read_bool(np, "bat_ocp_alm_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BAT_OCP_ALM);
|
|
if (of_property_read_bool(np, "bus_ovp_alm_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BUS_OVP_ALM);
|
|
if (of_property_read_bool(np, "bus_ocp_alm_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BUS_OCP_ALM);
|
|
if (of_property_read_bool(np, "bat_ucp_alm_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BAT_UCP_ALM);
|
|
if (of_property_read_bool(np, "adapter_insert_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_ADAPTER_INSERT);
|
|
if (of_property_read_bool(np, "vbat_insert_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_VBAT_INSERT);
|
|
if (of_property_read_bool(np, "adc_done_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_ADC_DONE);
|
|
if (of_property_read_bool(np, "bat_ovp_flt_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BAT_OVP_FLT);
|
|
if (of_property_read_bool(np, "bat_ocp_flt_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BAT_OCP_FLT);
|
|
if (of_property_read_bool(np, "bus_ovp_flt_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BUS_OVP_FLT);
|
|
if (of_property_read_bool(np, "bus_ocp_flt_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_BUS_OCP_FLT);
|
|
if (of_property_read_bool(np, "tsbus_tsbat_alm_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_TSBUS_TSBAT_ALM);
|
|
if (of_property_read_bool(np, "tsbat_flt_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_TSBAT_FLT);
|
|
if (of_property_read_bool(np, "tsbus_flt_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_TSBUS_FLT);
|
|
if (of_property_read_bool(np, "tdie_alm_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_TDIE_ALM);
|
|
if (of_property_read_bool(np, "vbatreg_active_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_VBATREG_ACTIVE);
|
|
if (of_property_read_bool(np, "ibatreg_active_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_IBATREG_ACTIVE);
|
|
if (of_property_read_bool(np, "vdrop_ovp_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_VDROP_OVP);
|
|
if (of_property_read_bool(np, "vout_ovp_mask"))
|
|
chip->cfg.irqmask |= BIT(NU2105_IRQFLAG_VOUT_OVP);
|
|
}
|
|
|
|
static void nu2105_parse_dt_protection(struct nu2105 *chip,
|
|
struct device_node *np)
|
|
{
|
|
chip->cfg.bat_ovp_dis = of_property_read_bool(np, "bat_ovp_dis");
|
|
chip->cfg.bat_ovp_alm_dis =
|
|
of_property_read_bool(np, "bat_ovp_alm_dis");
|
|
chip->cfg.bat_ocp_dis = of_property_read_bool(np, "bat_ocp_dis");
|
|
chip->cfg.bat_ocp_alm_dis =
|
|
of_property_read_bool(np, "bat_ocp_alm_dis");
|
|
chip->cfg.bat_ucp_alm_dis =
|
|
of_property_read_bool(np, "bat_ucp_alm_dis");
|
|
chip->cfg.bus_ovp_alm_dis =
|
|
of_property_read_bool(np, "bus_ovp_alm_dis");
|
|
chip->cfg.bus_ocp_dis = of_property_read_bool(np, "bus_ocp_dis");
|
|
chip->cfg.bus_ocp_alm_dis =
|
|
of_property_read_bool(np, "bus_ocp_alm_dis");
|
|
chip->cfg.tsbus_dis = of_property_read_bool(np, "tsbus_dis");
|
|
chip->cfg.tsbat_dis = of_property_read_bool(np, "tsbat_dis");
|
|
chip->cfg.tdie_dis = of_property_read_bool(np, "tdie_dis");
|
|
}
|
|
|
|
static int nu2105_parse_dt(struct nu2105 *chip)
|
|
{
|
|
struct device_node *np = chip->dev->of_node;
|
|
int ret;
|
|
|
|
if (!np)
|
|
return -ENODEV;
|
|
|
|
ret = of_property_read_u32(np, "ac_ovp", &chip->cfg.ac_ovp);
|
|
if (ret)
|
|
chip->cfg.ac_ovp = 17000000;
|
|
ret = of_property_read_u32(np, "bat_ucp_alm", &chip->cfg.bat_ucp_alm);
|
|
if (ret)
|
|
chip->cfg.bat_ucp_alm = 2000000;
|
|
ret = of_property_read_u32(np, "ss_timeout", &chip->cfg.ss_timeout);
|
|
if (ret)
|
|
chip->cfg.ss_timeout = 0;
|
|
ret = of_property_read_u32(np, "fsw_set", &chip->cfg.fsw_set);
|
|
if (ret)
|
|
chip->cfg.fsw_set = 500000;
|
|
ret = of_property_read_u32(np, "ibat_sns_res", &chip->cfg.ibat_sns_res);
|
|
if (ret)
|
|
chip->cfg.ibat_sns_res = 5;
|
|
ret = of_property_read_u32(np, "ibus_low_dg_set",
|
|
&chip->cfg.ibus_low_dg_set);
|
|
if (ret)
|
|
chip->cfg.ibus_low_dg_set = 10;
|
|
|
|
chip->cfg.watchdog_dis = of_property_read_bool(np, "watchdog_dis");
|
|
ret = of_property_read_u32(np, "watchdog", &chip->cfg.watchdog);
|
|
if (ret)
|
|
chip->cfg.watchdog = 30000000;
|
|
if (!chip->cfg.watchdog)
|
|
chip->cfg.watchdog_dis = true;
|
|
|
|
if (of_property_read_string(np, "chg_name", &chip->cfg.chg_name) < 0)
|
|
dev_info(chip->dev, "%s no chg name\n", __func__);
|
|
dev_info(chip->dev, "%s: chg_name1 = %s", __func__, chip->cfg.chg_name);
|
|
|
|
nu2105_parse_dt_protection(chip, np);
|
|
nu2105_parse_dt_irq(chip, np);
|
|
nu2105_parse_dt_adc(chip, np);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void determine_initial_status(struct nu2105 *chip)
|
|
{
|
|
if (chip->client->irq)
|
|
nu2105_irq_handler(chip->client->irq, chip);
|
|
}
|
|
|
|
static bool nu2105_detect_device(struct nu2105 *chip)
|
|
{
|
|
int ret;
|
|
u8 val;
|
|
|
|
ret = __nu2105_read(chip, NU2105_REG_PART_INFO, &val);
|
|
chg_id = val;
|
|
dev_err(chip->dev, "nu2105_detect_device---val=0x%x\n",val);
|
|
if (val == 0xc0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static int nu2105_disable_adc(struct nu2105 *chip)
|
|
{
|
|
dev_err(chip->dev,"%s\n",__func__);
|
|
return __nu2105_write(chip, 0x14, 0x0);
|
|
}
|
|
static void nu2105_shutdown(struct i2c_client *client)
|
|
{
|
|
struct nu2105 *chip = i2c_get_clientdata(client);
|
|
dev_err(chip->dev,"%s\n",__func__);
|
|
nu2105_disable_adc(chip);
|
|
}
|
|
|
|
|
|
static ssize_t chgid_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE, "%d\n", chg_id);
|
|
}
|
|
|
|
static DEVICE_ATTR(chgid, 0664, chgid_show, NULL);
|
|
|
|
static int nu2105_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
struct nu2105 *chip;
|
|
int ret;
|
|
|
|
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
|
|
if (!chip) {
|
|
dev_err(&client->dev, "failed to allocate memory\n");
|
|
return -ENOMEM;
|
|
}
|
|
i2c_set_clientdata(client, chip);
|
|
chip->client = client;
|
|
// chip->client->addr = 0x66;
|
|
chip->dev = &client->dev;
|
|
mutex_init(&chip->rw_lock);
|
|
mutex_init(&chip->ops_lock);
|
|
mutex_init(&chip->adc_lock);
|
|
init_completion(&chip->adc_done);
|
|
|
|
if(!nu2105_detect_device(chip)){
|
|
dev_err(&client->dev, "nu2105_detect_device failed.\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = nu2105_parse_dt(chip);
|
|
if (ret){
|
|
dev_err(&client->dev, "nu2105_parse_dt failed.\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = nu2105_hw_init(chip);
|
|
if (ret){
|
|
dev_err(&client->dev, "nu2105_hw_init failed.\n");
|
|
return ret;
|
|
}
|
|
ret = nu2105_irq_init(chip);
|
|
if (ret){
|
|
dev_err(&client->dev, "nu2105_irq_init failed.\n");
|
|
return ret;
|
|
}
|
|
|
|
determine_initial_status(chip);
|
|
|
|
ret = nu2105_charger_device_register(chip);
|
|
if (ret){
|
|
dev_err(&client->dev, "nu2105_charger_device_register failed.\n");
|
|
return ret;
|
|
}
|
|
|
|
create_debugfs_entries(chip);
|
|
device_create_file(&client->dev, &dev_attr_chgid);
|
|
// __nu2105_dump_register(chip);
|
|
nu2105_exist = 1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int nu2105_remove(struct i2c_client *client)
|
|
{
|
|
struct nu2105 *chip = i2c_get_clientdata(client);
|
|
|
|
charger_device_unregister(chip->chg_dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id nu2105_of_match[] = {
|
|
{ .compatible = "NuVolta,nu2105", },
|
|
{ },
|
|
};
|
|
|
|
static const struct i2c_device_id nu2105_i2c_id[] = {
|
|
{ .name = "nu2105", },
|
|
{ },
|
|
};
|
|
|
|
static struct i2c_driver nu2105_driver = {
|
|
.probe = nu2105_probe,
|
|
.remove = nu2105_remove,
|
|
.shutdown = nu2105_shutdown,
|
|
.driver = {
|
|
.name = "nu2105",
|
|
.of_match_table = nu2105_of_match,
|
|
},
|
|
.id_table = nu2105_i2c_id,
|
|
};
|
|
module_i2c_driver(nu2105_driver);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_AUTHOR("bing");
|
|
MODULE_DESCRIPTION("NuVolta NU2105 Switched Cap Fast Charger");
|
|
MODULE_VERSION("1.0");
|