// SPDX-License-Identifier: GPL-2.0
/*
* Chrager driver for Sc8551
*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*
* Author: Xu Shengfei <xsf@rock-chips.com>
*/
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/bitops.h>
/* Register 00h */
#define SC8551_REG_00 0x00
#define SC8551_BAT_OVP_DIS_MASK 0x80
#define SC8551_BAT_OVP_DIS_SHIFT 7
#define SC8551_BAT_OVP_ENABLE 0
#define SC8551_BAT_OVP_DISABLE 1
#define SC8551_BAT_OVP_MASK 0x3F
#define SC8551_BAT_OVP_SHIFT 0
#define SC8551_BAT_OVP_BASE 3500
#define SC8551_BAT_OVP_LSB 25
/* Register 02h */
#define SC8551_REG_02 0x02
#define SC8551_BAT_OCP_DIS_MASK 0x80
#define SC8551_BAT_OCP_DIS_SHIFT 7
#define SC8551_BAT_OCP_ENABLE 0
#define SC8551_BAT_OCP_DISABLE 1
#define SC8551_BAT_OCP_MASK 0x7F
#define SC8551_BAT_OCP_SHIFT 0
#define SC8551_BAT_OCP_BASE 2000
#define SC8551_BAT_OCP_LSB 100
/* Register 05h */
#define SC8551_REG_05 0x05
#define SC8551_AC_OVP_STAT_MASK 0x80
#define SC8551_AC_OVP_STAT_SHIFT 7
#define SC8551_AC_OVP_FLAG_MASK 0x40
#define SC8551_AC_OVP_FLAG_SHIFT 6
#define SC8551_AC_OVP_MASK_MASK 0x20
#define SC8551_AC_OVP_MASK_SHIFT 5
#define SC8551_VDROP_THRESHOLD_SET_MASK 0x10
#define SC8551_VDROP_THRESHOLD_SET_SHIFT 4
#define SC8551_VDROP_THRESHOLD_300MV 0
#define SC8551_VDROP_THRESHOLD_400MV 1
#define SC8551_VDROP_DEGLITCH_SET_MASK 0x08
#define SC8551_VDROP_DEGLITCH_SET_SHIFT 3
#define SC8551_VDROP_DEGLITCH_8US 0
#define SC8551_VDROP_DEGLITCH_5MS 1
#define SC8551_AC_OVP_MASK 0x07
#define SC8551_AC_OVP_SHIFT 0
#define SC8551_AC_OVP_BASE 11
#define SC8551_AC_OVP_LSB 1
#define SC8551_AC_OVP_6P5V 65
/* Register 06h */
#define SC8551_REG_06 0x06
#define SC8551_VBUS_PD_EN_MASK 0x80
#define SC8551_VBUS_PD_EN_SHIFT 7
#define SC8551_VBUS_PD_ENABLE 1
#define SC8551_VBUS_PD_DISABLE 0
#define SC8551_BUS_OVP_MASK 0x7F
#define SC8551_BUS_OVP_SHIFT 0
#define SC8551_BUS_OVP_BASE 6000
#define SC8551_BUS_OVP_LSB 50
/* Register 08h */
#define SC8551_REG_08 0x08
#define SC8551_BUS_OCP_DIS_MASK 0x80
#define SC8551_BUS_OCP_DIS_SHIFT 7
#define SC8551_BUS_OCP_ENABLE 0
#define SC8551_BUS_OCP_DISABLE 1
#define SC8551_IBUS_UCP_RISE_FLAG_MASK 0x40
#define SC8551_IBUS_UCP_RISE_FLAG_SHIFT 6
#define SC8551_IBUS_UCP_RISE_MASK_MASK 0x20
#define SC8551_IBUS_UCP_RISE_MASK_SHIFT 5
#define SC8551_IBUS_UCP_RISE_MASK_ENABLE 1
#define SC8551_IBUS_UCP_RISE_MASK_DISABLE 0
#define SC8551_IBUS_UCP_FALL_FLAG_MASK 0x10
#define SC8551_IBUS_UCP_FALL_FLAG_SHIFT 4
#define SC8551_BUS_OCP_MASK 0x0F
#define SC8551_BUS_OCP_SHIFT 0
#define SC8551_BUS_OCP_BASE 1000
#define SC8551_BUS_OCP_LSB 250
/* Register 0Ah */
#define SC8551_REG_0A 0x0A
#define SC8551_TSHUT_FLAG_MASK 0x80
#define SC8551_TSHUT_FLAG_SHIFT 7
#define SC8551_TSHUT_STAT_MASK 0x40
#define SC8551_TSHUT_STAT_SHIFT 6
#define SC8551_VBUS_ERRORLO_STAT_MASK 0x20
#define SC8551_VBUS_ERRORLO_STAT_SHIFT 5
#define SC8551_VBUS_ERRORHI_STAT_MASK 0x10
#define SC8551_VBUS_ERRORHI_STAT_SHIFT 4
#define SC8551_SS_TIMEOUT_FLAG_MASK 0x08
#define SC8551_SS_TIMEOUT_FLAG_SHIFT 3
#define SC8551_CONV_SWITCHING_STAT_MASK 0x04
#define SC8551_CONV_SWITCHING_STAT_SHIFT 2
#define SC8551_CONV_OCP_FLAG_MASK 0x02
#define SC8551_CONV_OCP_FLAG_SHIFT 1
#define SC8551_PIN_DIAG_FALL_FLAG_MASK 0x01
#define SC8551_PIN_DIAG_FALL_FLAG_SHIFT 0
/* Register 0Bh */
#define SC8551_REG_0B 0x0B
#define SC8551_REG_RST_MASK 0x80
#define SC8551_REG_RST_SHIFT 7
#define SC8551_REG_RST_ENABLE 1
#define SC8551_REG_RST_DISABLE 0
#define SC8551_FSW_SET_MASK 0x70
#define SC8551_FSW_SET_SHIFT 4
#define SC8551_FSW_SET_300KHZ 0
#define SC8551_FSW_SET_350KHZ 1
#define SC8551_FSW_SET_400KHZ 2
#define SC8551_FSW_SET_450KHZ 3
#define SC8551_FSW_SET_500KHZ 4
#define SC8551_FSW_SET_550KHZ 5
#define SC8551_FSW_SET_600KHZ 6
#define SC8551_FSW_SET_750KHZ 7
#define SC8551_WD_TIMEOUT_FLAG_MASK 0x08
#define SC8551_WD_TIMEOUT_SHIFT 3
#define SC8551_WATCHDOG_DIS_MASK 0x04
#define SC8551_WATCHDOG_DIS_SHIFT 2
#define SC8551_WATCHDOG_ENABLE 0
#define SC8551_WATCHDOG_DISABLE 1
#define SC8551_WATCHDOG_MASK 0x03
#define SC8551_WATCHDOG_SHIFT 0
#define SC8551_WATCHDOG_0P5S 0
#define SC8551_WATCHDOG_1S 1
#define SC8551_WATCHDOG_5S 2
#define SC8551_WATCHDOG_30S 3
/* Register 0Ch */
#define SC8551_REG_0C 0x0C
#define SC8551_CHG_EN_MASK 0x80
#define SC8551_CHG_EN_SHIFT 7
#define SC8551_CHG_ENABLE 1
#define SC8551_CHG_DISABLE 0
#define SC8551_MS_MASK 0x60
#define SC8551_MS_SHIFT 5
#define SC8551_MS_STANDALONE 0
#define SC8551_MS_SLAVE 1
#define SC8551_MS_MASTER 2
#define SC8551_ROLE_STDALONE 0
#define SC8551_ROLE_SLAVE 1
#define SC8551_ROLE_MASTER 2
#define SC8551_FREQ_SHIFT_MASK 0x18
#define SC8551_FREQ_SHIFT_SHIFT 3
#define SC8551_FREQ_SHIFT_NORMINAL 0
#define SC8551_FREQ_SHIFT_POSITIVE10 1
#define SC8551_FREQ_SHIFT_NEGATIVE10 2
#define SC8551_FREQ_SHIFT_SPREAD_SPECTRUM 3
#define SC8551_TSBUS_DIS_MASK 0x04
#define SC8551_TSBUS_DIS_SHIFT 2
#define SC8551_TSBUS_ENABLE 0
#define SC8551_TSBUS_DISABLE 1
#define SC8551_TSBAT_DIS_MASK 0x02
#define SC8551_TSBAT_DIS_SHIFT 1
#define SC8551_TSBAT_ENABLE 0
#define SC8551_TSBAT_DISABLE 1
/* Register 0Dh */
#define SC8551_REG_0D 0x0D
#define SC8551_BAT_OVP_ALM_STAT_MASK 0x80
#define SC8551_BAT_OVP_ALM_STAT_SHIFT 7
#define SC8551_BAT_OCP_ALM_STAT_MASK 0x40
#define SC8551_BAT_OCP_ALM_STAT_SHIFT 6
#define SC8551_BUS_OVP_ALM_STAT_MASK 0x20
#define SC8551_BUS_OVP_ALM_STAT_SHIFT 5
#define SC8551_BUS_OCP_ALM_STAT_MASK 0x10
#define SC8551_BUS_OCP_ALM_STAT_SHIFT 4
#define SC8551_BAT_UCP_ALM_STAT_MASK 0x08
#define SC8551_BAT_UCP_ALM_STAT_SHIFT 3
#define SC8551_ADAPTER_INSERT_STAT_MASK 0x04
#define SC8551_ADAPTER_INSERT_STAT_SHIFT 2
#define SC8551_VBAT_INSERT_STAT_MASK 0x02
#define SC8551_VBAT_INSERT_STAT_SHIFT 1
#define SC8551_ADC_DONE_STAT_MASK 0x01
#define SC8551_ADC_DONE_STAT_SHIFT 0
#define SC8551_ADC_DONE_STAT_COMPLETE 1
#define SC8551_ADC_DONE_STAT_NOTCOMPLETE 0
/* Register 0Eh */
#define SC8551_REG_0E 0x0E
#define SC8551_BAT_OVP_ALM_FLAG_MASK 0x80
#define SC8551_BAT_OVP_ALM_FLAG_SHIFT 7
#define SC8551_BAT_OCP_ALM_FLAG_MASK 0x40
#define SC8551_BAT_OCP_ALM_FLAG_SHIFT 6
#define SC8551_BUS_OVP_ALM_FLAG_MASK 0x20
#define SC8551_BUS_OVP_ALM_FLAG_SHIFT 5
#define SC8551_BUS_OCP_ALM_FLAG_MASK 0x10
#define SC8551_BUS_OCP_ALM_FLAG_SHIFT 4
#define SC8551_BAT_UCP_ALM_FLAG_MASK 0x08
#define SC8551_BAT_UCP_ALM_FLAG_SHIFT 3
#define SC8551_ADAPTER_INSERT_FLAG_MASK 0x04
#define SC8551_ADAPTER_INSERT_FLAG_SHIFT 2
#define SC8551_VBAT_INSERT_FLAG_MASK 0x02
#define SC8551_VBAT_INSERT_FLAG_SHIFT 1
#define SC8551_ADC_DONE_FLAG_MASK 0x01
#define SC8551_ADC_DONE_FLAG_SHIFT 0
#define SC8551_ADC_DONE_FLAG_COMPLETE 1
#define SC8551_ADC_DONE_FLAG_NOTCOMPLETE 0
/* Register 0Fh */
#define SC8551_REG_0F 0x0F
#define SC8551_BAT_OVP_ALM_MASK_MASK 0x80
#define SC8551_BAT_OVP_ALM_MASK_SHIFT 7
#define SC8551_BAT_OVP_ALM_MASK_ENABLE 1
#define SC8551_BAT_OVP_ALM_MASK_DISABLE 0
#define SC8551_BAT_OCP_ALM_MASK_MASK 0x40
#define SC8551_BAT_OCP_ALM_MASK_SHIFT 6
#define SC8551_BAT_OCP_ALM_MASK_ENABLE 1
#define SC8551_BAT_OCP_ALM_MASK_DISABLE 0
#define SC8551_BUS_OVP_ALM_MASK_MASK 0x20
#define SC8551_BUS_OVP_ALM_MASK_SHIFT 5
#define SC8551_BUS_OVP_ALM_MASK_ENABLE 1
#define SC8551_BUS_OVP_ALM_MASK_DISABLE 0
#define SC8551_BUS_OCP_ALM_MASK_MASK 0x10
#define SC8551_BUS_OCP_ALM_MASK_SHIFT 4
#define SC8551_BUS_OCP_ALM_MASK_ENABLE 1
#define SC8551_BUS_OCP_ALM_MASK_DISABLE 0
#define SC8551_BAT_UCP_ALM_MASK_MASK 0x08
#define SC8551_BAT_UCP_ALM_MASK_SHIFT 3
#define SC8551_BAT_UCP_ALM_MASK_ENABLE 1
#define SC8551_BAT_UCP_ALM_MASK_DISABLE 0
#define SC8551_ADAPTER_INSERT_MASK_MASK 0x04
#define SC8551_ADAPTER_INSERT_MASK_SHIFT 2
#define SC8551_ADAPTER_INSERT_MASK_ENABLE 1
#define SC8551_ADAPTER_INSERT_MASK_DISABLE 0
#define SC8551_VBAT_INSERT_MASK_MASK 0x02
#define SC8551_VBAT_INSERT_MASK_SHIFT 1
#define SC8551_VBAT_INSERT_MASK_ENABLE 1
#define SC8551_VBAT_INSERT_MASK_DISABLE 0
#define SC8551_ADC_DONE_MASK_MASK 0x01
#define SC8551_ADC_DONE_MASK_SHIFT 0
#define SC8551_ADC_DONE_MASK_ENABLE 1
#define SC8551_ADC_DONE_MASK_DISABLE 0
/* Register 10h */
#define SC8551_REG_10 0x10
#define SC8551_BAT_OVP_FLT_STAT_MASK 0x80
#define SC8551_BAT_OVP_FLT_STAT_SHIFT 7
#define SC8551_BAT_OCP_FLT_STAT_MASK 0x40
#define SC8551_BAT_OCP_FLT_STAT_SHIFT 6
#define SC8551_BUS_OVP_FLT_STAT_MASK 0x20
#define SC8551_BUS_OVP_FLT_STAT_SHIFT 5
#define SC8551_BUS_OCP_FLT_STAT_MASK 0x10
#define SC8551_BUS_OCP_FLT_STAT_SHIFT 4
#define SC8551_TSBUS_TSBAT_ALM_STAT_MASK 0x08
#define SC8551_TSBUS_TSBAT_ALM_STAT_SHIFT 3
#define SC8551_TSBAT_FLT_STAT_MASK 0x04
#define SC8551_TSBAT_FLT_STAT_SHIFT 2
#define SC8551_TSBUS_FLT_STAT_MASK 0x02
#define SC8551_TSBUS_FLT_STAT_SHIFT 1
#define SC8551_TDIE_ALM_STAT_MASK 0x01
#define SC8551_TDIE_ALM_STAT_SHIFT 0
/* Register 11h */
#define SC8551_REG_11 0x11
#define SC8551_BAT_OVP_FLT_FLAG_MASK 0x80
#define SC8551_BAT_OVP_FLT_FLAG_SHIFT 7
#define SC8551_BAT_OCP_FLT_FLAG_MASK 0x40
#define SC8551_BAT_OCP_FLT_FLAG_SHIFT 6
#define SC8551_BUS_OVP_FLT_FLAG_MASK 0x20
#define SC8551_BUS_OVP_FLT_FLAG_SHIFT 5
#define SC8551_BUS_OCP_FLT_FLAG_MASK 0x10
#define SC8551_BUS_OCP_FLT_FLAG_SHIFT 4
#define SC8551_TSBUS_TSBAT_ALM_FLAG_MASK 0x08
#define SC8551_TSBUS_TSBAT_ALM_FLAG_SHIFT 3
#define SC8551_TSBAT_FLT_FLAG_MASK 0x04
#define SC8551_TSBAT_FLT_FLAG_SHIFT 2
#define SC8551_TSBUS_FLT_FLAG_MASK 0x02
#define SC8551_TSBUS_FLT_FLAG_SHIFT 1
#define SC8551_TDIE_ALM_FLAG_MASK 0x01
#define SC8551_TDIE_ALM_FLAG_SHIFT 0
/* Register 12h */
#define SC8551_REG_12 0x12
#define SC8551_BAT_OVP_FLT_MASK_MASK 0x80
#define SC8551_BAT_OVP_FLT_MASK_SHIFT 7
#define SC8551_BAT_OVP_FLT_MASK_ENABLE 1
#define SC8551_BAT_OVP_FLT_MASK_DISABLE 0
#define SC8551_BAT_OCP_FLT_MASK_MASK 0x40
#define SC8551_BAT_OCP_FLT_MASK_SHIFT 6
#define SC8551_BAT_OCP_FLT_MASK_ENABLE 1
#define SC8551_BAT_OCP_FLT_MASK_DISABLE 0
#define SC8551_BUS_OVP_FLT_MASK_MASK 0x20
#define SC8551_BUS_OVP_FLT_MASK_SHIFT 5
#define SC8551_BUS_OVP_FLT_MASK_ENABLE 1
#define SC8551_BUS_OVP_FLT_MASK_DISABLE 0
#define SC8551_BUS_OCP_FLT_MASK_MASK 0x10
#define SC8551_BUS_OCP_FLT_MASK_SHIFT 4
#define SC8551_BUS_OCP_FLT_MASK_ENABLE 1
#define SC8551_BUS_OCP_FLT_MASK_DISABLE 0
#define SC8551_TSBUS_TSBAT_ALM_MASK_MASK 0x08
#define SC8551_TSBUS_TSBAT_ALM_MASK_SHIFT 3
#define SC8551_TSBUS_TSBAT_ALM_MASK_ENABLE 1
#define SC8551_TSBUS_TSBAT_ALM_MASK_DISABLE 0
#define SC8551_TSBAT_FLT_MASK_MASK 0x04
#define SC8551_TSBAT_FLT_MASK_SHIFT 2
#define SC8551_TSBAT_FLT_MASK_ENABLE 1
#define SC8551_TSBAT_FLT_MASK_DISABLE 0
#define SC8551_TSBUS_FLT_MASK_MASK 0x02
#define SC8551_TSBUS_FLT_MASK_SHIFT 1
#define SC8551_TSBUS_FLT_MASK_ENABLE 1
#define SC8551_TSBUS_FLT_MASK_DISABLE 0
#define SC8551_TDIE_ALM_MASK_MASK 0x01
#define SC8551_TDIE_ALM_MASK_SHIFT 0
#define SC8551_TDIE_ALM_MASK_ENABLE 1
#define SC8551_TDIE_ALM_MASK_DISABLE 0
/* Register 13h */
#define SC8551_REG_13 0x13
#define SC8551_DEV_ID_MASK 0xFF
#define SC8551_DEV_ID_SHIFT 0
/* Register 14h */
#define SC8551_REG_14 0x14
#define SC8551_ADC_EN_MASK 0x80
#define SC8551_ADC_EN_SHIFT 7
#define SC8551_ADC_ENABLE 1
#define SC8551_ADC_DISABLE 0
#define SC8551_ADC_RATE_MASK 0x40
#define SC8551_ADC_RATE_SHIFT 6
#define SC8551_ADC_RATE_CONTINOUS 0
#define SC8551_ADC_RATE_ONESHOT 1
#define SC8551_IBUS_ADC_DIS_MASK 0x01
#define SC8551_IBUS_ADC_DIS_SHIFT 0
#define SC8551_IBUS_ADC_ENABLE 0
#define SC8551_IBUS_ADC_DISABLE 1
/* Register 15h */
#define SC8551_REG_15 0x15
#define SC8551_VBUS_ADC_DIS_MASK 0x80
#define SC8551_VBUS_ADC_DIS_SHIFT 7
#define SC8551_VBUS_ADC_ENABLE 0
#define SC8551_VBUS_ADC_DISABLE 1
#define SC8551_VAC_ADC_DIS_MASK 0x40
#define SC8551_VAC_ADC_DIS_SHIFT 6
#define SC8551_VAC_ADC_ENABLE 0
#define SC8551_VAC_ADC_DISABLE 1
#define SC8551_VOUT_ADC_DIS_MASK 0x20
#define SC8551_VOUT_ADC_DIS_SHIFT 5
#define SC8551_VOUT_ADC_ENABLE 0
#define SC8551_VOUT_ADC_DISABLE 1
#define SC8551_VBAT_ADC_DIS_MASK 0x10
#define SC8551_VBAT_ADC_DIS_SHIFT 4
#define SC8551_VBAT_ADC_ENABLE 0
#define SC8551_VBAT_ADC_DISABLE 1
#define SC8551_IBAT_ADC_DIS_MASK 0x08
#define SC8551_IBAT_ADC_DIS_SHIFT 3
#define SC8551_IBAT_ADC_ENABLE 0
#define SC8551_IBAT_ADC_DISABLE 1
#define SC8551_TSBUS_ADC_DIS_MASK 0x04
#define SC8551_TSBUS_ADC_DIS_SHIFT 2
#define SC8551_TSBUS_ADC_ENABLE 0
#define SC8551_TSBUS_ADC_DISABLE 1
#define SC8551_TSBAT_ADC_DIS_MASK 0x02
#define SC8551_TSBAT_ADC_DIS_SHIFT 1
#define SC8551_TSBAT_ADC_ENABLE 0
#define SC8551_TSBAT_ADC_DISABLE 1
#define SC8551_TDIE_ADC_DIS_MASK 0x01
#define SC8551_TDIE_ADC_DIS_SHIFT 0
#define SC8551_TDIE_ADC_ENABLE 0
#define SC8551_TDIE_ADC_DISABLE 1
/* Register 16h */
#define SC8551_REG_16 0x16
#define SC8551_IBUS_POL_H_MASK 0x0F
/* Register 17h */
#define SC8551_REG_17 0x17
#define SC8551_IBUS_POL_L_MASK 0xFF
/* Register 18h */
#define SC8551_REG_18 0x18
#define SC8551_VBUS_POL_H_MASK 0x0F
/* Register 19h */
#define SC8551_REG_19 0x19
#define SC8551_VBUS_POL_L_MASK 0xFF
/* Register 1Ah */
#define SC8551_REG_1A 0x1A
#define SC8551_VAC_POL_H_MASK 0x0F
/* Register 1Bh */
#define SC8551_REG_1B 0x1B
#define SC8551_VAC_POL_L_MASK 0xFF
/* Register 1Ch */
#define SC8551_REG_1C 0x1C
#define SC8551_VOUT_POL_H_MASK 0x0F
/* Register 1Dh */
#define SC8551_REG_1D 0x1D
#define SC8551_VOUT_POL_L_MASK 0x0F
/* Register 1Eh */
#define SC8551_REG_1E 0x1E
#define SC8551_VBAT_POL_H_MASK 0x0F
/* Register 1Fh */
#define SC8551_REG_1F 0x1F
#define SC8551_VBAT_POL_L_MASK 0xFF
/* Register 20h */
#define SC8551_REG_20 0x20
#define SC8551_IBAT_POL_H_MASK 0x0F
/* Register 21h */
#define SC8551_REG_21 0x21
#define SC8551_IBAT_POL_L_MASK 0xFF
/* Register 26h */
#define SC8551_REG_26 0x26
#define SC8551_TDIE_POL_H_MASK 0x01
/* Register 2Bh */
#define SC8551_REG_2B 0x2B
#define SC8551_SS_TIMEOUT_SET_MASK 0xE0
#define SC8551_SS_TIMEOUT_SET_SHIFT 5
#define SC8551_SS_TIMEOUT_DISABLE 0
#define SC8551_SS_TIMEOUT_12P5MS 1
#define SC8551_SS_TIMEOUT_25MS 2
#define SC8551_SS_TIMEOUT_50MS 3
#define SC8551_SS_TIMEOUT_100MS 4
#define SC8551_SS_TIMEOUT_400MS 5
#define SC8551_SS_TIMEOUT_1500MS 6
#define SC8551_SS_TIMEOUT_100000MS 7
#define SC8551_EN_REGULATION_MASK 0x10
#define SC8551_EN_REGULATION_SHIFT 4
#define SC8551_EN_REGULATION_ENABLE 1
#define SC8551_EN_REGULATION_DISABLE 0
#define SC8551_VOUT_OVP_DIS_MASK 0x08
#define SC8551_VOUT_OVP_DIS_SHIFT 3
#define SC8551_VOUT_OVP_ENABLE 1
#define SC8551_VOUT_OVP_DISABLE 0
#define SC8551_IBUS_UCP_RISE_TH_MASK 0x04
#define SC8551_IBUS_UCP_RISE_TH_SHIFT 2
#define SC8551_IBUS_UCP_RISE_150MA 0
#define SC8551_IBUS_UCP_RISE_250MA 1
#define SC8551_SET_IBAT_SNS_RES_MASK 0x02
#define SC8551_SET_IBAT_SNS_RES_SHIFT 1
#define SC8551_SET_IBAT_SNS_RES_2MHM 0
#define SC8551_SET_IBAT_SNS_RES_5MHM 1
#define SC8551_VAC_PD_EN_MASK 0x01
#define SC8551_VAC_PD_EN_SHIFT 0
#define SC8551_VAC_PD_ENABLE 1
#define SC8551_VAC_PD_DISABLE 0
/* Register 2Ch */
#define SC8551_REG_2C 0x2C
#define SC8551_IBAT_REG_MASK 0xC0
#define SC8551_IBAT_REG_SHIFT 6
#define SC8551_IBAT_REG_200MA 0
#define SC8551_IBAT_REG_300MA 1
#define SC8551_IBAT_REG_400MA 2
#define SC8551_IBAT_REG_500MA 3
#define SC8551_VBAT_REG_MASK 0x30
#define SC8551_VBAT_REG_SHIFT 4
#define SC8551_VBAT_REG_50MV 0
#define SC8551_VBAT_REG_100MV 1
#define SC8551_VBAT_REG_150MV 2
#define SC8551_VBAT_REG_200MV 3
#define SC8551_VBAT_REG_ACTIVE_STAT_MASK 0x08
#define SC8551_IBAT_REG_ACTIVE_STAT_MASK 0x04
#define SC8551_VDROP_OVP_ACTIVE_STAT_MASK 0x02
#define SC8551_VOUT_OVP_ACTIVE_STAT_MASK 0x01
#define SC8551_REG_2D 0x2D
#define SC8551_VBAT_REG_ACTIVE_FLAG_MASK 0x80
#define SC8551_IBAT_REG_ACTIVE_FLAG_MASK 0x40
#define SC8551_VDROP_OVP_FLAG_MASK 0x20
#define SC8551_VOUT_OVP_FLAG_MASK 0x10
#define SC8551_VBAT_REG_ACTIVE_MASK_MASK 0x08
#define SC8551_IBAT_REG_ACTIVE_MASK_MASK 0x04
#define SC8551_VDROP_OVP_MASK_MASK 0x02
#define SC8551_VOUT_OVP_MASK_MASK 0x01
#define SC8551_REG_2E 0x2E
#define SC8551_IBUS_LOW_DG_MASK 0x08
#define SC8551_IBUS_LOW_DG_SHIFT 3
#define SC8551_IBUS_LOW_DG_10US 0
#define SC8551_IBUS_LOW_DG_5MS 1
#define SC8551_REG_2F 0x2F
#define SC8551_PMID2OUT_UVP_FLAG_MASK 0x08
#define SC8551_PMID2OUT_OVP_FLAG_MASK 0x04
#define SC8551_PMID2OUT_UVP_STAT_MASK 0x02
#define SC8551_PMID2OUT_OVP_STAT_MASK 0x01
#define SC8551_REG_30 0x30
#define SC8551_IBUS_REG_EN_MASK 0x80
#define SC8551_IBUS_REG_EN_SHIFT 7
#define SC8551_IBUS_REG_ENABLE 1
#define SC8551_IBUS_REG_DISABLE 0
#define SC8551_IBUS_REG_ACTIVE_STAT_MASK 0x40
#define SC8551_IBUS_REG_ACTIVE_FLAG_MASK 0x20
#define SC8551_IBUS_REG_ACTIVE_MASK_MASK 0x10
#define SC8551_IBUS_REG_ACTIVE_MASK_SHIFT 4
#define SC8551_IBUS_REG_ACTIVE_NOT_MASK 0
#define SC8551_IBUS_REG_ACTIVE_MASK 1
#define SC8551_IBUS_REG_MASK 0x0F
#define SC8551_IBUS_REG_SHIFT 0
#define SC8551_IBUS_REG_BASE 1000
#define SC8551_IBUS_REG_LSB 250
#define SC8551_REG_31 0x31
#define SC8551_CHARGE_MODE_MASK 0x01
#define SC8551_CHARGE_MODE_SHIFT 0
#define SC8551_CHARGE_MODE_2_1 0
#define SC8551_CHARGE_MODE_1_1 1
#define SC8551_REG_35 0x35
#define SC8551_VBUS_IN_RANGE_MASK 0x01
#define SC8551_VBUS_IN_RANGE_SHIFT 6
#define SC8551_VBUS_IN_RANGE_ENABLE 0
#define SC8551_VBUS_IN_RANGE_DISABLE 1
#define SC8551_REG_36 0x36
#define SC8551_OVPGATE_MASK 0x01
#define SC8551_OVPGATE_SHIFT 3
#define SC8551_OVPGATE_ENABLE 0
#define SC8551_OVPGATE_DISABLE 1
#define VBUS_INSERT BIT(2)
#define VBAT_INSERT BIT(1)
#define ADC_DONE BIT(0)
#define BAT_OVP_FAULT BIT(7)
#define BAT_OCP_FAULT BIT(6)
#define BUS_OVP_FAULT BIT(5)
#define BUS_OCP_FAULT BIT(4)
/*below used for comm with other module*/
#define BAT_OVP_FAULT_SHIFT 0
#define BAT_OCP_FAULT_SHIFT 1
#define BUS_OVP_FAULT_SHIFT 2
#define BUS_OCP_FAULT_SHIFT 3
#define BAT_THERM_FAULT_SHIFT 4
#define BUS_THERM_FAULT_SHIFT 5
#define DIE_THERM_FAULT_SHIFT 6
#define BAT_OVP_FAULT_MASK (1 << BAT_OVP_FAULT_SHIFT)
#define BAT_OCP_FAULT_MASK (1 << BAT_OCP_FAULT_SHIFT)
#define BUS_OVP_FAULT_MASK (1 << BUS_OVP_FAULT_SHIFT)
#define BUS_OCP_FAULT_MASK (1 << BUS_OCP_FAULT_SHIFT)
#define BAT_THERM_FAULT_MASK (1 << BAT_THERM_FAULT_SHIFT)
#define BUS_THERM_FAULT_MASK (1 << BUS_THERM_FAULT_SHIFT)
#define DIE_THERM_FAULT_MASK (1 << DIE_THERM_FAULT_SHIFT)
#define BAT_OVP_ALARM_SHIFT 0
#define BAT_OCP_ALARM_SHIFT 1
#define BUS_OVP_ALARM_SHIFT 2
#define BUS_OCP_ALARM_SHIFT 3
#define BAT_THERM_ALARM_SHIFT 4
#define BUS_THERM_ALARM_SHIFT 5
#define DIE_THERM_ALARM_SHIFT 6
#define BAT_UCP_ALARM_SHIFT 7
#define BAT_OVP_ALARM_MASK (1 << BAT_OVP_ALARM_SHIFT)
#define BAT_OCP_ALARM_MASK (1 << BAT_OCP_ALARM_SHIFT)
#define BUS_OVP_ALARM_MASK (1 << BUS_OVP_ALARM_SHIFT)
#define BUS_OCP_ALARM_MASK (1 << BUS_OCP_ALARM_SHIFT)
#define BAT_THERM_ALARM_MASK (1 << BAT_THERM_ALARM_SHIFT)
#define BUS_THERM_ALARM_MASK (1 << BUS_THERM_ALARM_SHIFT)
#define DIE_THERM_ALARM_MASK (1 << DIE_THERM_ALARM_SHIFT)
#define BAT_UCP_ALARM_MASK (1 << BAT_UCP_ALARM_SHIFT)
#define VBAT_REG_STATUS_SHIFT 0
#define IBAT_REG_STATUS_SHIFT 1
#define VBAT_REG_STATUS_MASK (1 << VBAT_REG_STATUS_SHIFT)
#define IBAT_REG_STATUS_MASK (1 << VBAT_REG_STATUS_SHIFT)
#define SC8551_DEBUG_BUF_LEN 30
enum {
ADC_IBUS,
ADC_VBUS,
ADC_VAC,
ADC_VOUT,
ADC_VBAT,
ADC_IBAT,
ADC_TBUS,
ADC_TBAT,
ADC_TDIE,
ADC_MAX_NUM,
};
struct sc8551_cfg {
bool bat_ovp_disable;
bool bat_ocp_disable;
int bat_ovp_th;
int bat_ovp_alm_th;
int bat_ocp_th;
bool bus_ocp_disable;
int bus_ovp_th;
int bus_ocp_th;
int ac_ovp_th;
bool bat_therm_disable;
bool bus_therm_disable;
bool die_therm_disable;
int sense_r_mohm;
};
struct sc8551 {
struct device *dev;
struct i2c_client *client;
int part_no;
int revision;
int mode;
struct mutex data_lock;
struct mutex i2c_rw_lock;
int irq;
bool batt_present;
bool vbus_present;
bool usb_present;
bool charge_enabled;
int vbus_error;
/* ADC reading */
int vbat_volt;
int vbus_volt;
int vout_volt;
int vac_volt;
int ibat_curr;
int ibus_curr;
int die_temp;
/* alarm/fault status */
bool bat_ovp_fault;
bool bat_ocp_fault;
bool bus_ovp_fault;
bool bus_ocp_fault;
bool vbat_reg;
bool ibat_reg;
int prev_alarm;
int prev_fault;
struct sc8551_cfg *cfg;
struct power_supply_desc psy_desc;
struct power_supply_config psy_cfg;
struct power_supply *fc2_psy;
};
static int __sc8551_read_byte(struct sc8551 *sc, u8 reg, u8 *data)
{
s32 ret;
ret = i2c_smbus_read_byte_data(sc->client, reg);
if (ret < 0) {
dev_err(sc->dev, "i2c read fail: can't read from reg 0x%02X\n", reg);
return ret;
}
*data = (u8) ret;
return 0;
}
static int __sc8551_write_byte(struct sc8551 *sc, int reg, u8 val)
{
s32 ret;
ret = i2c_smbus_write_byte_data(sc->client, reg, val);
if (ret < 0) {
dev_err(sc->dev, "i2c write fail: can't write 0x%02X to reg 0x%02X: %d\n",
val, reg, ret);
return ret;
}
return 0;
}
static int sc8551_read_byte(struct sc8551 *sc, u8 reg, u8 *data)
{
int ret;
mutex_lock(&sc->i2c_rw_lock);
ret = __sc8551_read_byte(sc, reg, data);
mutex_unlock(&sc->i2c_rw_lock);
return ret;
}
static int sc8551_write_byte(struct sc8551 *sc, u8 reg, u8 data)
{
int ret;
mutex_lock(&sc->i2c_rw_lock);
ret = __sc8551_write_byte(sc, reg, data);
mutex_unlock(&sc->i2c_rw_lock);
return ret;
}
static int sc8551_update_bits(struct sc8551 *sc,
u8 reg,
u8 mask,
u8 data)
{
int ret;
u8 tmp;
mutex_lock(&sc->i2c_rw_lock);
ret = __sc8551_read_byte(sc, reg, &tmp);
if (ret) {
dev_err(sc->dev, "Failed: reg=%02X, ret=%d\n", reg, ret);
goto out;
}
tmp &= ~mask;
tmp |= data & mask;
ret = __sc8551_write_byte(sc, reg, tmp);
if (ret)
dev_err(sc->dev, "Failed: reg=%02X, ret=%d\n", reg, ret);
out:
mutex_unlock(&sc->i2c_rw_lock);
return ret;
}
static int sc8551_enable_charge(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_CHG_ENABLE;
else
val = SC8551_CHG_DISABLE;
val <<= SC8551_CHG_EN_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_0C,
SC8551_CHG_EN_MASK,
val);
return ret;
}
static int sc8551_check_charge_enabled(struct sc8551 *sc, bool *enabled)
{
int ret;
u8 val;
ret = sc8551_read_byte(sc, SC8551_REG_0C, &val);
if (!ret)
*enabled = !!(val & SC8551_CHG_EN_MASK);
return ret;
}
static int sc8551_enable_wdt(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_WATCHDOG_ENABLE;
else
val = SC8551_WATCHDOG_DISABLE;
val <<= SC8551_WATCHDOG_DIS_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_0B,
SC8551_WATCHDOG_DIS_MASK,
val);
return ret;
}
static int sc8551_set_wdt(struct sc8551 *sc, int ms)
{
int ret;
u8 val;
if (ms == 500)
val = SC8551_WATCHDOG_0P5S;
else if (ms == 1000)
val = SC8551_WATCHDOG_1S;
else if (ms == 5000)
val = SC8551_WATCHDOG_5S;
else if (ms == 30000)
val = SC8551_WATCHDOG_30S;
else
val = SC8551_WATCHDOG_30S;
val <<= SC8551_WATCHDOG_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_0B,
SC8551_WATCHDOG_MASK,
val);
return ret;
}
static int sc8551_enable_batovp(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_BAT_OVP_ENABLE;
else
val = SC8551_BAT_OVP_DISABLE;
val <<= SC8551_BAT_OVP_DIS_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_00,
SC8551_BAT_OVP_DIS_MASK,
val);
return ret;
}
static int sc8551_set_batovp_th(struct sc8551 *sc, int threshold)
{
int ret;
u8 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(sc,
SC8551_REG_00,
SC8551_BAT_OVP_MASK,
val);
return ret;
}
static int sc8551_enable_batocp(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_BAT_OCP_ENABLE;
else
val = SC8551_BAT_OCP_DISABLE;
val <<= SC8551_BAT_OCP_DIS_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_02,
SC8551_BAT_OCP_DIS_MASK,
val);
return ret;
}
static int sc8551_set_batocp_th(struct sc8551 *sc, int threshold)
{
int ret;
u8 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(sc,
SC8551_REG_02,
SC8551_BAT_OCP_MASK,
val);
return ret;
}
static int sc8551_set_busovp_th(struct sc8551 *sc, int threshold)
{
int ret;
u8 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(sc,
SC8551_REG_06,
SC8551_BUS_OVP_MASK,
val);
return ret;
}
static int sc8551_enable_busocp(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_BUS_OCP_ENABLE;
else
val = SC8551_BUS_OCP_DISABLE;
val <<= SC8551_BUS_OCP_DIS_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_08,
SC8551_BUS_OCP_DIS_MASK,
val);
return ret;
}
static int sc8551_set_busocp_th(struct sc8551 *sc, int threshold)
{
int ret;
u8 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(sc,
SC8551_REG_08,
SC8551_BUS_OCP_MASK,
val);
return ret;
}
static int sc8551_set_acovp_th(struct sc8551 *sc, int threshold)
{
int ret;
u8 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(sc, SC8551_REG_05,
SC8551_AC_OVP_MASK, val);
return ret;
}
static int sc8551_set_vdrop_th(struct sc8551 *sc, int threshold)
{
int ret;
u8 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(sc, SC8551_REG_05,
SC8551_VDROP_THRESHOLD_SET_MASK,
val);
return ret;
}
static int sc8551_set_vdrop_deglitch(struct sc8551 *sc, int us)
{
int ret;
u8 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(sc,
SC8551_REG_05,
SC8551_VDROP_DEGLITCH_SET_MASK,
val);
return ret;
}
static int sc8551_enable_bat_therm(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_TSBAT_ENABLE;
else
val = SC8551_TSBAT_DISABLE;
val <<= SC8551_TSBAT_DIS_SHIFT;
ret = sc8551_update_bits(sc, SC8551_REG_0C,
SC8551_TSBAT_DIS_MASK, val);
return ret;
}
static int sc8551_enable_bus_therm(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_TSBUS_ENABLE;
else
val = SC8551_TSBUS_DISABLE;
val <<= SC8551_TSBUS_DIS_SHIFT;
ret = sc8551_update_bits(sc, SC8551_REG_0C,
SC8551_TSBUS_DIS_MASK, val);
return ret;
}
static int sc8551_enable_adc(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_ADC_ENABLE;
else
val = SC8551_ADC_DISABLE;
val <<= SC8551_ADC_EN_SHIFT;
ret = sc8551_update_bits(sc, SC8551_REG_14,
SC8551_ADC_EN_MASK, val);
return ret;
}
static int sc8551_set_adc_scanrate(struct sc8551 *sc, bool oneshot)
{
int ret;
u8 val;
if (oneshot)
val = SC8551_ADC_RATE_ONESHOT;
else
val = SC8551_ADC_RATE_CONTINOUS;
val <<= SC8551_ADC_RATE_SHIFT;
ret = sc8551_update_bits(sc, SC8551_REG_14,
SC8551_ADC_RATE_MASK, val);
return ret;
}
static int sc8551_get_adc_data(struct sc8551 *sc, int channel, int *result)
{
u8 val_l = 0, val_h = 0;
u16 val = 0;
int ret = 0;
if (channel >= ADC_MAX_NUM)
return 0;
ret = sc8551_read_byte(sc, SC8551_REG_16 + (channel << 1), &val_h);
if (ret < 0)
return ret;
ret = sc8551_read_byte(sc, SC8551_REG_16 + (channel << 1) + 1, &val_l);
if (ret < 0)
return ret;
val = (val_h << 8) | val_l;
if (channel == ADC_IBUS)
val = val * 15625 / 10000;
else if (channel == ADC_VBUS)
val = val * 375 / 100;
else if (channel == ADC_VAC)
val = val * 5;
else if (channel == ADC_VOUT)
val = val * 125 / 100;
else if (channel == ADC_VBAT)
val = val * 125 / 100;
else if (channel == ADC_IBAT)
val = val * 3125 / 1000;
else if (channel == ADC_TDIE)
val = val * 5 / 10;
*result = val;
return ret;
}
static int sc8551_set_adc_scan(struct sc8551 *sc, int channel, bool enable)
{
int ret;
u8 reg;
u8 mask;
u8 shift;
u8 val;
if (channel > ADC_MAX_NUM)
return -EINVAL;
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(sc, reg, mask, val);
return ret;
}
static int sc8551_set_alarm_int_mask(struct sc8551 *sc, u8 mask)
{
int ret;
u8 val;
ret = sc8551_read_byte(sc, SC8551_REG_0F, &val);
if (ret)
return ret;
val |= mask;
ret = sc8551_write_byte(sc, SC8551_REG_0F, val);
return ret;
}
static int sc8551_set_sense_resistor(struct sc8551 *sc, int r_mohm)
{
int ret;
u8 val;
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 -EINVAL;
val <<= SC8551_SET_IBAT_SNS_RES_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_2B,
SC8551_SET_IBAT_SNS_RES_MASK,
val);
return ret;
}
static int sc8551_enable_regulation(struct sc8551 *sc, bool enable)
{
int ret;
u8 val;
if (enable)
val = SC8551_EN_REGULATION_ENABLE;
else
val = SC8551_EN_REGULATION_DISABLE;
val <<= SC8551_EN_REGULATION_SHIFT;
ret = sc8551_update_bits(sc,
SC8551_REG_2B,
SC8551_EN_REGULATION_MASK,
val);
return ret;
}
static int sc8551_set_ss_timeout(struct sc8551 *sc, int timeout)
{
int ret;
u8 val;
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;
ret = sc8551_update_bits(sc,
SC8551_REG_2B,
SC8551_SS_TIMEOUT_SET_MASK,
val);
return ret;
}
static int sc8551_set_ibat_reg_th(struct sc8551 *sc, int th_ma)
{
int ret;
u8 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(sc,
SC8551_REG_2C,
SC8551_IBAT_REG_MASK,
val);
return ret;
}
static int sc8551_set_vbat_reg_th(struct sc8551 *sc, int th_mv)
{
int ret;
u8 val;
if (th_mv == 50)
val = SC8551_VBAT_REG_50MV;
else if (th_mv == 100)
val = SC8551_VBAT_REG_100MV;
else if (th_mv == 150)
val = SC8551_VBAT_REG_150MV;
else
val = SC8551_VBAT_REG_200MV;
val <<= SC8551_VBAT_REG_SHIFT;
ret = sc8551_update_bits(sc, SC8551_REG_2C,
SC8551_VBAT_REG_MASK,
val);
return ret;
}
static int sc8551_get_work_mode(struct sc8551 *sc, int *mode)
{
int ret;
u8 val;
ret = sc8551_read_byte(sc, SC8551_REG_0C, &val);
if (ret) {
dev_err(sc->dev, "Failed to read operation mode register\n");
return ret;
}
val = (val & SC8551_MS_MASK) >> SC8551_MS_SHIFT;
if (val == SC8551_MS_MASTER)
*mode = SC8551_ROLE_MASTER;
else if (val == SC8551_MS_SLAVE)
*mode = SC8551_ROLE_SLAVE;
else
*mode = SC8551_ROLE_STDALONE;
pr_debug("work mode:%s\n", *mode == SC8551_ROLE_STDALONE ? "Standalone" :
(*mode == SC8551_ROLE_SLAVE ? "Slave" : "Master"));
return ret;
}
static int sc8551_check_vbus_error_status(struct sc8551 *sc)
{
int ret;
u8 data;
ret = sc8551_read_byte(sc, SC8551_REG_0A, &data);
if (!ret)
sc->vbus_error = data;
return ret;
}
static void sc8551_check_alarm_status(struct sc8551 *sc)
{
u8 flag = 0;
u8 stat = 0;
int ret;
mutex_lock(&sc->data_lock);
ret = sc8551_read_byte(sc, SC8551_REG_08, &flag);
if (!ret && (flag & SC8551_IBUS_UCP_FALL_FLAG_MASK))
pr_debug("UCP_FLAG =0x%02X\n",
!!(flag & SC8551_IBUS_UCP_FALL_FLAG_MASK));
ret = sc8551_read_byte(sc, SC8551_REG_2D, &flag);
if (!ret && (flag & SC8551_VDROP_OVP_FLAG_MASK))
pr_debug("VDROP_OVP_FLAG =0x%02X\n",
!!(flag & SC8551_VDROP_OVP_FLAG_MASK));
/*read to clear alarm flag*/
ret = sc8551_read_byte(sc, SC8551_REG_0E, &flag);
if (!ret && flag)
pr_debug("INT_FLAG =0x%02X\n", flag);
ret = sc8551_read_byte(sc, SC8551_REG_0D, &stat);
if (!ret && stat != sc->prev_alarm) {
pr_debug("INT_STAT = 0X%02x\n", stat);
sc->prev_alarm = stat;
sc->batt_present = !!(stat & VBAT_INSERT);
sc->vbus_present = !!(stat & VBUS_INSERT);
}
ret = sc8551_read_byte(sc, SC8551_REG_08, &stat);
if (!ret && (stat & 0x50))
dev_err(sc->dev, "Reg[05]BUS_UCPOVP = 0x%02X\n", stat);
ret = sc8551_read_byte(sc, SC8551_REG_0A, &stat);
if (!ret && (stat & 0x02))
dev_err(sc->dev, "Reg[0A]CONV_OCP = 0x%02X\n", stat);
mutex_unlock(&sc->data_lock);
}
static void sc8551_check_fault_status(struct sc8551 *sc)
{
u8 flag = 0;
u8 stat = 0;
int ret;
mutex_lock(&sc->data_lock);
ret = sc8551_read_byte(sc, SC8551_REG_10, &stat);
if (!ret && stat)
dev_err(sc->dev, "FAULT_STAT = 0x%02X\n", stat);
ret = sc8551_read_byte(sc, SC8551_REG_11, &flag);
if (!ret && flag)
dev_err(sc->dev, "FAULT_FLAG = 0x%02X\n", flag);
if (!ret && flag != sc->prev_fault) {
sc->prev_fault = flag;
sc->bat_ovp_fault = !!(flag & BAT_OVP_FAULT);
sc->bat_ocp_fault = !!(flag & BAT_OCP_FAULT);
sc->bus_ovp_fault = !!(flag & BUS_OVP_FAULT);
sc->bus_ocp_fault = !!(flag & BUS_OCP_FAULT);
}
mutex_unlock(&sc->data_lock);
}
static int sc8551_detect_device(struct sc8551 *sc)
{
int ret;
u8 data;
ret = sc8551_read_byte(sc, SC8551_REG_13, &data);
if (ret == 0) {
sc->part_no = (data & SC8551_DEV_ID_MASK);
sc->part_no >>= SC8551_DEV_ID_SHIFT;
}
return ret;
}
static int sc8551_parse_dt(struct sc8551 *sc, struct device *dev)
{
int ret;
struct device_node *np = dev->of_node;
sc->cfg = devm_kzalloc(dev,
sizeof(struct sc8551_cfg),
GFP_KERNEL);
if (!sc->cfg)
return -ENOMEM;
sc->cfg->bat_ovp_disable = of_property_read_bool(np,
"sc,sc8551,bat-ovp-disable");
sc->cfg->bat_ocp_disable = of_property_read_bool(np,
"sc,sc8551,bat-ocp-disable");
sc->cfg->bus_ocp_disable = of_property_read_bool(np,
"sc,sc8551,bus-ocp-disable");
sc->cfg->bat_therm_disable = of_property_read_bool(np,
"sc,sc8551,bat-therm-disable");
sc->cfg->bus_therm_disable = of_property_read_bool(np,
"sc,sc8551,bus-therm-disable");
ret = of_property_read_u32(np, "sc,sc8551,bat-ovp-threshold",
&sc->cfg->bat_ovp_th);
if (ret) {
dev_err(sc->dev, "failed to read bat-ovp-threshold\n");
return ret;
}
ret = of_property_read_u32(np, "sc,sc8551,bat-ocp-threshold",
&sc->cfg->bat_ocp_th);
if (ret) {
dev_err(sc->dev, "failed to read bat-ocp-threshold\n");
return ret;
}
ret = of_property_read_u32(np, "sc,sc8551,bus-ovp-threshold",
&sc->cfg->bus_ovp_th);
if (ret) {
dev_err(sc->dev, "failed to read bus-ovp-threshold\n");
return ret;
}
ret = of_property_read_u32(np, "sc,sc8551,bus-ocp-threshold",
&sc->cfg->bus_ocp_th);
if (ret) {
dev_err(sc->dev, "failed to read bus-ocp-threshold\n");
return ret;
}
ret = of_property_read_u32(np, "sc,sc8551,ac-ovp-threshold",
&sc->cfg->ac_ovp_th);
if (ret) {
dev_err(sc->dev, "failed to read ac-ovp-threshold\n");
return ret;
}
ret = of_property_read_u32(np, "sc,sc8551,sense-resistor-mohm",
&sc->cfg->sense_r_mohm);
if (ret) {
dev_err(sc->dev, "failed to read sense-resistor-mohm\n");
return ret;
}
return 0;
}
static int sc8551_init_protection(struct sc8551 *sc)
{
int ret;
ret = sc8551_enable_batovp(sc, !sc->cfg->bat_ovp_disable);
pr_debug("%s bat ovp %s\n",
sc->cfg->bat_ovp_disable ? "disable" : "enable",
!ret ? "successfully" : "failed");
ret = sc8551_enable_batocp(sc, !sc->cfg->bat_ocp_disable);
pr_debug("%s bat ocp %s\n",
sc->cfg->bat_ocp_disable ? "disable" : "enable",
!ret ? "successfully" : "failed");
ret = sc8551_enable_busocp(sc, !sc->cfg->bus_ocp_disable);
pr_debug("%s bus ocp %s\n",
sc->cfg->bus_ocp_disable ? "disable" : "enable",
!ret ? "successfully" : "failed");
ret = sc8551_enable_bat_therm(sc, !sc->cfg->bat_therm_disable);
pr_debug("%s bat therm %s\n",
sc->cfg->bat_therm_disable ? "disable" : "enable",
!ret ? "successfully" : "failed");
ret = sc8551_enable_bus_therm(sc, !sc->cfg->bus_therm_disable);
pr_debug("%s bus therm %s\n",
sc->cfg->bus_therm_disable ? "disable" : "enable",
!ret ? "successfully" : "failed");
ret = sc8551_set_batovp_th(sc, sc->cfg->bat_ovp_th);
pr_debug("set bat ovp th %d %s\n", sc->cfg->bat_ovp_th,
!ret ? "successfully" : "failed");
ret = sc8551_set_batocp_th(sc, sc->cfg->bat_ocp_th);
pr_debug("set bat ocp threshold %d %s\n", sc->cfg->bat_ocp_th,
!ret ? "successfully" : "failed");
ret = sc8551_set_busovp_th(sc, sc->cfg->bus_ovp_th);
pr_debug("set bus ovp threshold %d %s\n", sc->cfg->bus_ovp_th,
!ret ? "successfully" : "failed");
ret = sc8551_set_busocp_th(sc, sc->cfg->bus_ocp_th);
pr_debug("set bus ocp threshold %d %s\n", sc->cfg->bus_ocp_th,
!ret ? "successfully" : "failed");
ret = sc8551_set_acovp_th(sc, sc->cfg->ac_ovp_th);
pr_debug("set ac ovp threshold %d %s\n", sc->cfg->ac_ovp_th,
!ret ? "successfully" : "failed");
return 0;
}
static int sc8551_init_adc(struct sc8551 *sc)
{
int ret;
ret = sc8551_set_adc_scanrate(sc, false);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_IBUS, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_VBUS, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_VOUT, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_VBAT, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_IBAT, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_TBUS, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_TBAT, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_TDIE, true);
if (ret)
return ret;
ret = sc8551_set_adc_scan(sc, ADC_VAC, true);
if (ret)
return ret;
ret = sc8551_enable_adc(sc, true);
if (ret)
return ret;
return 0;
}
static int sc8551_init_int_src(struct sc8551 *sc)
{
int ret;
/*TODO:be careful ts bus and ts bat alarm bit mask is in
* fault mask register.
*/
ret = sc8551_set_alarm_int_mask(sc, ADC_DONE);
if (ret)
dev_err(sc->dev, "failed to set alarm mask:%d\n", ret);
return ret;
}
static int sc8551_init_regulation(struct sc8551 *sc)
{
int ret;
ret = sc8551_set_ibat_reg_th(sc, 300);
if (ret)
return ret;
ret = sc8551_set_vbat_reg_th(sc, 100);
if (ret)
return ret;
ret = sc8551_set_vdrop_deglitch(sc, 5000);
if (ret)
return ret;
ret = sc8551_set_vdrop_th(sc, 400);
if (ret)
return ret;
ret = sc8551_enable_regulation(sc, false);
if (ret)
return ret;
ret = sc8551_write_byte(sc, SC8551_REG_2E, 0x08);
if (ret)
return ret;
return 0;
}
static int sc8551_init_device(struct sc8551 *sc)
{
int ret;
/* Reset registers to their default values */
ret = sc8551_update_bits(sc,
SC8551_REG_0B,
SC8551_REG_RST_MASK,
SC8551_REG_RST_ENABLE << SC8551_REG_RST_SHIFT);
if (ret)
return ret;
ret = sc8551_enable_wdt(sc, false);
if (ret)
return ret;
ret = sc8551_set_wdt(sc, 30000);
if (ret)
return ret;
ret = sc8551_set_ss_timeout(sc, 100000);
if (ret)
return ret;
ret = sc8551_set_sense_resistor(sc, sc->cfg->sense_r_mohm);
if (ret)
return ret;
ret = sc8551_init_protection(sc);
if (ret)
return ret;
ret = sc8551_init_adc(sc);
if (ret)
return ret;
ret = sc8551_init_int_src(sc);
if (ret)
return ret;
ret = sc8551_init_regulation(sc);
if (ret)
return ret;
return 0;
}
static int sc8551_set_present(struct sc8551 *sc, bool present)
{
sc->usb_present = present;
if (present)
sc8551_init_device(sc);
return 0;
}
static ssize_t registers_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct sc8551 *sc = dev_get_drvdata(dev);
u8 tmpbuf[SC8551_DEBUG_BUF_LEN];
int idx = 0;
int result;
u8 addr, val;
int len, ret;
ret = sc8551_get_adc_data(sc, ADC_VBAT, &result);
if (!ret)
sc->vbat_volt = result;
ret = sc8551_get_adc_data(sc, ADC_VAC, &result);
if (!ret)
sc->vac_volt = result;
ret = sc8551_get_adc_data(sc, ADC_VBUS, &result);
if (!ret)
sc->vbus_volt = result;
ret = sc8551_get_adc_data(sc, ADC_VOUT, &result);
if (!ret)
sc->vout_volt = result;
ret = sc8551_get_adc_data(sc, ADC_IBUS, &result);
if (!ret)
sc->ibus_curr = result;
ret = sc8551_get_adc_data(sc, ADC_TDIE, &result);
if (!ret)
sc->die_temp = result;
ret = sc8551_get_adc_data(sc, ADC_IBAT, &result);
if (!ret)
sc->ibat_curr = result;
dev_err(sc->dev, "vbus_vol %d vbat_vol(vout) %d vout %d, vac: %d\n",
sc->vbus_volt, sc->vbat_volt, sc->vout_volt, sc->vac_volt);
dev_err(sc->dev, "ibus_curr %d ibat_curr %d\n", sc->ibus_curr, sc->ibat_curr);
dev_err(sc->dev, "die_temp %d\n", sc->die_temp);
for (addr = SC8551_REG_00; addr <= SC8551_REG_36; addr++) {
ret = sc8551_read_byte(sc, addr, &val);
if (ret == 0) {
len = snprintf(tmpbuf, SC8551_DEBUG_BUF_LEN,
"Reg[%.2X] = 0x%.2x\n",
addr,
val);
memcpy(&buf[idx], tmpbuf, len);
idx += len;
}
}
return idx;
}
static ssize_t registers_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct sc8551 *sc = dev_get_drvdata(dev);
unsigned int reg;
unsigned int val;
int ret;
ret = sscanf(buf, "%x %x", ®, &val);
if ((ret == 2) && (reg >= SC8551_REG_00) && (reg <= SC8551_REG_36))
sc8551_write_byte(sc,
(unsigned char)reg,
(unsigned char)val);
return count;
}
static DEVICE_ATTR_RW(registers);
static void sc8551_create_device_node(struct device *dev)
{
device_create_file(dev, &dev_attr_registers);
}
static enum power_supply_property sc8551_charger_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CP_CHARGING_ENABLED,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_CP_DIE_TEMPERATURE,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CP_BAT_OVP_FAULT,
POWER_SUPPLY_PROP_CP_BAT_OCP_FAULT,
POWER_SUPPLY_PROP_CP_BUS_OVP_FAULT,
POWER_SUPPLY_PROP_CP_BUS_OCP_FAULT,
POWER_SUPPLY_PROP_CP_VBUS_HERROR_STATUS,
POWER_SUPPLY_PROP_CP_VBUS_LERROR_STATUS,
};
static int sc8551_charger_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct sc8551 *sc = power_supply_get_drvdata(psy);
int result;
u8 reg_val;
int ret;
sc8551_check_alarm_status(sc);
sc8551_check_fault_status(sc);
sc8551_check_vbus_error_status(sc);
switch (psp) {
case POWER_SUPPLY_PROP_CP_CHARGING_ENABLED:
sc8551_check_charge_enabled(sc, &sc->charge_enabled);
val->intval = sc->charge_enabled;
break;
case POWER_SUPPLY_PROP_STATUS:
val->intval = 0;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = sc->usb_present;
break;
case POWER_SUPPLY_PROP_ONLINE:
ret = sc8551_read_byte(sc, SC8551_REG_0D, ®_val);
if (!ret)
sc->vbus_present = !!(reg_val & VBUS_INSERT);
val->intval = sc->vbus_present;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = sc8551_get_adc_data(sc, ADC_VBAT, &result);
if (!ret)
sc->vbat_volt = result;
val->intval = sc->vbat_volt * 1000;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = sc8551_get_adc_data(sc, ADC_IBAT, &result);
if (!ret)
sc->ibat_curr = result;
val->intval = sc->ibat_curr * 1000;
break;
case POWER_SUPPLY_PROP_CP_VBUS: /* BUS_VOLTAGE */
ret = sc8551_get_adc_data(sc, ADC_VBUS, &result);
if (!ret)
sc->vbus_volt = result;
val->intval = sc->vbus_volt * 1000;
break;
case POWER_SUPPLY_PROP_CP_IBUS: /* BUS_CURRENT */
ret = sc8551_get_adc_data(sc, ADC_IBUS, &result);
if (!ret)
sc->ibus_curr = result;
val->intval = sc->ibus_curr * 1000;
break;
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: /* BUS_VOLTAGE */
val->intval = 12000 * 1000; /* 20V */
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: /* BUS_CURRENT */
val->intval = 4500 * 1000; /* 4.75A */
break;
case POWER_SUPPLY_PROP_CP_DIE_TEMPERATURE:/* DIE_TEMPERATURE */
ret = sc8551_get_adc_data(sc, ADC_TDIE, &result);
if (!ret)
sc->die_temp = result;
val->intval = sc->die_temp;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
val->intval = 4300 * 1000;
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = 8000 * 1000;
break;
case POWER_SUPPLY_PROP_CP_BAT_OVP_FAULT:
val->intval = sc->bat_ovp_fault;
break;
case POWER_SUPPLY_PROP_CP_BAT_OCP_FAULT:
val->intval = sc->bat_ocp_fault;
break;
case POWER_SUPPLY_PROP_CP_BUS_OVP_FAULT:
val->intval = sc->bus_ovp_fault;
break;
case POWER_SUPPLY_PROP_CP_BUS_OCP_FAULT:
val->intval = sc->bus_ocp_fault;
break;
case POWER_SUPPLY_PROP_CP_VBUS_HERROR_STATUS:
val->intval = (sc->vbus_error >> 0x04) & 0x01;
break;
case POWER_SUPPLY_PROP_CP_VBUS_LERROR_STATUS:
val->intval = (sc->vbus_error >> 0x05) & 0x01;
break;
default:
return -EINVAL;
}
return 0;
}
static int sc8551_charger_set_property(struct power_supply *psy,
enum power_supply_property prop,
const union power_supply_propval *val)
{
struct sc8551 *sc = power_supply_get_drvdata(psy);
switch (prop) {
case POWER_SUPPLY_PROP_CP_CHARGING_ENABLED:
sc8551_enable_charge(sc, val->intval);
if (val->intval)
sc8551_enable_wdt(sc, true);
else
sc8551_enable_wdt(sc, false);
sc8551_check_charge_enabled(sc, &sc->charge_enabled);
break;
case POWER_SUPPLY_PROP_PRESENT:
sc8551_set_present(sc, !!val->intval);
break;
default:
return -EINVAL;
}
return 0;
}
static int sc8551_charger_is_writeable(struct power_supply *psy,
enum power_supply_property prop)
{
int ret;
switch (prop) {
case POWER_SUPPLY_PROP_ONLINE:
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
static int sc8551_psy_register(struct sc8551 *sc)
{
sc->psy_cfg.drv_data = sc;
sc->psy_cfg.of_node = sc->dev->of_node;
sc->psy_desc.name = "sc8551-standalone";
sc->psy_desc.type = POWER_SUPPLY_TYPE_CHARGE_PUMP;
sc->psy_desc.properties = sc8551_charger_props;
sc->psy_desc.num_properties = ARRAY_SIZE(sc8551_charger_props);
sc->psy_desc.get_property = sc8551_charger_get_property;
sc->psy_desc.set_property = sc8551_charger_set_property;
sc->psy_desc.property_is_writeable = sc8551_charger_is_writeable;
sc->fc2_psy = devm_power_supply_register(sc->dev,
&sc->psy_desc,
&sc->psy_cfg);
if (IS_ERR(sc->fc2_psy)) {
dev_err(sc->dev, "failed to register fc2_psy\n");
return PTR_ERR(sc->fc2_psy);
}
return 0;
}
/*
* interrupt does nothing, just info event change, other module could get info
* through power supply interface
*/
static irqreturn_t sc8551_charger_interrupt(int irq, void *dev_id)
{
struct sc8551 *sc = dev_id;
int ret, value;
ret = sc8551_get_adc_data(sc, ADC_VOUT, &value);
if (!ret)
sc->vbat_volt = value;
ret = sc8551_get_adc_data(sc, ADC_IBAT, &value);
if (!ret)
sc->ibat_curr = value;
ret = sc8551_get_adc_data(sc, ADC_VBUS, &value);
if (!ret)
sc->vbus_volt = value;
ret = sc8551_get_adc_data(sc, ADC_IBUS, &value);
if (!ret)
sc->ibus_curr = value;
ret = sc8551_get_adc_data(sc, ADC_TDIE, &value);
if (!ret)
sc->die_temp = value;
ret = sc8551_get_adc_data(sc, ADC_IBAT, &value);
if (!ret)
sc->ibat_curr = value;
sc8551_check_alarm_status(sc);
sc8551_check_fault_status(sc);
sc8551_check_vbus_error_status(sc);
power_supply_changed(sc->fc2_psy);
return IRQ_HANDLED;
}
static int sc8551_init_irq(struct sc8551 *sc)
{
int ret;
sc->irq = sc->client->irq;
if (sc->irq <= 0) {
dev_err(sc->dev, "irq mapping fail\n");
return 0;
}
ret = devm_request_threaded_irq(sc->dev,
sc->irq,
NULL,
sc8551_charger_interrupt,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"sc8551 standalone irq",
sc);
if (ret < 0)
dev_err(sc->dev, "request irq for irq=%d failed, ret =%d\n",
sc->irq, ret);
enable_irq_wake(sc->irq);
device_init_wakeup(sc->dev, 1);
return 0;
}
static void determine_initial_status(struct sc8551 *sc)
{
if (sc->client->irq)
sc8551_charger_interrupt(sc->client->irq, sc);
}
static const struct of_device_id sc8551_charger_match[] = {
{ .compatible = "sc,sc8551-standalone", },
{},
};
static int sc8551_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct sc8551 *sc;
const struct of_device_id *match;
struct device_node *node = client->dev.of_node;
int ret;
sc = devm_kzalloc(&client->dev, sizeof(struct sc8551), GFP_KERNEL);
if (!sc)
return -ENOMEM;
sc->dev = &client->dev;
sc->client = client;
mutex_init(&sc->i2c_rw_lock);
mutex_init(&sc->data_lock);
ret = sc8551_detect_device(sc);
if (ret) {
dev_err(sc->dev, "No sc8551 device found!\n");
return -ENODEV;
}
i2c_set_clientdata(client, sc);
match = of_match_node(sc8551_charger_match, node);
if (match == NULL) {
dev_err(sc->dev, "device tree match not found!\n");
return -ENODEV;
}
sc8551_get_work_mode(sc, &sc->mode);
if (sc->mode != SC8551_ROLE_STDALONE) {
dev_err(sc->dev, "device operation mode mismatch with dts configuration\n");
return -EINVAL;
}
ret = sc8551_parse_dt(sc, &client->dev);
if (ret)
return -EIO;
ret = sc8551_init_device(sc);
if (ret) {
dev_err(sc->dev, "Failed to init device\n");
return ret;
}
ret = sc8551_psy_register(sc);
if (ret)
return ret;
ret = sc8551_init_irq(sc);
if (ret)
goto err_1;
determine_initial_status(sc);
sc8551_create_device_node(&(client->dev));
return 0;
err_1:
power_supply_unregister(sc->fc2_psy);
return ret;
}
static int sc8551_charger_remove(struct i2c_client *client)
{
struct sc8551 *sc = i2c_get_clientdata(client);
sc8551_enable_adc(sc, false);
power_supply_unregister(sc->fc2_psy);
mutex_destroy(&sc->data_lock);
mutex_destroy(&sc->i2c_rw_lock);
return 0;
}
static void sc8551_charger_shutdown(struct i2c_client *client)
{
struct sc8551 *sc = i2c_get_clientdata(client);
sc8551_enable_adc(sc, false);
}
static const struct i2c_device_id sc8551_charger_id[] = {
{"sc8551-standalone", SC8551_ROLE_STDALONE},
{},
};
static struct i2c_driver sc8551_charger_driver = {
.driver = {
.name = "sc8551-charger",
.owner = THIS_MODULE,
.of_match_table = sc8551_charger_match,
},
.id_table = sc8551_charger_id,
.probe = sc8551_charger_probe,
.remove = sc8551_charger_remove,
.shutdown = sc8551_charger_shutdown,
};
module_i2c_driver(sc8551_charger_driver);
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
MODULE_DESCRIPTION("SC SC8551 Charge Pump Driver");
MODULE_LICENSE("GPL");