You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
kernel_samsung_sm7125/drivers/power/supply/qcom_r1/smb1351-charger.c

3134 lines
79 KiB

/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/i2c.h>
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/extcon.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/power_supply.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
#include <linux/of.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/pinctrl/consumer.h>
/* Mask/Bit helpers */
#define _SMB1351_MASK(BITS, POS) \
((unsigned char)(((1 << (BITS)) - 1) << (POS)))
#define SMB1351_MASK(LEFT_BIT_POS, RIGHT_BIT_POS) \
_SMB1351_MASK((LEFT_BIT_POS) - (RIGHT_BIT_POS) + 1, \
(RIGHT_BIT_POS))
/* Configuration registers */
#define CHG_CURRENT_CTRL_REG 0x0
#define FAST_CHG_CURRENT_MASK SMB1351_MASK(7, 4)
#define AC_INPUT_CURRENT_LIMIT_MASK SMB1351_MASK(3, 0)
#define CHG_OTH_CURRENT_CTRL_REG 0x1
#define PRECHG_CURRENT_MASK SMB1351_MASK(7, 5)
#define ITERM_MASK SMB1351_MASK(4, 2)
#define USB_2_3_MODE_SEL_BIT BIT(1)
#define USB_2_3_MODE_SEL_BY_I2C 0
#define USB_2_3_MODE_SEL_BY_PIN 0x2
#define USB_5_1_CMD_POLARITY_BIT BIT(0)
#define USB_CMD_POLARITY_500_1_100_0 0
#define USB_CMD_POLARITY_500_0_100_1 0x1
#define VARIOUS_FUNC_REG 0x2
#define SUSPEND_MODE_CTRL_BIT BIT(7)
#define SUSPEND_MODE_CTRL_BY_PIN 0
#define SUSPEND_MODE_CTRL_BY_I2C 0x80
#define BATT_TO_SYS_POWER_CTRL_BIT BIT(6)
#define MAX_SYS_VOLTAGE BIT(5)
#define AICL_EN_BIT BIT(4)
#define AICL_DET_TH_BIT BIT(3)
#define APSD_EN_BIT BIT(2)
#define BATT_OV_BIT BIT(1)
#define VCHG_FUNC_BIT BIT(0)
#define VFLOAT_REG 0x3
#define PRECHG_TO_FAST_VOLTAGE_CFG_MASK SMB1351_MASK(7, 6)
#define VFLOAT_MASK SMB1351_MASK(5, 0)
#define CHG_CTRL_REG 0x4
#define AUTO_RECHG_BIT BIT(7)
#define AUTO_RECHG_ENABLE 0
#define AUTO_RECHG_DISABLE 0x80
#define ITERM_EN_BIT BIT(6)
#define ITERM_ENABLE 0
#define ITERM_DISABLE 0x40
#define MAPPED_AC_INPUT_CURRENT_LIMIT_MASK SMB1351_MASK(5, 4)
#define AUTO_RECHG_TH_BIT BIT(3)
#define AUTO_RECHG_TH_50MV 0
#define AUTO_RECHG_TH_100MV 0x8
#define AFCV_MASK SMB1351_MASK(2, 0)
#define CHG_STAT_TIMERS_CTRL_REG 0x5
#define STAT_OUTPUT_POLARITY_BIT BIT(7)
#define STAT_OUTPUT_MODE_BIT BIT(6)
#define STAT_OUTPUT_CTRL_BIT BIT(5)
#define OTH_CHG_IL_BIT BIT(4)
#define COMPLETE_CHG_TIMEOUT_MASK SMB1351_MASK(3, 2)
#define PRECHG_TIMEOUT_MASK SMB1351_MASK(1, 0)
#define CHG_PIN_EN_CTRL_REG 0x6
#define LED_BLINK_FUNC_BIT BIT(7)
#define EN_PIN_CTRL_MASK SMB1351_MASK(6, 5)
#define EN_BY_I2C_0_DISABLE 0
#define EN_BY_I2C_0_ENABLE 0x20
#define EN_BY_PIN_HIGH_ENABLE 0x40
#define EN_BY_PIN_LOW_ENABLE 0x60
#define USBCS_CTRL_BIT BIT(4)
#define USBCS_CTRL_BY_I2C 0
#define USBCS_CTRL_BY_PIN 0x10
#define USBCS_INPUT_STATE_BIT BIT(3)
#define CHG_ERR_BIT BIT(2)
#define APSD_DONE_BIT BIT(1)
#define USB_FAIL_BIT BIT(0)
#define THERM_A_CTRL_REG 0x7
#define MIN_SYS_VOLTAGE_MASK SMB1351_MASK(7, 6)
#define LOAD_BATT_10MA_FVC_BIT BIT(5)
#define THERM_MONITOR_BIT BIT(4)
#define THERM_MONITOR_EN 0
#define SOFT_COLD_TEMP_LIMIT_MASK SMB1351_MASK(3, 2)
#define SOFT_HOT_TEMP_LIMIT_MASK SMB1351_MASK(1, 0)
#define WDOG_SAFETY_TIMER_CTRL_REG 0x8
#define AICL_FAIL_OPTION_BIT BIT(7)
#define AICL_FAIL_TO_SUSPEND 0
#define AICL_FAIL_TO_150_MA 0x80
#define WDOG_TIMEOUT_MASK SMB1351_MASK(6, 5)
#define WDOG_IRQ_SAFETY_TIMER_MASK SMB1351_MASK(4, 3)
#define WDOG_IRQ_SAFETY_TIMER_EN_BIT BIT(2)
#define WDOG_OPTION_BIT BIT(1)
#define WDOG_TIMER_EN_BIT BIT(0)
#define OTG_USBIN_AICL_CTRL_REG 0x9
#define OTG_ID_PIN_CTRL_MASK SMB1351_MASK(7, 6)
#define OTG_PIN_POLARITY_BIT BIT(5)
#define DCIN_IC_GLITCH_FILTER_HV_ADAPTER_MASK SMB1351_MASK(4, 3)
#define DCIN_IC_GLITCH_FILTER_LV_ADAPTER_BIT BIT(2)
#define USBIN_AICL_CFG1_BIT BIT(1)
#define USBIN_AICL_CFG0_BIT BIT(0)
#define OTG_TLIM_CTRL_REG 0xA
#define SWITCH_FREQ_MASK SMB1351_MASK(7, 6)
#define THERM_LOOP_TEMP_SEL_MASK SMB1351_MASK(5, 4)
#define OTG_OC_LIMIT_MASK SMB1351_MASK(3, 2)
#define OTG_BATT_UVLO_TH_MASK SMB1351_MASK(1, 0)
#define HARD_SOFT_LIMIT_CELL_TEMP_REG 0xB
#define HARD_LIMIT_COLD_TEMP_ALARM_TRIP_MASK SMB1351_MASK(7, 6)
#define HARD_LIMIT_HOT_TEMP_ALARM_TRIP_MASK SMB1351_MASK(5, 4)
#define SOFT_LIMIT_COLD_TEMP_ALARM_TRIP_MASK SMB1351_MASK(3, 2)
#define SOFT_LIMIT_HOT_TEMP_ALARM_TRIP_MASK SMB1351_MASK(1, 0)
#define FAULT_INT_REG 0xC
#define HOT_COLD_HARD_LIMIT_BIT BIT(7)
#define HOT_COLD_SOFT_LIMIT_BIT BIT(6)
#define BATT_UVLO_IN_OTG_BIT BIT(5)
#define OTG_OC_BIT BIT(4)
#define INPUT_OVLO_BIT BIT(3)
#define INPUT_UVLO_BIT BIT(2)
#define AICL_DONE_FAIL_BIT BIT(1)
#define INTERNAL_OVER_TEMP_BIT BIT(0)
#define STATUS_INT_REG 0xD
#define CHG_OR_PRECHG_TIMEOUT_BIT BIT(7)
#define RID_CHANGE_BIT BIT(6)
#define BATT_OVP_BIT BIT(5)
#define FAST_TERM_TAPER_RECHG_INHIBIT_BIT BIT(4)
#define WDOG_TIMER_BIT BIT(3)
#define POK_BIT BIT(2)
#define BATT_MISSING_BIT BIT(1)
#define BATT_LOW_BIT BIT(0)
#define VARIOUS_FUNC_2_REG 0xE
#define CHG_HOLD_OFF_TIMER_AFTER_PLUGIN_BIT BIT(7)
#define CHG_INHIBIT_BIT BIT(6)
#define FAST_CHG_CC_IN_BATT_SOFT_LIMIT_MODE_BIT BIT(5)
#define FVCL_IN_BATT_SOFT_LIMIT_MODE_MASK SMB1351_MASK(4, 3)
#define HARD_TEMP_LIMIT_BEHAVIOR_BIT BIT(2)
#define PRECHG_TO_FASTCHG_BIT BIT(1)
#define STAT_PIN_CONFIG_BIT BIT(0)
#define FLEXCHARGER_REG 0x10
#define AFVC_IRQ_BIT BIT(7)
#define CHG_CONFIG_MASK SMB1351_MASK(6, 4)
#define LOW_BATT_VOLTAGE_DET_TH_MASK SMB1351_MASK(3, 0)
#define VARIOUS_FUNC_3_REG 0x11
#define SAFETY_TIMER_EN_MASK SMB1351_MASK(7, 6)
#define BLOCK_SUSPEND_DURING_VBATT_LOW_BIT BIT(5)
#define TIMEOUT_SEL_FOR_APSD_BIT BIT(4)
#define SDP_SUSPEND_BIT BIT(3)
#define QC_2P1_AUTO_INCREMENT_MODE_BIT BIT(2)
#define QC_2P1_AUTH_ALGO_BIT BIT(1)
#define DCD_EN_BIT BIT(0)
#define HVDCP_BATT_MISSING_CTRL_REG 0x12
#define HVDCP_ADAPTER_SEL_MASK SMB1351_MASK(7, 6)
#define HVDCP_EN_BIT BIT(5)
#define HVDCP_AUTO_INCREMENT_LIMIT_BIT BIT(4)
#define BATT_MISSING_ON_INPUT_PLUGIN_BIT BIT(3)
#define BATT_MISSING_2P6S_POLLER_BIT BIT(2)
#define BATT_MISSING_ALGO_BIT BIT(1)
#define BATT_MISSING_THERM_PIN_SOURCE_BIT BIT(0)
#define PON_OPTIONS_REG 0x13
#define SYSOK_INOK_POLARITY_BIT BIT(7)
#define SYSOK_OPTIONS_MASK SMB1351_MASK(6, 4)
#define INPUT_MISSING_POLLER_CONFIG_BIT BIT(3)
#define VBATT_LOW_DISABLED_OR_RESET_STATE_BIT BIT(2)
#define QC_2P1_AUTH_ALGO_IRQ_EN_BIT BIT(0)
#define OTG_MODE_POWER_OPTIONS_REG 0x14
#define ADAPTER_CONFIG_MASK SMB1351_MASK(7, 6)
#define MAP_HVDCP_BIT BIT(5)
#define SDP_LOW_BATT_FORCE_USB5_OVER_USB1_BIT BIT(4)
#define OTG_HICCUP_MODE_BIT BIT(2)
#define INPUT_CURRENT_LIMIT_MASK SMB1351_MASK(1, 0)
#define CHARGER_I2C_CTRL_REG 0x15
#define FULLON_MODE_EN_BIT BIT(7)
#define I2C_HS_MODE_EN_BIT BIT(6)
#define SYSON_LDO_OUTPUT_SEL_BIT BIT(5)
#define VBATT_TRACKING_VOLTAGE_DIFF_BIT BIT(4)
#define DISABLE_AFVC_WHEN_ENTER_TAPER_BIT BIT(3)
#define VCHG_IINV_BIT BIT(2)
#define AFVC_OVERRIDE_BIT BIT(1)
#define SYSOK_PIN_CONFIG_BIT BIT(0)
#define VERSION_REG 0x2E
#define VERSION_MASK BIT(1)
/* Command registers */
#define CMD_I2C_REG 0x30
#define CMD_RELOAD_BIT BIT(7)
#define CMD_BQ_CFG_ACCESS_BIT BIT(6)
#define CMD_INPUT_LIMIT_REG 0x31
#define CMD_OVERRIDE_BIT BIT(7)
#define CMD_SUSPEND_MODE_BIT BIT(6)
#define CMD_INPUT_CURRENT_MODE_BIT BIT(3)
#define CMD_INPUT_CURRENT_MODE_APSD 0
#define CMD_INPUT_CURRENT_MODE_CMD 0x08
#define CMD_USB_2_3_SEL_BIT BIT(2)
#define CMD_USB_2_MODE 0
#define CMD_USB_3_MODE 0x4
#define CMD_USB_1_5_AC_CTRL_MASK SMB1351_MASK(1, 0)
#define CMD_USB_100_MODE 0
#define CMD_USB_500_MODE 0x2
#define CMD_USB_AC_MODE 0x1
#define CMD_CHG_REG 0x32
#define CMD_DISABLE_THERM_MONITOR_BIT BIT(4)
#define CMD_TURN_OFF_STAT_PIN_BIT BIT(3)
#define CMD_PRE_TO_FAST_EN_BIT BIT(2)
#define CMD_CHG_EN_BIT BIT(1)
#define CMD_CHG_DISABLE 0
#define CMD_CHG_ENABLE 0x2
#define CMD_OTG_EN_BIT BIT(0)
#define CMD_DEAD_BATT_REG 0x33
#define CMD_STOP_DEAD_BATT_TIMER_MASK SMB1351_MASK(7, 0)
#define CMD_HVDCP_REG 0x34
#define CMD_APSD_RE_RUN_BIT BIT(7)
#define CMD_FORCE_HVDCP_2P0_BIT BIT(5)
#define CMD_HVDCP_MODE_MASK SMB1351_MASK(5, 0)
/* Status registers */
#define STATUS_0_REG 0x36
#define STATUS_AICL_BIT BIT(7)
#define STATUS_INPUT_CURRENT_LIMIT_MASK SMB1351_MASK(6, 5)
#define STATUS_DCIN_INPUT_CURRENT_LIMIT_MASK SMB1351_MASK(4, 0)
#define STATUS_1_REG 0x37
#define STATUS_INPUT_RANGE_MASK SMB1351_MASK(7, 4)
#define STATUS_INPUT_USB_BIT BIT(0)
#define STATUS_2_REG 0x38
#define STATUS_FAST_CHG_BIT BIT(7)
#define STATUS_HARD_LIMIT_BIT BIT(6)
#define STATUS_FLOAT_VOLTAGE_MASK SMB1351_MASK(5, 0)
#define STATUS_3_REG 0x39
#define STATUS_CHG_BIT BIT(7)
#define STATUS_PRECHG_CURRENT_MASK SMB1351_MASK(6, 4)
#define STATUS_FAST_CHG_CURRENT_MASK SMB1351_MASK(3, 0)
#define STATUS_4_REG 0x3A
#define STATUS_OTG_BIT BIT(7)
#define STATUS_AFVC_BIT BIT(6)
#define STATUS_DONE_BIT BIT(5)
#define STATUS_BATT_LESS_THAN_2V_BIT BIT(4)
#define STATUS_HOLD_OFF_BIT BIT(3)
#define STATUS_CHG_MASK SMB1351_MASK(2, 1)
#define STATUS_NO_CHARGING 0
#define STATUS_FAST_CHARGING 0x4
#define STATUS_PRE_CHARGING 0x2
#define STATUS_TAPER_CHARGING 0x6
#define STATUS_CHG_EN_STATUS_BIT BIT(0)
#define STATUS_5_REG 0x3B
#define STATUS_SOURCE_DETECTED_MASK SMB1351_MASK(7, 0)
#define STATUS_PORT_CDP 0x80
#define STATUS_PORT_DCP 0x40
#define STATUS_PORT_OTHER 0x20
#define STATUS_PORT_SDP 0x10
#define STATUS_PORT_ACA_A 0x8
#define STATUS_PORT_ACA_B 0x4
#define STATUS_PORT_ACA_C 0x2
#define STATUS_PORT_ACA_DOCK 0x1
#define STATUS_6_REG 0x3C
#define STATUS_DCD_TIMEOUT_BIT BIT(7)
#define STATUS_DCD_GOOD_DG_BIT BIT(6)
#define STATUS_OCD_GOOD_DG_BIT BIT(5)
#define STATUS_RID_ABD_DG_BIT BIT(4)
#define STATUS_RID_FLOAT_STATE_MACHINE_BIT BIT(3)
#define STATUS_RID_A_STATE_MACHINE_BIT BIT(2)
#define STATUS_RID_B_STATE_MACHINE_BIT BIT(1)
#define STATUS_RID_C_STATE_MACHINE_BIT BIT(0)
#define STATUS_7_REG 0x3D
#define STATUS_HVDCP_MASK SMB1351_MASK(7, 0)
#define STATUS_8_REG 0x3E
#define STATUS_USNIN_HV_INPUT_SEL_BIT BIT(5)
#define STATUS_USBIN_LV_UNDER_INPUT_SEL_BIT BIT(4)
#define STATUS_USBIN_LV_INPUT_SEL_BIT BIT(3)
/* Revision register */
#define CHG_REVISION_REG 0x3F
#define GUI_REVISION_MASK SMB1351_MASK(7, 4)
#define DEVICE_REVISION_MASK SMB1351_MASK(3, 0)
/* IRQ status registers */
#define IRQ_A_REG 0x40
#define IRQ_HOT_HARD_BIT BIT(6)
#define IRQ_COLD_HARD_BIT BIT(4)
#define IRQ_HOT_SOFT_BIT BIT(2)
#define IRQ_COLD_SOFT_BIT BIT(0)
#define IRQ_B_REG 0x41
#define IRQ_BATT_TERMINAL_REMOVED_BIT BIT(6)
#define IRQ_BATT_MISSING_BIT BIT(4)
#define IRQ_LOW_BATT_VOLTAGE_BIT BIT(2)
#define IRQ_INTERNAL_TEMP_LIMIT_BIT BIT(0)
#define IRQ_C_REG 0x42
#define IRQ_PRE_TO_FAST_VOLTAGE_BIT BIT(6)
#define IRQ_RECHG_BIT BIT(4)
#define IRQ_TAPER_BIT BIT(2)
#define IRQ_TERM_BIT BIT(0)
#define IRQ_D_REG 0x43
#define IRQ_BATT_OV_BIT BIT(6)
#define IRQ_CHG_ERROR_BIT BIT(4)
#define IRQ_CHG_TIMEOUT_BIT BIT(2)
#define IRQ_PRECHG_TIMEOUT_BIT BIT(0)
#define IRQ_E_REG 0x44
#define IRQ_USBIN_OV_BIT BIT(6)
#define IRQ_USBIN_UV_BIT BIT(4)
#define IRQ_AFVC_BIT BIT(2)
#define IRQ_POWER_OK_BIT BIT(0)
#define IRQ_F_REG 0x45
#define IRQ_OTG_OVER_CURRENT_BIT BIT(6)
#define IRQ_OTG_FAIL_BIT BIT(4)
#define IRQ_RID_BIT BIT(2)
#define IRQ_OTG_OC_RETRY_BIT BIT(0)
#define IRQ_G_REG 0x46
#define IRQ_SOURCE_DET_BIT BIT(6)
#define IRQ_AICL_DONE_BIT BIT(4)
#define IRQ_AICL_FAIL_BIT BIT(2)
#define IRQ_CHG_INHIBIT_BIT BIT(0)
#define IRQ_H_REG 0x47
#define IRQ_IC_LIMIT_STATUS_BIT BIT(5)
#define IRQ_HVDCP_2P1_STATUS_BIT BIT(4)
#define IRQ_HVDCP_AUTH_DONE_BIT BIT(2)
#define IRQ_WDOG_TIMEOUT_BIT BIT(0)
/* constants */
#define USB2_MIN_CURRENT_MA 100
#define USB2_MAX_CURRENT_MA 500
#define USB3_MIN_CURRENT_MA 150
#define USB3_MAX_CURRENT_MA 900
#define DCP_MAX_CURRENT_MA 1500
#define SMB1351_IRQ_REG_COUNT 8
#define SMB1351_CHG_PRE_MIN_MA 100
#define SMB1351_CHG_FAST_MIN_MA 1000
#define SMB1351_CHG_FAST_MAX_MA 4500
#define SMB1351_CHG_PRE_SHIFT 5
#define SMB1351_CHG_FAST_SHIFT 4
#define DEFAULT_BATT_CAPACITY 50
#define DEFAULT_BATT_TEMP 250
#define SUSPEND_CURRENT_MA 2
#define CHG_ITERM_200MA 0x0
#define CHG_ITERM_300MA 0x04
#define CHG_ITERM_400MA 0x08
#define CHG_ITERM_500MA 0x0C
#define CHG_ITERM_600MA 0x10
#define CHG_ITERM_700MA 0x14
#define OTG_ID_PIN_CTRL_SHIFT 6
enum otg_control {
RID_DISABLED_OTG_I2C = 0,
RID_DISABLED_OTG_PIN,
RID_ENABLED_OTG_I2C,
RID_ENABLED_OTG_AUTO,
};
enum reason {
USER = BIT(0),
THERMAL = BIT(1),
CURRENT = BIT(2),
SOC = BIT(3),
};
static char *pm_batt_supplied_to[] = {
"bms",
};
struct smb1351_regulator {
struct regulator_desc rdesc;
struct regulator_dev *rdev;
};
enum chip_version {
SMB_UNKNOWN = 0,
SMB1350,
SMB1351,
SMB_MAX_TYPE,
};
static const char *smb1351_version_str[SMB_MAX_TYPE] = {
[SMB_UNKNOWN] = "Unknown",
[SMB1350] = "SMB1350",
[SMB1351] = "SMB1351",
};
static const unsigned int smb1351_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_NONE,
};
struct smb1351_charger {
struct i2c_client *client;
struct device *dev;
bool recharge_disabled;
int recharge_mv;
bool iterm_disabled;
int iterm_ma;
int vfloat_mv;
int chg_present;
int fake_battery_soc;
bool chg_autonomous_mode;
bool disable_apsd;
bool battery_missing;
const char *bms_psy_name;
bool resume_completed;
bool irq_waiting;
struct delayed_work chg_remove_work;
struct delayed_work hvdcp_det_work;
/* status tracking */
bool batt_full;
bool batt_hot;
bool batt_cold;
bool batt_warm;
bool batt_cool;
int battchg_disabled_status;
int usb_suspended_status;
int target_fastchg_current_max_ma;
int fastchg_current_max_ma;
int workaround_flags;
int parallel_pin_polarity_setting;
int parallel_mode;
int pl_batfet_mode;
bool parallel_charger;
bool parallel_charger_suspended;
bool bms_controlled_charging;
bool apsd_rerun;
bool usbin_ov;
bool chg_remove_work_scheduled;
bool force_hvdcp_2p0;
enum chip_version version;
/* psy */
struct power_supply_desc usb_psy_d;
struct power_supply *usb_psy;
int usb_psy_ma;
struct power_supply *bms_psy;
struct power_supply_desc batt_psy_d;
struct power_supply *batt_psy;
struct power_supply *parallel_psy;
struct power_supply_desc parallel_psy_d;
struct smb1351_regulator otg_vreg;
struct mutex irq_complete;
struct dentry *debug_root;
u32 peek_poke_address;
/* pinctrl parameters */
const char *pinctrl_state_name;
struct pinctrl *smb_pinctrl;
/* standalone */
bool charger_present;
struct extcon_dev *extcon;
struct regulator *dpdm_reg;
enum power_supply_type charger_type;
bool otg_enable;
};
struct smb_irq_info {
const char *name;
int (*smb_irq)(struct smb1351_charger *chip, u8 rt_stat);
int high;
int low;
};
struct irq_handler_info {
u8 stat_reg;
u8 val;
u8 prev_val;
struct smb_irq_info irq_info[4];
};
/* USB input charge current */
static int usb_chg_current[] = {
500, 685, 1000, 1100, 1200, 1300, 1500, 1600,
1700, 1800, 2000, 2200, 2500, 3000,
};
static int fast_chg_current[] = {
1000, 1200, 1400, 1600, 1800, 2000, 2200,
2400, 2600, 2800, 3000, 3400, 3600, 3800,
4000, 4640,
};
static int pre_chg_current[] = {
200, 300, 400, 500, 600, 700,
};
static int smb1351_read_reg(struct smb1351_charger *chip, int reg, u8 *val)
{
s32 ret;
pm_stay_awake(chip->dev);
ret = i2c_smbus_read_byte_data(chip->client, reg);
if (ret < 0) {
pr_err("i2c read fail: can't read from %02x: %d\n", reg, ret);
pm_relax(chip->dev);
return ret;
}
*val = ret;
pm_relax(chip->dev);
pr_debug("Reading 0x%02x=0x%02x\n", reg, *val);
return 0;
}
static int smb1351_write_reg(struct smb1351_charger *chip, int reg, u8 val)
{
s32 ret;
pm_stay_awake(chip->dev);
ret = i2c_smbus_write_byte_data(chip->client, reg, val);
if (ret < 0) {
pr_err("i2c write fail: can't write %02x to %02x: %d\n",
val, reg, ret);
pm_relax(chip->dev);
return ret;
}
pm_relax(chip->dev);
pr_debug("Writing 0x%02x=0x%02x\n", reg, val);
return 0;
}
static int smb1351_masked_write(struct smb1351_charger *chip, int reg,
u8 mask, u8 val)
{
s32 rc;
u8 temp;
rc = smb1351_read_reg(chip, reg, &temp);
if (rc) {
pr_err("read failed: reg=%03X, rc=%d\n", reg, rc);
return rc;
}
temp &= ~mask;
temp |= val & mask;
rc = smb1351_write_reg(chip, reg, temp);
if (rc) {
pr_err("write failed: reg=%03X, rc=%d\n", reg, rc);
return rc;
}
return 0;
}
static int smb1351_enable_volatile_writes(struct smb1351_charger *chip)
{
int rc;
rc = smb1351_masked_write(chip, CMD_I2C_REG, CMD_BQ_CFG_ACCESS_BIT,
CMD_BQ_CFG_ACCESS_BIT);
if (rc)
pr_err("Couldn't write CMD_BQ_CFG_ACCESS_BIT rc=%d\n", rc);
return rc;
}
static int smb1351_get_closest_usb_setpoint(int val)
{
int i;
for (i = ARRAY_SIZE(usb_chg_current) - 1; i >= 0; i--) {
if (usb_chg_current[i] <= val)
break;
}
if (i < 0)
i = 0;
if (i >= ARRAY_SIZE(usb_chg_current) - 1)
return ARRAY_SIZE(usb_chg_current) - 1;
/* check what is closer, i or i + 1 */
if (abs(usb_chg_current[i] - val) < abs(usb_chg_current[i + 1] - val))
return i;
else
return i + 1;
}
static int smb1351_request_dpdm(struct smb1351_charger *chip, bool enable)
{
int rc = 0;
/* fetch the DPDM regulator */
if (!chip->dpdm_reg && of_get_property(chip->dev->of_node,
"dpdm-supply", NULL)) {
chip->dpdm_reg = devm_regulator_get(chip->dev, "dpdm");
if (IS_ERR(chip->dpdm_reg)) {
rc = PTR_ERR(chip->dpdm_reg);
pr_err("Couldn't get dpdm regulator rc=%d\n",
rc);
chip->dpdm_reg = NULL;
return rc;
}
}
if (enable) {
if (chip->dpdm_reg && !regulator_is_enabled(chip->dpdm_reg)) {
pr_err("enabling DPDM regulator\n");
rc = regulator_enable(chip->dpdm_reg);
if (rc < 0)
pr_err("Couldn't enable dpdm regulator rc=%d\n",
rc);
}
} else {
if (chip->dpdm_reg && regulator_is_enabled(chip->dpdm_reg)) {
pr_err("disabling DPDM regulator\n");
rc = regulator_disable(chip->dpdm_reg);
if (rc < 0)
pr_err("Couldn't disable dpdm regulator rc=%d\n",
rc);
}
}
return rc;
}
static int smb1351_usb_suspend(struct smb1351_charger *chip, int reason,
bool suspend)
{
int rc = 0;
int suspended;
suspended = chip->usb_suspended_status;
pr_debug("reason = %d requested_suspend = %d suspended_status = %d\n",
reason, suspend, suspended);
if (suspend == false)
suspended &= ~reason;
else
suspended |= reason;
pr_debug("new suspended_status = %d\n", suspended);
rc = smb1351_masked_write(chip, CMD_INPUT_LIMIT_REG,
CMD_SUSPEND_MODE_BIT,
suspended ? CMD_SUSPEND_MODE_BIT : 0);
if (rc)
pr_err("Couldn't suspend rc = %d\n", rc);
else
chip->usb_suspended_status = suspended;
return rc;
}
static int smb1351_battchg_disable(struct smb1351_charger *chip,
int reason, int disable)
{
int rc = 0;
int disabled;
if (chip->chg_autonomous_mode) {
pr_debug("Charger in autonomous mode\n");
return 0;
}
disabled = chip->battchg_disabled_status;
pr_debug("reason = %d requested_disable = %d disabled_status = %d\n",
reason, disable, disabled);
if (disable == true)
disabled |= reason;
else
disabled &= ~reason;
pr_debug("new disabled_status = %d\n", disabled);
rc = smb1351_masked_write(chip, CMD_CHG_REG, CMD_CHG_EN_BIT,
disabled ? 0 : CMD_CHG_ENABLE);
if (rc)
pr_err("Couldn't %s charging rc=%d\n",
disable ? "disable" : "enable", rc);
else
chip->battchg_disabled_status = disabled;
return rc;
}
static int smb1351_fastchg_current_set(struct smb1351_charger *chip,
unsigned int fastchg_current)
{
int i, rc;
bool is_pre_chg = false;
if ((fastchg_current < SMB1351_CHG_PRE_MIN_MA) ||
(fastchg_current > SMB1351_CHG_FAST_MAX_MA)) {
pr_err("bad pre_fastchg current mA=%d asked to set\n",
fastchg_current);
return -EINVAL;
}
/*
* fast chg current could not support less than 1000mA
* use pre chg to instead for the parallel charging
*/
if (fastchg_current < SMB1351_CHG_FAST_MIN_MA) {
is_pre_chg = true;
pr_debug("is_pre_chg true, current is %d\n", fastchg_current);
}
if (is_pre_chg) {
/* set prechg current */
for (i = ARRAY_SIZE(pre_chg_current) - 1; i >= 0; i--) {
if (pre_chg_current[i] <= fastchg_current)
break;
}
if (i < 0)
i = 0;
chip->fastchg_current_max_ma = pre_chg_current[i];
pr_debug("prechg setting %02x\n", i);
i = i << SMB1351_CHG_PRE_SHIFT;
rc = smb1351_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG,
PRECHG_CURRENT_MASK, i);
if (rc)
pr_err("Couldn't write CHG_OTH_CURRENT_CTRL_REG rc=%d\n",
rc);
return smb1351_masked_write(chip, VARIOUS_FUNC_2_REG,
PRECHG_TO_FASTCHG_BIT, PRECHG_TO_FASTCHG_BIT);
} else {
if (chip->version == SMB_UNKNOWN)
return -EINVAL;
/* SMB1350 supports FCC upto 2600 mA */
if (chip->version == SMB1350 && fastchg_current > 2600)
fastchg_current = 2600;
/* set fastchg current */
for (i = ARRAY_SIZE(fast_chg_current) - 1; i >= 0; i--) {
if (fast_chg_current[i] <= fastchg_current)
break;
}
if (i < 0)
i = 0;
chip->fastchg_current_max_ma = fast_chg_current[i];
i = i << SMB1351_CHG_FAST_SHIFT;
pr_debug("fastchg limit=%d setting %02x\n",
chip->fastchg_current_max_ma, i);
/* make sure pre chg mode is disabled */
rc = smb1351_masked_write(chip, VARIOUS_FUNC_2_REG,
PRECHG_TO_FASTCHG_BIT, 0);
if (rc)
pr_err("Couldn't write VARIOUS_FUNC_2_REG rc=%d\n", rc);
return smb1351_masked_write(chip, CHG_CURRENT_CTRL_REG,
FAST_CHG_CURRENT_MASK, i);
}
}
#define MIN_FLOAT_MV 3500
#define MAX_FLOAT_MV 4500
#define VFLOAT_STEP_MV 20
static int smb1351_float_voltage_set(struct smb1351_charger *chip,
int vfloat_mv)
{
u8 temp;
if ((vfloat_mv < MIN_FLOAT_MV) || (vfloat_mv > MAX_FLOAT_MV)) {
pr_err("bad float voltage mv =%d asked to set\n", vfloat_mv);
return -EINVAL;
}
temp = (vfloat_mv - MIN_FLOAT_MV) / VFLOAT_STEP_MV;
return smb1351_masked_write(chip, VFLOAT_REG, VFLOAT_MASK, temp);
}
static int smb1351_iterm_set(struct smb1351_charger *chip, int iterm_ma)
{
int rc;
u8 reg;
if (iterm_ma <= 200)
reg = CHG_ITERM_200MA;
else if (iterm_ma <= 300)
reg = CHG_ITERM_300MA;
else if (iterm_ma <= 400)
reg = CHG_ITERM_400MA;
else if (iterm_ma <= 500)
reg = CHG_ITERM_500MA;
else if (iterm_ma <= 600)
reg = CHG_ITERM_600MA;
else
reg = CHG_ITERM_700MA;
rc = smb1351_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG,
ITERM_MASK, reg);
if (rc) {
pr_err("Couldn't set iterm rc = %d\n", rc);
return rc;
}
/* enable the iterm */
rc = smb1351_masked_write(chip, CHG_CTRL_REG,
ITERM_EN_BIT, ITERM_ENABLE);
if (rc) {
pr_err("Couldn't enable iterm rc = %d\n", rc);
return rc;
}
return 0;
}
static int smb1351_chg_otg_regulator_enable(struct regulator_dev *rdev)
{
int rc = 0;
struct smb1351_charger *chip = rdev_get_drvdata(rdev);
rc = smb1351_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT,
CMD_OTG_EN_BIT);
if (rc)
pr_err("Couldn't enable OTG mode rc=%d\n", rc);
return rc;
}
static int smb1351_chg_otg_regulator_disable(struct regulator_dev *rdev)
{
int rc = 0;
struct smb1351_charger *chip = rdev_get_drvdata(rdev);
rc = smb1351_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, 0);
if (rc)
pr_err("Couldn't disable OTG mode rc=%d\n", rc);
return rc;
}
static int smb1351_chg_otg_regulator_is_enable(struct regulator_dev *rdev)
{
int rc = 0;
u8 reg = 0;
struct smb1351_charger *chip = rdev_get_drvdata(rdev);
rc = smb1351_read_reg(chip, CMD_CHG_REG, &reg);
if (rc) {
pr_err("Couldn't read OTG enable bit rc=%d\n", rc);
return rc;
}
return (reg & CMD_OTG_EN_BIT) ? 1 : 0;
}
static struct regulator_ops smb1351_chg_otg_reg_ops = {
.enable = smb1351_chg_otg_regulator_enable,
.disable = smb1351_chg_otg_regulator_disable,
.is_enabled = smb1351_chg_otg_regulator_is_enable,
};
static int smb1351_regulator_init(struct smb1351_charger *chip)
{
int rc = 0;
struct regulator_config cfg = {};
struct regulator_init_data *init_data;
chip->otg_vreg.rdesc.owner = THIS_MODULE;
chip->otg_vreg.rdesc.type = REGULATOR_VOLTAGE;
chip->otg_vreg.rdesc.ops = &smb1351_chg_otg_reg_ops;
chip->otg_vreg.rdesc.name =
chip->dev->of_node->name;
chip->otg_vreg.rdesc.of_match =
chip->dev->of_node->name;
init_data = of_get_regulator_init_data(chip->dev, chip->dev->of_node,
&chip->otg_vreg.rdesc);
if (!init_data) {
pr_err("regulator init data is missing\n");
return -EINVAL;
}
cfg.dev = chip->dev;
cfg.driver_data = chip;
cfg.init_data = init_data;
cfg.of_node = chip->dev->of_node;
chip->otg_vreg.rdev = regulator_register(
&chip->otg_vreg.rdesc, &cfg);
if (IS_ERR(chip->otg_vreg.rdev)) {
rc = PTR_ERR(chip->otg_vreg.rdev);
chip->otg_vreg.rdev = NULL;
if (rc != -EPROBE_DEFER)
pr_err("OTG reg failed, rc=%d\n", rc);
}
return rc;
}
static int smb_chip_get_version(struct smb1351_charger *chip)
{
u8 ver;
int rc = 0;
if (chip->version == SMB_UNKNOWN) {
rc = smb1351_read_reg(chip, VERSION_REG, &ver);
if (rc) {
pr_err("Couldn't read version rc=%d\n", rc);
return rc;
}
/* If bit 1 is set, it is SMB1350 */
if (ver & VERSION_MASK)
chip->version = SMB1350;
else
chip->version = SMB1351;
}
return rc;
}
static int smb1351_hw_init(struct smb1351_charger *chip)
{
int rc;
u8 reg = 0, mask = 0;
/* configure smb_pinctrl to enable irqs */
if (chip->pinctrl_state_name) {
chip->smb_pinctrl = pinctrl_get_select(chip->dev,
chip->pinctrl_state_name);
if (IS_ERR(chip->smb_pinctrl)) {
pr_err("Could not get/set %s pinctrl state rc = %ld\n",
chip->pinctrl_state_name,
PTR_ERR(chip->smb_pinctrl));
return PTR_ERR(chip->smb_pinctrl);
}
}
/*
* If the charger is pre-configured for autonomous operation,
* do not apply additional settings
*/
if (chip->chg_autonomous_mode) {
pr_debug("Charger configured for autonomous mode\n");
return 0;
}
rc = smb_chip_get_version(chip);
if (rc) {
pr_err("Couldn't get version rc = %d\n", rc);
return rc;
}
rc = smb1351_enable_volatile_writes(chip);
if (rc) {
pr_err("Couldn't configure volatile writes rc=%d\n", rc);
return rc;
}
/* enable/disable charging by suspending usb */
rc = smb1351_usb_suspend(chip, USER, chip->usb_suspended_status);
if (rc) {
pr_err("Unable to %ssuspend usb. rc=%d\n",
chip->usb_suspended_status ? "" : "un-", rc);
return rc;
}
/* enable/disable battery charging */
rc = smb1351_battchg_disable(chip, USER, chip->battchg_disabled_status);
if (rc) {
pr_err("Unable to %s battery charging. rc=%d\n",
chip->battchg_disabled_status ? "disable" : "enable",
rc);
return rc;
}
/* setup battery missing source */
reg = BATT_MISSING_THERM_PIN_SOURCE_BIT;
mask = BATT_MISSING_THERM_PIN_SOURCE_BIT;
rc = smb1351_masked_write(chip, HVDCP_BATT_MISSING_CTRL_REG,
mask, reg);
if (rc) {
pr_err("Couldn't set HVDCP_BATT_MISSING_CTRL_REG rc=%d\n", rc);
return rc;
}
/* setup defaults for CHG_PIN_EN_CTRL_REG */
reg = EN_BY_I2C_0_DISABLE | USBCS_CTRL_BY_I2C | CHG_ERR_BIT |
APSD_DONE_BIT | LED_BLINK_FUNC_BIT;
mask = EN_PIN_CTRL_MASK | USBCS_CTRL_BIT | CHG_ERR_BIT |
APSD_DONE_BIT | LED_BLINK_FUNC_BIT;
rc = smb1351_masked_write(chip, CHG_PIN_EN_CTRL_REG, mask, reg);
if (rc) {
pr_err("Couldn't set CHG_PIN_EN_CTRL_REG rc=%d\n", rc);
return rc;
}
/* setup USB 2.0/3.0 detection and USB 500/100 command polarity */
reg = USB_2_3_MODE_SEL_BY_I2C | USB_CMD_POLARITY_500_1_100_0;
mask = USB_2_3_MODE_SEL_BIT | USB_5_1_CMD_POLARITY_BIT;
rc = smb1351_masked_write(chip, CHG_OTH_CURRENT_CTRL_REG, mask, reg);
if (rc) {
pr_err("Couldn't set CHG_OTH_CURRENT_CTRL_REG rc=%d\n", rc);
return rc;
}
/* setup USB suspend, AICL and APSD */
reg = SUSPEND_MODE_CTRL_BY_I2C | AICL_EN_BIT;
if (!chip->disable_apsd)
reg |= APSD_EN_BIT;
mask = SUSPEND_MODE_CTRL_BIT | AICL_EN_BIT | APSD_EN_BIT;
rc = smb1351_masked_write(chip, VARIOUS_FUNC_REG, mask, reg);
if (rc) {
pr_err("Couldn't set VARIOUS_FUNC_REG rc=%d\n", rc);
return rc;
}
/* Fault and Status IRQ configuration */
reg = HOT_COLD_HARD_LIMIT_BIT | HOT_COLD_SOFT_LIMIT_BIT
| INPUT_OVLO_BIT | INPUT_UVLO_BIT | AICL_DONE_FAIL_BIT;
rc = smb1351_write_reg(chip, FAULT_INT_REG, reg);
if (rc) {
pr_err("Couldn't set FAULT_INT_REG rc=%d\n", rc);
return rc;
}
reg = CHG_OR_PRECHG_TIMEOUT_BIT | BATT_OVP_BIT |
FAST_TERM_TAPER_RECHG_INHIBIT_BIT |
BATT_MISSING_BIT | BATT_LOW_BIT;
if (chip->otg_enable)
reg = reg | RID_CHANGE_BIT;
rc = smb1351_write_reg(chip, STATUS_INT_REG, reg);
if (rc) {
pr_err("Couldn't set STATUS_INT_REG rc=%d\n", rc);
return rc;
}
/* setup THERM Monitor */
rc = smb1351_masked_write(chip, THERM_A_CTRL_REG,
THERM_MONITOR_BIT, THERM_MONITOR_EN);
if (rc) {
pr_err("Couldn't set THERM_A_CTRL_REG rc=%d\n", rc);
return rc;
}
/* set the fast charge current limit */
rc = smb1351_fastchg_current_set(chip,
chip->target_fastchg_current_max_ma);
if (rc) {
pr_err("Couldn't set fastchg current rc=%d\n", rc);
return rc;
}
/* set the float voltage */
if (chip->vfloat_mv != -EINVAL) {
rc = smb1351_float_voltage_set(chip, chip->vfloat_mv);
if (rc) {
pr_err("Couldn't set float voltage rc = %d\n", rc);
return rc;
}
}
/* set iterm */
if (chip->iterm_ma != -EINVAL) {
if (chip->iterm_disabled) {
pr_err("Error: Both iterm_disabled and iterm_ma set\n");
return -EINVAL;
}
rc = smb1351_iterm_set(chip, chip->iterm_ma);
if (rc) {
pr_err("Couldn't set iterm rc = %d\n", rc);
return rc;
}
} else if (chip->iterm_disabled) {
rc = smb1351_masked_write(chip, CHG_CTRL_REG,
ITERM_EN_BIT, ITERM_DISABLE);
if (rc) {
pr_err("Couldn't set iterm rc = %d\n", rc);
return rc;
}
}
/* set recharge-threshold */
if (chip->recharge_mv != -EINVAL) {
if (chip->recharge_disabled) {
pr_err("Error: Both recharge_disabled and recharge_mv set\n");
return -EINVAL;
}
reg = AUTO_RECHG_ENABLE;
if (chip->recharge_mv > 50)
reg |= AUTO_RECHG_TH_100MV;
else
reg |= AUTO_RECHG_TH_50MV;
rc = smb1351_masked_write(chip, CHG_CTRL_REG,
AUTO_RECHG_BIT |
AUTO_RECHG_TH_BIT, reg);
if (rc) {
pr_err("Couldn't set rechg-cfg rc = %d\n", rc);
return rc;
}
} else if (chip->recharge_disabled) {
rc = smb1351_masked_write(chip, CHG_CTRL_REG,
AUTO_RECHG_BIT,
AUTO_RECHG_DISABLE);
if (rc) {
pr_err("Couldn't disable auto-rechg rc = %d\n", rc);
return rc;
}
}
if (chip->otg_enable) {
/* Configure OTG/ID pin control: RID enabled, OTG I2C control */
rc = smb1351_masked_write(chip, OTG_USBIN_AICL_CTRL_REG,
OTG_ID_PIN_CTRL_MASK,
RID_ENABLED_OTG_I2C << OTG_ID_PIN_CTRL_SHIFT);
if (rc) {
pr_err("Couldn't configure RID enable rc = %d\n", rc);
return rc;
}
}
/* Disable watchdog */
rc = smb1351_masked_write(chip, WDOG_SAFETY_TIMER_CTRL_REG,
WDOG_TIMER_EN_BIT, 0);
if (rc) {
pr_err("Couldn't disable watchdog rc = %d\n", rc);
return rc;
}
return rc;
}
static enum power_supply_property smb1351_battery_properties[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CHARGING_ENABLED,
POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_MODEL_NAME,
};
static int smb1351_get_prop_batt_status(struct smb1351_charger *chip)
{
int rc;
u8 reg = 0;
if (chip->batt_full)
return POWER_SUPPLY_STATUS_FULL;
rc = smb1351_read_reg(chip, STATUS_4_REG, &reg);
if (rc) {
pr_err("Couldn't read STATUS_4 rc = %d\n", rc);
return POWER_SUPPLY_STATUS_UNKNOWN;
}
pr_debug("STATUS_4_REG(0x3A)=%x\n", reg);
if (reg & STATUS_HOLD_OFF_BIT)
return POWER_SUPPLY_STATUS_NOT_CHARGING;
if (reg & STATUS_CHG_MASK)
return POWER_SUPPLY_STATUS_CHARGING;
return POWER_SUPPLY_STATUS_DISCHARGING;
}
static int smb1351_get_prop_batt_present(struct smb1351_charger *chip)
{
return !chip->battery_missing;
}
static int smb1351_get_prop_batt_capacity(struct smb1351_charger *chip)
{
union power_supply_propval ret = {0, };
if (chip->fake_battery_soc >= 0)
return chip->fake_battery_soc;
if (chip->bms_psy) {
power_supply_get_property(chip->bms_psy,
POWER_SUPPLY_PROP_CAPACITY, &ret);
return ret.intval;
}
pr_debug("return DEFAULT_BATT_CAPACITY\n");
return DEFAULT_BATT_CAPACITY;
}
static int smb1351_get_prop_batt_temp(struct smb1351_charger *chip)
{
union power_supply_propval ret = {0, };
if (chip->bms_psy) {
power_supply_get_property(chip->bms_psy,
POWER_SUPPLY_PROP_TEMP, &ret);
return ret.intval;
}
pr_debug("return default temperature\n");
return DEFAULT_BATT_TEMP;
}
static int smb1351_get_prop_charge_type(struct smb1351_charger *chip)
{
int rc;
u8 reg = 0;
rc = smb1351_read_reg(chip, STATUS_4_REG, &reg);
if (rc) {
pr_err("Couldn't read STATUS_4 rc = %d\n", rc);
return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
}
pr_debug("STATUS_4_REG(0x3A)=%x\n", reg);
reg &= STATUS_CHG_MASK;
if (reg == STATUS_FAST_CHARGING)
return POWER_SUPPLY_CHARGE_TYPE_FAST;
else if (reg == STATUS_TAPER_CHARGING)
return POWER_SUPPLY_CHARGE_TYPE_TAPER;
else if (reg == STATUS_PRE_CHARGING)
return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
else
return POWER_SUPPLY_CHARGE_TYPE_NONE;
}
static int smb1351_get_prop_batt_health(struct smb1351_charger *chip)
{
union power_supply_propval ret = {0, };
if (chip->batt_hot)
ret.intval = POWER_SUPPLY_HEALTH_OVERHEAT;
else if (chip->batt_cold)
ret.intval = POWER_SUPPLY_HEALTH_COLD;
else if (chip->batt_warm)
ret.intval = POWER_SUPPLY_HEALTH_WARM;
else if (chip->batt_cool)
ret.intval = POWER_SUPPLY_HEALTH_COOL;
else
ret.intval = POWER_SUPPLY_HEALTH_GOOD;
return ret.intval;
}
static int smb1351_set_usb_chg_current(struct smb1351_charger *chip,
int current_ma)
{
int i, rc = 0;
u8 reg = 0, mask = 0;
pr_debug("USB current_ma = %d\n", current_ma);
if (chip->chg_autonomous_mode) {
pr_debug("Charger in autonomous mode\n");
return 0;
}
/* set suspend bit when urrent_ma <= 2 */
if (current_ma <= SUSPEND_CURRENT_MA) {
smb1351_usb_suspend(chip, CURRENT, true);
pr_debug("USB suspend\n");
return 0;
}
if (current_ma > SUSPEND_CURRENT_MA &&
current_ma < USB2_MIN_CURRENT_MA)
current_ma = USB2_MIN_CURRENT_MA;
if (current_ma == USB2_MIN_CURRENT_MA) {
/* USB 2.0 - 100mA */
reg = CMD_USB_2_MODE | CMD_USB_100_MODE;
} else if (current_ma == USB3_MIN_CURRENT_MA) {
/* USB 3.0 - 150mA */
reg = CMD_USB_3_MODE | CMD_USB_100_MODE;
} else if (current_ma == USB2_MAX_CURRENT_MA) {
/* USB 2.0 - 500mA */
reg = CMD_USB_2_MODE | CMD_USB_500_MODE;
} else if (current_ma == USB3_MAX_CURRENT_MA) {
/* USB 3.0 - 900mA */
reg = CMD_USB_3_MODE | CMD_USB_500_MODE;
} else if (current_ma > USB2_MAX_CURRENT_MA) {
/* HC mode - if none of the above */
reg = CMD_USB_AC_MODE;
for (i = ARRAY_SIZE(usb_chg_current) - 1; i >= 0; i--) {
if (usb_chg_current[i] <= current_ma)
break;
}
if (i < 0)
i = 0;
rc = smb1351_masked_write(chip, CHG_CURRENT_CTRL_REG,
AC_INPUT_CURRENT_LIMIT_MASK, i);
if (rc) {
pr_err("Couldn't set input mA rc=%d\n", rc);
return rc;
}
}
/* control input current mode by command */
reg |= CMD_INPUT_CURRENT_MODE_CMD;
mask = CMD_INPUT_CURRENT_MODE_BIT | CMD_USB_2_3_SEL_BIT |
CMD_USB_1_5_AC_CTRL_MASK;
rc = smb1351_masked_write(chip, CMD_INPUT_LIMIT_REG, mask, reg);
if (rc) {
pr_err("Couldn't set charging mode rc = %d\n", rc);
return rc;
}
/* unset the suspend bit here */
smb1351_usb_suspend(chip, CURRENT, false);
return rc;
}
static char *smb1351_usb_supplicants[] = {
"bms",
};
static enum power_supply_property smb1351_usb_properties[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_TYPE,
POWER_SUPPLY_PROP_REAL_TYPE,
POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
};
static int smb1351_usb_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct smb1351_charger *chip = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_CURRENT_MAX:
case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
val->intval = chip->usb_psy_ma * 1000;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = chip->chg_present;
break;
case POWER_SUPPLY_PROP_ONLINE:
val->intval = chip->chg_present && !chip->usb_suspended_status;
break;
case POWER_SUPPLY_PROP_TYPE:
val->intval = chip->charger_type;
break;
case POWER_SUPPLY_PROP_REAL_TYPE:
if (chip->charger_type == POWER_SUPPLY_TYPE_USB_HVDCP)
val->intval = POWER_SUPPLY_TYPE_USB_DCP;
else if (chip->charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
val->intval = POWER_SUPPLY_TYPE_USB;
else
val->intval = chip->charger_type;
break;
default:
return -EINVAL;
}
return 0;
}
static int smb1351_usb_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct smb1351_charger *chip = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_CURRENT_MAX:
case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
chip->usb_psy_ma = val->intval / 1000;
smb1351_enable_volatile_writes(chip);
smb1351_set_usb_chg_current(chip, chip->usb_psy_ma);
break;
default:
return -EINVAL;
}
power_supply_changed(psy);
return 0;
}
static int smb1351_usb_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_CURRENT_MAX:
return 1;
default:
break;
}
return 0;
}
static int smb1351_batt_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
case POWER_SUPPLY_PROP_CAPACITY:
return 1;
default:
break;
}
return 0;
}
static int smb1351_battery_set_property(struct power_supply *psy,
enum power_supply_property prop,
const union power_supply_propval *val)
{
int rc;
struct smb1351_charger *chip = power_supply_get_drvdata(psy);
switch (prop) {
case POWER_SUPPLY_PROP_STATUS:
if (!chip->bms_controlled_charging)
return -EINVAL;
switch (val->intval) {
case POWER_SUPPLY_STATUS_FULL:
rc = smb1351_battchg_disable(chip, SOC, true);
if (rc) {
pr_err("Couldn't disable charging rc = %d\n",
rc);
} else {
chip->batt_full = true;
pr_debug("status = FULL, batt_full = %d\n",
chip->batt_full);
}
break;
case POWER_SUPPLY_STATUS_DISCHARGING:
chip->batt_full = false;
power_supply_changed(chip->batt_psy);
pr_debug("status = DISCHARGING, batt_full = %d\n",
chip->batt_full);
break;
case POWER_SUPPLY_STATUS_CHARGING:
rc = smb1351_battchg_disable(chip, SOC, false);
if (rc) {
pr_err("Couldn't enable charging rc = %d\n",
rc);
} else {
chip->batt_full = false;
pr_debug("status = CHARGING, batt_full = %d\n",
chip->batt_full);
}
break;
default:
return -EINVAL;
}
break;
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
smb1351_usb_suspend(chip, USER, !val->intval);
break;
case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
smb1351_battchg_disable(chip, USER, !val->intval);
break;
case POWER_SUPPLY_PROP_CAPACITY:
chip->fake_battery_soc = val->intval;
power_supply_changed(chip->batt_psy);
break;
default:
return -EINVAL;
}
return 0;
}
static int smb1351_battery_get_property(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
{
struct smb1351_charger *chip = power_supply_get_drvdata(psy);
switch (prop) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = smb1351_get_prop_batt_status(chip);
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = smb1351_get_prop_batt_present(chip);
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = smb1351_get_prop_batt_capacity(chip);
break;
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
val->intval = !chip->usb_suspended_status;
break;
case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
val->intval = !chip->battchg_disabled_status;
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
val->intval = smb1351_get_prop_charge_type(chip);
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = smb1351_get_prop_batt_health(chip);
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = smb1351_get_prop_batt_temp(chip);
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = "smb1351";
break;
default:
return -EINVAL;
}
return 0;
}
static enum power_supply_property smb1351_parallel_properties[] = {
POWER_SUPPLY_PROP_CHARGING_ENABLED,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PARALLEL_MODE,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
};
static int smb1351_parallel_set_chg_suspend(struct smb1351_charger *chip,
int suspend)
{
int rc;
u8 reg, mask = 0;
if (chip->parallel_charger_suspended == suspend) {
pr_debug("Skip same state request suspended = %d suspend=%d\n",
chip->parallel_charger_suspended, !suspend);
return 0;
}
if (!suspend) {
rc = smb_chip_get_version(chip);
if (rc) {
pr_err("Couldn't get version rc = %d\n", rc);
return rc;
}
rc = smb1351_enable_volatile_writes(chip);
if (rc) {
pr_err("Couldn't configure for volatile rc = %d\n", rc);
return rc;
}
/* set the float voltage */
if (chip->vfloat_mv != -EINVAL) {
rc = smb1351_float_voltage_set(chip, chip->vfloat_mv);
if (rc) {
pr_err("Couldn't set float voltage rc = %d\n",
rc);
return rc;
}
}
/* set recharge-threshold and enable auto recharge */
if (chip->recharge_mv != -EINVAL) {
reg = AUTO_RECHG_ENABLE;
if (chip->recharge_mv > 50)
reg |= AUTO_RECHG_TH_100MV;
else
reg |= AUTO_RECHG_TH_50MV;
rc = smb1351_masked_write(chip, CHG_CTRL_REG,
AUTO_RECHG_BIT |
AUTO_RECHG_TH_BIT, reg);
if (rc) {
pr_err("Couldn't set rechg-cfg rc = %d\n", rc);
return rc;
}
}
/* control USB suspend via command bits */
rc = smb1351_masked_write(chip, VARIOUS_FUNC_REG,
APSD_EN_BIT | SUSPEND_MODE_CTRL_BIT,
SUSPEND_MODE_CTRL_BY_I2C);
if (rc) {
pr_err("Couldn't set USB suspend rc=%d\n", rc);
return rc;
}
/*
* When present is being set force USB suspend, start charging
* only when POWER_SUPPLY_PROP_CURRENT_MAX is set.
*/
rc = smb1351_usb_suspend(chip, CURRENT, true);
if (rc) {
pr_err("failed to suspend rc=%d\n", rc);
return rc;
}
chip->usb_psy_ma = SUSPEND_CURRENT_MA;
/* set chg en by pin active low */
reg = chip->parallel_pin_polarity_setting | USBCS_CTRL_BY_I2C;
rc = smb1351_masked_write(chip, CHG_PIN_EN_CTRL_REG,
EN_PIN_CTRL_MASK | USBCS_CTRL_BIT, reg);
if (rc) {
pr_err("Couldn't set en pin rc=%d\n", rc);
return rc;
}
/*
* setup USB 2.0/3.0 detection and USB 500/100
* command polarity
*/
reg = USB_2_3_MODE_SEL_BY_I2C | USB_CMD_POLARITY_500_1_100_0;
mask = USB_2_3_MODE_SEL_BIT | USB_5_1_CMD_POLARITY_BIT;
rc = smb1351_masked_write(chip,
CHG_OTH_CURRENT_CTRL_REG, mask, reg);
if (rc) {
pr_err("Couldn't set CHG_OTH_CURRENT_CTRL_REG rc=%d\n",
rc);
return rc;
}
rc = smb1351_fastchg_current_set(chip,
chip->target_fastchg_current_max_ma);
if (rc) {
pr_err("Couldn't set fastchg current rc=%d\n", rc);
return rc;
}
chip->parallel_charger_suspended = false;
} else {
rc = smb1351_usb_suspend(chip, CURRENT, true);
if (rc)
pr_debug("failed to suspend rc=%d\n", rc);
chip->usb_psy_ma = SUSPEND_CURRENT_MA;
chip->parallel_charger_suspended = true;
}
return 0;
}
static bool smb1351_is_input_current_limited(struct smb1351_charger *chip)
{
int rc;
u8 reg;
rc = smb1351_read_reg(chip, IRQ_H_REG, &reg);
if (rc) {
pr_err("Failed to read IRQ_H_REG for ICL status: %d\n", rc);
return false;
}
return !!(reg & IRQ_IC_LIMIT_STATUS_BIT);
}
static bool smb1351_is_usb_present(struct smb1351_charger *chip)
{
int rc;
union power_supply_propval val = {0, };
if (!chip->usb_psy)
chip->usb_psy = power_supply_get_by_name("usb");
if (!chip->usb_psy) {
pr_err("USB psy not found\n");
return false;
}
rc = power_supply_get_property(chip->usb_psy,
POWER_SUPPLY_PROP_ONLINE, &val);
if (rc < 0) {
pr_err("Failed to get present property rc=%d\n", rc);
return false;
}
if (val.intval)
return true;
return false;
}
static int smb1351_parallel_set_property(struct power_supply *psy,
enum power_supply_property prop,
const union power_supply_propval *val)
{
int rc = 0, index;
struct smb1351_charger *chip = power_supply_get_drvdata(psy);
switch (prop) {
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
/*
*CHG EN is controlled by pin in the parallel charging.
*Use suspend if disable charging by command.
*/
if (!chip->parallel_charger_suspended)
rc = smb1351_usb_suspend(chip, USER, !val->intval);
break;
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
rc = smb1351_parallel_set_chg_suspend(chip, val->intval);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
chip->target_fastchg_current_max_ma =
val->intval / 1000;
if (!chip->parallel_charger_suspended)
rc = smb1351_fastchg_current_set(chip,
chip->target_fastchg_current_max_ma);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
index = smb1351_get_closest_usb_setpoint(val->intval / 1000);
chip->usb_psy_ma = usb_chg_current[index];
if (!chip->parallel_charger_suspended)
rc = smb1351_set_usb_chg_current(chip,
chip->usb_psy_ma);
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
chip->vfloat_mv = val->intval / 1000;
if (!chip->parallel_charger_suspended)
rc = smb1351_float_voltage_set(chip, val->intval);
break;
default:
return -EINVAL;
}
return rc;
}
static int smb1351_parallel_is_writeable(struct power_supply *psy,
enum power_supply_property prop)
{
switch (prop) {
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
return 1;
default:
return 0;
}
}
static int smb1351_parallel_get_property(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
{
struct smb1351_charger *chip = power_supply_get_drvdata(psy);
switch (prop) {
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
val->intval = !chip->parallel_charger_suspended;
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
if (!chip->parallel_charger_suspended)
val->intval = chip->usb_psy_ma * 1000;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
if (!chip->parallel_charger_suspended)
val->intval = chip->vfloat_mv;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
/* Check if SMB1351 is present */
if (smb1351_is_usb_present(chip)) {
val->intval = smb1351_get_prop_charge_type(chip);
if (val->intval == POWER_SUPPLY_CHARGE_TYPE_UNKNOWN) {
pr_debug("Failed to charge type, charger may be absent\n");
return -ENODEV;
}
}
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
if (!chip->parallel_charger_suspended)
val->intval = chip->fastchg_current_max_ma * 1000;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_STATUS:
if (!chip->parallel_charger_suspended)
val->intval = smb1351_get_prop_batt_status(chip);
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
if (!chip->parallel_charger_suspended)
val->intval =
smb1351_is_input_current_limited(chip) ? 1 : 0;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = chip->parallel_mode;
break;
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
val->intval = chip->parallel_charger_suspended;
break;
case POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE:
val->intval = chip->pl_batfet_mode;
break;
default:
return -EINVAL;
}
return 0;
}
static int rerun_apsd(struct smb1351_charger *chip)
{
int rc;
pr_debug("Reruning APSD\nDisabling APSD\n");
rc = smb1351_masked_write(chip, CMD_HVDCP_REG, CMD_APSD_RE_RUN_BIT,
CMD_APSD_RE_RUN_BIT);
if (rc)
pr_err("Couldn't re-run APSD algo\n");
return 0;
}
static void smb1351_hvdcp_det_work(struct work_struct *work)
{
int rc;
u8 reg;
union power_supply_propval pval = {0, };
struct smb1351_charger *chip = container_of(work,
struct smb1351_charger,
hvdcp_det_work.work);
rc = smb1351_read_reg(chip, STATUS_7_REG, &reg);
if (rc) {
pr_err("Couldn't read STATUS_7_REG rc == %d\n", rc);
goto end;
}
pr_debug("STATUS_7_REG = 0x%02X\n", reg);
if (reg) {
pr_debug("HVDCP detected; notifying USB PSY\n");
pval.intval = POWER_SUPPLY_TYPE_USB_HVDCP;
power_supply_set_property(chip->usb_psy,
POWER_SUPPLY_PROP_TYPE, &pval);
}
end:
pm_relax(chip->dev);
}
#define HVDCP_NOTIFY_MS 2500
static int smb1351_apsd_complete_handler(struct smb1351_charger *chip,
u8 status)
{
int rc, usb_psy_ma = 0;
u8 reg = 0;
enum power_supply_type type = POWER_SUPPLY_TYPE_UNKNOWN;
union extcon_property_value val;
/*
* If apsd is disabled, charger detection is done by
* USB phy driver.
*/
if (chip->disable_apsd || chip->usbin_ov) {
pr_debug("APSD %s, status = %d\n",
chip->disable_apsd ? "disabled" : "enabled", !!status);
pr_debug("USBIN ov, status = %d\n", chip->usbin_ov);
return 0;
}
rc = smb1351_read_reg(chip, STATUS_5_REG, &reg);
if (rc) {
pr_err("Couldn't read STATUS_5 rc = %d\n", rc);
return rc;
}
pr_debug("STATUS_5_REG(0x3B)=%x\n", reg);
switch (reg) {
case STATUS_PORT_ACA_DOCK:
case STATUS_PORT_ACA_C:
case STATUS_PORT_ACA_B:
case STATUS_PORT_ACA_A:
type = POWER_SUPPLY_TYPE_USB_ACA;
break;
case STATUS_PORT_CDP:
type = POWER_SUPPLY_TYPE_USB_CDP;
break;
case STATUS_PORT_DCP:
type = POWER_SUPPLY_TYPE_USB_DCP;
break;
case STATUS_PORT_SDP:
type = POWER_SUPPLY_TYPE_USB;
break;
case STATUS_PORT_OTHER:
type = POWER_SUPPLY_TYPE_USB_DCP;
break;
default:
type = POWER_SUPPLY_TYPE_USB;
break;
}
if (status) {
chip->chg_present = true;
pr_debug("APSD complete. USB type detected=%d chg_present=%d\n",
type, chip->chg_present);
if (!chip->battery_missing && !chip->apsd_rerun) {
if (type == POWER_SUPPLY_TYPE_USB) {
smb1351_request_dpdm(chip, false);
smb1351_request_dpdm(chip, true);
chip->apsd_rerun = true;
rerun_apsd(chip);
return 0;
}
}
/*
* If defined force hvdcp 2p0 property,
* we force to hvdcp 2p0 in the APSD handler.
*/
if (chip->force_hvdcp_2p0) {
pr_debug("Force set to HVDCP 2.0 mode\n");
smb1351_masked_write(chip, VARIOUS_FUNC_3_REG,
QC_2P1_AUTH_ALGO_BIT, 0);
smb1351_masked_write(chip, CMD_HVDCP_REG,
CMD_FORCE_HVDCP_2P0_BIT,
CMD_FORCE_HVDCP_2P0_BIT);
type = POWER_SUPPLY_TYPE_USB_HVDCP;
} else if (type == POWER_SUPPLY_TYPE_USB_DCP) {
pr_debug("schedule hvdcp detection worker\n");
pm_stay_awake(chip->dev);
schedule_delayed_work(&chip->hvdcp_det_work,
msecs_to_jiffies(HVDCP_NOTIFY_MS));
}
chip->charger_type = type;
if (type == POWER_SUPPLY_TYPE_USB
|| type == POWER_SUPPLY_TYPE_USB_CDP) {
val.intval = true;
extcon_set_property(chip->extcon, EXTCON_USB,
EXTCON_PROP_USB_SS, val);
extcon_set_state_sync(chip->extcon, EXTCON_USB, true);
pr_debug("extcon notify: EXTCON_USB present = 1\n");
}
chip->apsd_rerun = false;
/* set the charge current as required */
if (type == POWER_SUPPLY_TYPE_USB)
usb_psy_ma = USB2_MIN_CURRENT_MA;
else /* DCP */
usb_psy_ma = DCP_MAX_CURRENT_MA;
chip->usb_psy_ma = usb_psy_ma;
smb1351_enable_volatile_writes(chip);
rc = smb1351_set_usb_chg_current(chip, chip->usb_psy_ma);
if (rc < 0)
pr_err("Failed to set USB current rc=%d\n", rc);
} else if (!chip->apsd_rerun) {
/* Handle Charger removal */
chip->chg_present = 0;
chip->charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
val.intval = false;
extcon_set_property(chip->extcon, EXTCON_USB,
EXTCON_PROP_USB_SS, val);
extcon_set_state_sync(chip->extcon, EXTCON_USB, false);
pr_debug("extcon notify: EXTCON_USB present = 0\n");
smb1351_request_dpdm(chip, false);
}
return 0;
}
/*
* As source detect interrupt is not triggered on the falling edge,
* we need to schedule a work for checking source detect status after
* charger UV interrupt fired.
*/
#define FIRST_CHECK_DELAY 100
#define SECOND_CHECK_DELAY 1000
static void smb1351_chg_remove_work(struct work_struct *work)
{
int rc;
u8 reg;
struct smb1351_charger *chip = container_of(work,
struct smb1351_charger, chg_remove_work.work);
rc = smb1351_read_reg(chip, IRQ_G_REG, &reg);
if (rc) {
pr_err("Couldn't read IRQ_G_REG rc = %d\n", rc);
goto end;
}
if (!(reg & IRQ_SOURCE_DET_BIT)) {
pr_debug("chg removed\n");
smb1351_apsd_complete_handler(chip, 0);
} else if (!chip->chg_remove_work_scheduled) {
chip->chg_remove_work_scheduled = true;
goto reschedule;
} else {
pr_debug("charger is present\n");
}
end:
chip->chg_remove_work_scheduled = false;
pm_relax(chip->dev);
return;
reschedule:
pr_debug("reschedule after 1s\n");
schedule_delayed_work(&chip->chg_remove_work,
msecs_to_jiffies(SECOND_CHECK_DELAY));
}
static int smb1351_usbin_uv_handler(struct smb1351_charger *chip, u8 status)
{
smb1351_request_dpdm(chip, !!status);
if (status) {
cancel_delayed_work_sync(&chip->hvdcp_det_work);
pm_relax(chip->dev);
pr_debug("schedule charger remove worker\n");
schedule_delayed_work(&chip->chg_remove_work,
msecs_to_jiffies(FIRST_CHECK_DELAY));
pm_stay_awake(chip->dev);
}
pr_debug("chip->chg_present = %d\n", chip->chg_present);
return 0;
}
static int smb1351_usbin_ov_handler(struct smb1351_charger *chip, u8 status)
{
int rc;
u8 reg = 0;
rc = smb1351_read_reg(chip, IRQ_E_REG, &reg);
if (rc)
pr_err("Couldn't read IRQ_E rc = %d\n", rc);
if (status != 0) {
chip->usbin_ov = true;
chip->charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
if (chip->chg_present) {
extcon_set_state_sync(chip->extcon, EXTCON_USB, false);
pr_debug("extcon notify: EXTCON_USB present = 0\n");
}
chip->chg_present = false;
} else {
chip->usbin_ov = false;
if (reg & IRQ_USBIN_UV_BIT)
pr_debug("Charger unplugged from OV\n");
else
smb1351_apsd_complete_handler(chip, 1);
}
pr_debug("chip->chg_present = %d\n", chip->chg_present);
return 0;
}
static int smb1351_fast_chg_handler(struct smb1351_charger *chip, u8 status)
{
pr_debug("enter\n");
return 0;
}
static int smb1351_chg_term_handler(struct smb1351_charger *chip, u8 status)
{
pr_debug("enter\n");
if (!chip->bms_controlled_charging)
chip->batt_full = !!status;
return 0;
}
static int smb1351_safety_timeout_handler(struct smb1351_charger *chip,
u8 status)
{
pr_debug("safety_timeout triggered\n");
return 0;
}
static int smb1351_aicl_done_handler(struct smb1351_charger *chip, u8 status)
{
pr_debug("aicl_done triggered\n");
return 0;
}
static int smb1351_hot_hard_handler(struct smb1351_charger *chip, u8 status)
{
pr_debug("status = 0x%02x\n", status);
chip->batt_hot = !!status;
return 0;
}
static int smb1351_cold_hard_handler(struct smb1351_charger *chip, u8 status)
{
pr_debug("status = 0x%02x\n", status);
chip->batt_cold = !!status;
return 0;
}
static int smb1351_hot_soft_handler(struct smb1351_charger *chip, u8 status)
{
pr_debug("status = 0x%02x\n", status);
chip->batt_warm = !!status;
return 0;
}
static int smb1351_cold_soft_handler(struct smb1351_charger *chip, u8 status)
{
pr_debug("status = 0x%02x\n", status);
chip->batt_cool = !!status;
return 0;
}
static int smb1351_battery_missing_handler(struct smb1351_charger *chip,
u8 status)
{
if (status)
chip->battery_missing = true;
else
chip->battery_missing = false;
return 0;
}
static int smb1351_rid_handler(struct smb1351_charger *chip,
u8 status)
{
union extcon_property_value val;
bool rid_status;
u8 reg = 0;
int rc;
rc = smb1351_read_reg(chip, STATUS_6_REG, &reg);
if (rc < 0)
pr_err("Couldn't read status_6_reg, rc=%d\n", rc);
pr_debug("rt_status = 0x%02x, status_6_reg=0x%x\n", status, reg);
rid_status = (!!status) || !(reg & STATUS_RID_FLOAT_STATE_MACHINE_BIT);
if (rid_status) {
val.intval = true;
extcon_set_property(chip->extcon, EXTCON_USB_HOST,
EXTCON_PROP_USB_SS, val);
}
extcon_set_state_sync(chip->extcon, EXTCON_USB_HOST, rid_status);
pr_debug("extcon notify: EXTCON_USB_HOST present = %d\n", rid_status);
return 0;
}
static struct irq_handler_info handlers[] = {
[0] = {
.stat_reg = IRQ_A_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "cold_soft",
.smb_irq = smb1351_cold_soft_handler,
},
{ .name = "hot_soft",
.smb_irq = smb1351_hot_soft_handler,
},
{ .name = "cold_hard",
.smb_irq = smb1351_cold_hard_handler,
},
{ .name = "hot_hard",
.smb_irq = smb1351_hot_hard_handler,
},
},
},
[1] = {
.stat_reg = IRQ_B_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "internal_temp_limit",
},
{ .name = "vbatt_low",
},
{ .name = "battery_missing",
.smb_irq = smb1351_battery_missing_handler,
},
{ .name = "batt_therm_removed",
},
},
},
[2] = {
.stat_reg = IRQ_C_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "chg_term",
.smb_irq = smb1351_chg_term_handler,
},
{ .name = "taper",
},
{ .name = "recharge",
},
{ .name = "fast_chg",
.smb_irq = smb1351_fast_chg_handler,
},
},
},
[3] = {
.stat_reg = IRQ_D_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "prechg_timeout",
},
{ .name = "safety_timeout",
.smb_irq = smb1351_safety_timeout_handler,
},
{ .name = "chg_error",
},
{ .name = "batt_ov",
},
},
},
[4] = {
.stat_reg = IRQ_E_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "power_ok",
},
{ .name = "afvc",
},
{ .name = "usbin_uv",
.smb_irq = smb1351_usbin_uv_handler,
},
{ .name = "usbin_ov",
.smb_irq = smb1351_usbin_ov_handler,
},
},
},
[5] = {
.stat_reg = IRQ_F_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "otg_oc_retry",
},
{ .name = "rid",
.smb_irq = smb1351_rid_handler,
},
{ .name = "otg_fail",
},
{ .name = "otg_oc",
},
},
},
[6] = {
.stat_reg = IRQ_G_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "chg_inhibit",
},
{ .name = "aicl_fail",
},
{ .name = "aicl_done",
.smb_irq = smb1351_aicl_done_handler,
},
{ .name = "apsd_complete",
.smb_irq = smb1351_apsd_complete_handler,
},
},
},
[7] = {
.stat_reg = IRQ_H_REG,
.val = 0,
.prev_val = 0,
.irq_info = {
{ .name = "wdog_timeout",
},
{ .name = "hvdcp_auth_done",
},
},
},
};
#define IRQ_LATCHED_MASK 0x02
#define IRQ_STATUS_MASK 0x01
#define BITS_PER_IRQ 2
static irqreturn_t smb1351_chg_stat_handler(int irq, void *dev_id)
{
struct smb1351_charger *chip = dev_id;
int i, j;
u8 triggered;
u8 changed;
u8 rt_stat, prev_rt_stat;
int rc;
int handler_count = 0;
mutex_lock(&chip->irq_complete);
chip->irq_waiting = true;
if (!chip->resume_completed) {
pr_debug("IRQ triggered before device-resume\n");
disable_irq_nosync(irq);
mutex_unlock(&chip->irq_complete);
return IRQ_HANDLED;
}
chip->irq_waiting = false;
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
rc = smb1351_read_reg(chip, handlers[i].stat_reg,
&handlers[i].val);
if (rc) {
pr_err("Couldn't read %d rc = %d\n",
handlers[i].stat_reg, rc);
continue;
}
for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) {
triggered = handlers[i].val
& (IRQ_LATCHED_MASK << (j * BITS_PER_IRQ));
rt_stat = handlers[i].val
& (IRQ_STATUS_MASK << (j * BITS_PER_IRQ));
prev_rt_stat = handlers[i].prev_val
& (IRQ_STATUS_MASK << (j * BITS_PER_IRQ));
changed = prev_rt_stat ^ rt_stat;
if (triggered || changed)
rt_stat ? handlers[i].irq_info[j].high++ :
handlers[i].irq_info[j].low++;
if ((triggered || changed)
&& handlers[i].irq_info[j].smb_irq != NULL) {
handler_count++;
rc = handlers[i].irq_info[j].smb_irq(chip,
rt_stat);
if (rc)
pr_err("Couldn't handle %d irq for reg 0x%02x rc = %d\n",
j, handlers[i].stat_reg, rc);
}
}
handlers[i].prev_val = handlers[i].val;
}
pr_debug("handler count = %d\n", handler_count);
if (handler_count) {
pr_debug("batt psy changed\n");
power_supply_changed(chip->batt_psy);
}
mutex_unlock(&chip->irq_complete);
return IRQ_HANDLED;
}
#define LAST_CNFG_REG 0x16
static int show_cnfg_regs(struct seq_file *m, void *data)
{
struct smb1351_charger *chip = m->private;
int rc;
u8 reg;
u8 addr;
for (addr = 0; addr <= LAST_CNFG_REG; addr++) {
rc = smb1351_read_reg(chip, addr, &reg);
if (!rc)
seq_printf(m, "0x%02x = 0x%02x\n", addr, reg);
}
return 0;
}
static int cnfg_debugfs_open(struct inode *inode, struct file *file)
{
struct smb1351_charger *chip = inode->i_private;
return single_open(file, show_cnfg_regs, chip);
}
static const struct file_operations cnfg_debugfs_ops = {
.owner = THIS_MODULE,
.open = cnfg_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#define FIRST_CMD_REG 0x30
#define LAST_CMD_REG 0x34
static int show_cmd_regs(struct seq_file *m, void *data)
{
struct smb1351_charger *chip = m->private;
int rc;
u8 reg;
u8 addr;
for (addr = FIRST_CMD_REG; addr <= LAST_CMD_REG; addr++) {
rc = smb1351_read_reg(chip, addr, &reg);
if (!rc)
seq_printf(m, "0x%02x = 0x%02x\n", addr, reg);
}
return 0;
}
static int cmd_debugfs_open(struct inode *inode, struct file *file)
{
struct smb1351_charger *chip = inode->i_private;
return single_open(file, show_cmd_regs, chip);
}
static const struct file_operations cmd_debugfs_ops = {
.owner = THIS_MODULE,
.open = cmd_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#define FIRST_STATUS_REG 0x36
#define LAST_STATUS_REG 0x3F
static int show_status_regs(struct seq_file *m, void *data)
{
struct smb1351_charger *chip = m->private;
int rc;
u8 reg;
u8 addr;
for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) {
rc = smb1351_read_reg(chip, addr, &reg);
if (!rc)
seq_printf(m, "0x%02x = 0x%02x\n", addr, reg);
}
return 0;
}
static int status_debugfs_open(struct inode *inode, struct file *file)
{
struct smb1351_charger *chip = inode->i_private;
return single_open(file, show_status_regs, chip);
}
static const struct file_operations status_debugfs_ops = {
.owner = THIS_MODULE,
.open = status_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int show_irq_count(struct seq_file *m, void *data)
{
int i, j, total = 0;
for (i = 0; i < ARRAY_SIZE(handlers); i++)
for (j = 0; j < 4; j++) {
seq_printf(m, "%s=%d\t(high=%d low=%d)\n",
handlers[i].irq_info[j].name,
handlers[i].irq_info[j].high
+ handlers[i].irq_info[j].low,
handlers[i].irq_info[j].high,
handlers[i].irq_info[j].low);
total += (handlers[i].irq_info[j].high
+ handlers[i].irq_info[j].low);
}
seq_printf(m, "\n\tTotal = %d\n", total);
return 0;
}
static int irq_count_debugfs_open(struct inode *inode, struct file *file)
{
struct smb1351_charger *chip = inode->i_private;
return single_open(file, show_irq_count, chip);
}
static const struct file_operations irq_count_debugfs_ops = {
.owner = THIS_MODULE,
.open = irq_count_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int get_reg(void *data, u64 *val)
{
struct smb1351_charger *chip = data;
int rc;
u8 temp;
rc = smb1351_read_reg(chip, chip->peek_poke_address, &temp);
if (rc) {
pr_err("Couldn't read reg %x rc = %d\n",
chip->peek_poke_address, rc);
return -EAGAIN;
}
*val = temp;
return 0;
}
static int set_reg(void *data, u64 val)
{
struct smb1351_charger *chip = data;
int rc;
u8 temp;
temp = (u8) val;
rc = smb1351_write_reg(chip, chip->peek_poke_address, temp);
if (rc) {
pr_err("Couldn't write 0x%02x to 0x%02x rc= %d\n",
temp, chip->peek_poke_address, rc);
return -EAGAIN;
}
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n");
static int force_irq_set(void *data, u64 val)
{
struct smb1351_charger *chip = data;
smb1351_chg_stat_handler(chip->client->irq, data);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(force_irq_ops, NULL, force_irq_set, "0x%02llx\n");
#ifdef DEBUG
static void dump_regs(struct smb1351_charger *chip)
{
int rc;
u8 reg;
u8 addr;
for (addr = 0; addr <= LAST_CNFG_REG; addr++) {
rc = smb1351_read_reg(chip, addr, &reg);
if (rc)
pr_err("Couldn't read 0x%02x rc = %d\n", addr, rc);
else
pr_debug("0x%02x = 0x%02x\n", addr, reg);
}
for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) {
rc = smb1351_read_reg(chip, addr, &reg);
if (rc)
pr_err("Couldn't read 0x%02x rc = %d\n", addr, rc);
else
pr_debug("0x%02x = 0x%02x\n", addr, reg);
}
for (addr = FIRST_CMD_REG; addr <= LAST_CMD_REG; addr++) {
rc = smb1351_read_reg(chip, addr, &reg);
if (rc)
pr_err("Couldn't read 0x%02x rc = %d\n", addr, rc);
else
pr_debug("0x%02x = 0x%02x\n", addr, reg);
}
}
#else
static void dump_regs(struct smb1351_charger *chip)
{
}
#endif
static int smb1351_parse_dt(struct smb1351_charger *chip)
{
int rc;
struct device_node *node = chip->dev->of_node;
if (!node) {
pr_err("device tree info. missing\n");
return -EINVAL;
}
chip->usb_suspended_status = of_property_read_bool(node,
"qcom,charging-disabled");
chip->battchg_disabled_status = of_property_read_bool(node,
"qcom,batt-charging-disabled");
chip->chg_autonomous_mode = of_property_read_bool(node,
"qcom,chg-autonomous-mode");
chip->disable_apsd = of_property_read_bool(node, "qcom,disable-apsd");
chip->bms_controlled_charging = of_property_read_bool(node,
"qcom,bms-controlled-charging");
chip->force_hvdcp_2p0 = of_property_read_bool(node,
"qcom,force-hvdcp-2p0");
rc = of_property_read_string(node, "qcom,bms-psy-name",
&chip->bms_psy_name);
if (rc)
chip->bms_psy_name = NULL;
rc = of_property_read_u32(node, "qcom,fastchg-current-max-ma",
&chip->target_fastchg_current_max_ma);
if (rc)
chip->target_fastchg_current_max_ma = SMB1351_CHG_FAST_MAX_MA;
chip->iterm_disabled = of_property_read_bool(node,
"qcom,iterm-disabled");
rc = of_property_read_u32(node, "qcom,iterm-ma", &chip->iterm_ma);
if (rc)
chip->iterm_ma = -EINVAL;
rc = of_property_read_u32(node, "qcom,float-voltage-mv",
&chip->vfloat_mv);
if (rc)
chip->vfloat_mv = -EINVAL;
rc = of_property_read_u32(node, "qcom,recharge-mv",
&chip->recharge_mv);
if (rc)
chip->recharge_mv = -EINVAL;
chip->recharge_disabled = of_property_read_bool(node,
"qcom,recharge-disabled");
chip->pinctrl_state_name = of_get_property(node, "pinctrl-names", NULL);
chip->otg_enable = of_property_read_bool(node, "qcom,otg-enable");
return 0;
}
static int smb1351_determine_initial_state(struct smb1351_charger *chip)
{
int rc;
u8 reg = 0;
/*
* It is okay to read the interrupt status here since
* interrupts aren't requested. Reading interrupt status
* clears the interrupt so be careful to read interrupt
* status only in interrupt handling code
*/
rc = smb1351_read_reg(chip, IRQ_B_REG, &reg);
if (rc) {
pr_err("Couldn't read IRQ_B rc = %d\n", rc);
goto fail_init_status;
}
chip->battery_missing = (reg & IRQ_BATT_MISSING_BIT) ? true : false;
rc = smb1351_read_reg(chip, IRQ_C_REG, &reg);
if (rc) {
pr_err("Couldn't read IRQ_C rc = %d\n", rc);
goto fail_init_status;
}
chip->batt_full = (reg & IRQ_TERM_BIT) ? true : false;
rc = smb1351_read_reg(chip, IRQ_A_REG, &reg);
if (rc) {
pr_err("Couldn't read irq A rc = %d\n", rc);
return rc;
}
if (reg & IRQ_HOT_HARD_BIT)
chip->batt_hot = true;
if (reg & IRQ_COLD_HARD_BIT)
chip->batt_cold = true;
if (reg & IRQ_HOT_SOFT_BIT)
chip->batt_warm = true;
if (reg & IRQ_COLD_SOFT_BIT)
chip->batt_cool = true;
rc = smb1351_read_reg(chip, IRQ_E_REG, &reg);
if (rc) {
pr_err("Couldn't read IRQ_E rc = %d\n", rc);
goto fail_init_status;
}
if (reg & IRQ_USBIN_UV_BIT) {
smb1351_usbin_uv_handler(chip, 1);
} else {
smb1351_usbin_uv_handler(chip, 0);
smb1351_apsd_complete_handler(chip, 1);
}
rc = smb1351_read_reg(chip, IRQ_G_REG, &reg);
if (rc) {
pr_err("Couldn't read IRQ_G rc = %d\n", rc);
goto fail_init_status;
}
if (reg & IRQ_SOURCE_DET_BIT)
smb1351_apsd_complete_handler(chip, 1);
return 0;
fail_init_status:
pr_err("Couldn't determine initial status\n");
return rc;
}
static int is_parallel_charger(struct i2c_client *client)
{
struct device_node *node = client->dev.of_node;
return of_property_read_bool(node, "qcom,parallel-charger");
}
static int create_debugfs_entries(struct smb1351_charger *chip)
{
struct dentry *ent;
chip->debug_root = debugfs_create_dir("smb1351", NULL);
if (!chip->debug_root) {
pr_err("Couldn't create debug dir\n");
} else {
ent = debugfs_create_file("config_registers", S_IFREG | 0444,
chip->debug_root, chip,
&cnfg_debugfs_ops);
if (!ent)
pr_err("Couldn't create cnfg debug file\n");
ent = debugfs_create_file("status_registers", S_IFREG | 0444,
chip->debug_root, chip,
&status_debugfs_ops);
if (!ent)
pr_err("Couldn't create status debug file\n");
ent = debugfs_create_file("cmd_registers", S_IFREG | 0444,
chip->debug_root, chip,
&cmd_debugfs_ops);
if (!ent)
pr_err("Couldn't create cmd debug file\n");
ent = debugfs_create_x32("address", S_IFREG | 0644,
chip->debug_root,
&(chip->peek_poke_address));
if (!ent)
pr_err("Couldn't create address debug file\n");
ent = debugfs_create_file("data", S_IFREG | 0644,
chip->debug_root, chip,
&poke_poke_debug_ops);
if (!ent)
pr_err("Couldn't create data debug file\n");
ent = debugfs_create_file("force_irq",
S_IFREG | 0644,
chip->debug_root, chip,
&force_irq_ops);
if (!ent)
pr_err("Couldn't create data debug file\n");
ent = debugfs_create_file("irq_count", S_IFREG | 0444,
chip->debug_root, chip,
&irq_count_debugfs_ops);
if (!ent)
pr_err("Couldn't create count debug file\n");
}
return 0;
}
static int smb1351_main_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
struct smb1351_charger *chip;
struct power_supply_config batt_psy_cfg = {};
struct power_supply_config usb_psy_cfg = {};
u8 reg = 0;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->client = client;
chip->dev = &client->dev;
chip->fake_battery_soc = -EINVAL;
chip->extcon = devm_extcon_dev_allocate(chip->dev,
smb1351_extcon_cable);
if (IS_ERR(chip->extcon)) {
pr_err("failed to allocate extcon device\n");
rc = PTR_ERR(chip->extcon);
return rc;
}
rc = devm_extcon_dev_register(chip->dev, chip->extcon);
if (rc) {
pr_err("failed to register extcon device\n");
return rc;
}
rc = extcon_set_property_capability(chip->extcon,
EXTCON_USB, EXTCON_PROP_USB_SS);
rc |= extcon_set_property_capability(chip->extcon,
EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
if (rc < 0) {
pr_err("Failed to register extcon capability rc=%d\n", rc);
return rc;
}
chip->usb_psy_d.name = "usb";
chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB;
chip->usb_psy_d.get_property = smb1351_usb_get_property;
chip->usb_psy_d.set_property = smb1351_usb_set_property;
chip->usb_psy_d.properties = smb1351_usb_properties;
chip->usb_psy_d.num_properties = ARRAY_SIZE(smb1351_usb_properties);
chip->usb_psy_d.property_is_writeable = smb1351_usb_is_writeable;
usb_psy_cfg.drv_data = chip;
usb_psy_cfg.supplied_to = smb1351_usb_supplicants;
usb_psy_cfg.num_supplicants = ARRAY_SIZE(smb1351_usb_supplicants);
chip->usb_psy = devm_power_supply_register(chip->dev,
&chip->usb_psy_d, &usb_psy_cfg);
if (IS_ERR(chip->usb_psy)) {
pr_err("Unable to register usb_psy rc = %ld\n",
PTR_ERR(chip->usb_psy));
rc = PTR_ERR(chip->usb_psy);
return rc;
}
INIT_DELAYED_WORK(&chip->chg_remove_work, smb1351_chg_remove_work);
INIT_DELAYED_WORK(&chip->hvdcp_det_work, smb1351_hvdcp_det_work);
device_init_wakeup(chip->dev, true);
/* probe the device to check if its actually connected */
rc = smb1351_read_reg(chip, CHG_REVISION_REG, &reg);
if (rc) {
pr_err("Failed to detect smb1351, device may be absent\n");
return -ENODEV;
}
pr_debug("smb1351 chip revision is %d\n", reg);
rc = smb1351_parse_dt(chip);
if (rc) {
pr_err("Couldn't parse DT nodes rc=%d\n", rc);
return rc;
}
i2c_set_clientdata(client, chip);
chip->batt_psy_d.name = "battery";
chip->batt_psy_d.type = POWER_SUPPLY_TYPE_BATTERY;
chip->batt_psy_d.get_property = smb1351_battery_get_property;
chip->batt_psy_d.set_property = smb1351_battery_set_property;
chip->batt_psy_d.property_is_writeable =
smb1351_batt_property_is_writeable;
chip->batt_psy_d.properties = smb1351_battery_properties;
chip->batt_psy_d.num_properties =
ARRAY_SIZE(smb1351_battery_properties);
chip->resume_completed = true;
mutex_init(&chip->irq_complete);
batt_psy_cfg.drv_data = chip;
batt_psy_cfg.supplied_to = pm_batt_supplied_to;
batt_psy_cfg.num_supplicants = ARRAY_SIZE(pm_batt_supplied_to);
chip->batt_psy = devm_power_supply_register(chip->dev,
&chip->batt_psy_d,
&batt_psy_cfg);
if (IS_ERR(chip->batt_psy)) {
pr_err("Couldn't register batt psy rc=%ld\n",
PTR_ERR(chip->batt_psy));
return rc;
}
dump_regs(chip);
rc = smb1351_regulator_init(chip);
if (rc) {
pr_err("Couldn't initialize smb1351 ragulator rc=%d\n", rc);
goto fail_smb1351_regulator_init;
}
rc = smb1351_hw_init(chip);
if (rc) {
pr_err("Couldn't initialize hardware rc=%d\n", rc);
goto fail_smb1351_hw_init;
}
rc = smb1351_determine_initial_state(chip);
if (rc) {
pr_err("Couldn't determine initial state rc=%d\n", rc);
goto fail_smb1351_hw_init;
}
/* STAT irq configuration */
if (client->irq) {
rc = devm_request_threaded_irq(&client->dev, client->irq, NULL,
smb1351_chg_stat_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"smb1351_chg_stat_irq", chip);
if (rc) {
pr_err("Failed STAT irq=%d request rc = %d\n",
client->irq, rc);
goto fail_smb1351_hw_init;
}
enable_irq_wake(client->irq);
}
create_debugfs_entries(chip);
dump_regs(chip);
pr_info("smb1351 successfully probed. charger=%d, batt=%d version=%s\n",
chip->chg_present,
smb1351_get_prop_batt_present(chip),
smb1351_version_str[chip->version]);
return 0;
fail_smb1351_hw_init:
regulator_unregister(chip->otg_vreg.rdev);
fail_smb1351_regulator_init:
return rc;
}
static int smb1351_parallel_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
struct smb1351_charger *chip;
struct device_node *node = client->dev.of_node;
struct power_supply_config parallel_psy_cfg = {};
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->client = client;
chip->dev = &client->dev;
chip->parallel_charger = true;
chip->parallel_charger_suspended = true;
chip->usb_suspended_status = of_property_read_bool(node,
"qcom,charging-disabled");
rc = of_property_read_u32(node, "qcom,float-voltage-mv",
&chip->vfloat_mv);
if (rc)
chip->vfloat_mv = -EINVAL;
rc = of_property_read_u32(node, "qcom,recharge-mv",
&chip->recharge_mv);
if (rc)
chip->recharge_mv = -EINVAL;
rc = of_property_read_u32(node, "qcom,parallel-en-pin-polarity",
&chip->parallel_pin_polarity_setting);
if (rc)
chip->parallel_pin_polarity_setting = EN_BY_PIN_LOW_ENABLE;
else
chip->parallel_pin_polarity_setting =
chip->parallel_pin_polarity_setting ?
EN_BY_PIN_HIGH_ENABLE : EN_BY_PIN_LOW_ENABLE;
if (of_property_read_bool(node,
"qcom,parallel-external-current-sense"))
chip->parallel_mode = POWER_SUPPLY_PL_USBIN_USBIN_EXT;
else
chip->parallel_mode = POWER_SUPPLY_PL_USBIN_USBIN;
chip->pl_batfet_mode = POWER_SUPPLY_PL_NON_STACKED_BATFET;
if (of_property_read_bool(node, "qcom,stacked-batfet"))
chip->pl_batfet_mode = POWER_SUPPLY_PL_STACKED_BATFET;
i2c_set_clientdata(client, chip);
chip->parallel_psy_d.name = "parallel";
chip->parallel_psy_d.type = POWER_SUPPLY_TYPE_PARALLEL;
chip->parallel_psy_d.get_property = smb1351_parallel_get_property;
chip->parallel_psy_d.set_property = smb1351_parallel_set_property;
chip->parallel_psy_d.properties = smb1351_parallel_properties;
chip->parallel_psy_d.property_is_writeable
= smb1351_parallel_is_writeable;
chip->parallel_psy_d.num_properties
= ARRAY_SIZE(smb1351_parallel_properties);
parallel_psy_cfg.drv_data = chip;
parallel_psy_cfg.num_supplicants = 0;
chip->parallel_psy = devm_power_supply_register(chip->dev,
&chip->parallel_psy_d,
&parallel_psy_cfg);
if (IS_ERR(chip->parallel_psy)) {
pr_err("Couldn't register parallel psy rc=%ld\n",
PTR_ERR(chip->parallel_psy));
return rc;
}
chip->resume_completed = true;
mutex_init(&chip->irq_complete);
create_debugfs_entries(chip);
pr_info("smb1351 parallel successfully probed.\n");
return 0;
}
static int smb1351_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
if (is_parallel_charger(client))
return smb1351_parallel_charger_probe(client, id);
else
return smb1351_main_charger_probe(client, id);
}
static int smb1351_charger_remove(struct i2c_client *client)
{
struct smb1351_charger *chip = i2c_get_clientdata(client);
cancel_delayed_work_sync(&chip->chg_remove_work);
mutex_destroy(&chip->irq_complete);
debugfs_remove_recursive(chip->debug_root);
return 0;
}
static int smb1351_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct smb1351_charger *chip = i2c_get_clientdata(client);
/* no suspend resume activities for parallel charger */
if (chip->parallel_charger)
return 0;
mutex_lock(&chip->irq_complete);
chip->resume_completed = false;
mutex_unlock(&chip->irq_complete);
return 0;
}
static int smb1351_suspend_noirq(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct smb1351_charger *chip = i2c_get_clientdata(client);
/* no suspend resume activities for parallel charger */
if (chip->parallel_charger)
return 0;
if (chip->irq_waiting) {
pr_err_ratelimited("Aborting suspend, an interrupt was detected while suspending\n");
return -EBUSY;
}
return 0;
}
static int smb1351_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct smb1351_charger *chip = i2c_get_clientdata(client);
/* no suspend resume activities for parallel charger */
if (chip->parallel_charger)
return 0;
mutex_lock(&chip->irq_complete);
chip->resume_completed = true;
if (chip->irq_waiting) {
mutex_unlock(&chip->irq_complete);
smb1351_chg_stat_handler(client->irq, chip);
enable_irq(client->irq);
} else {
mutex_unlock(&chip->irq_complete);
}
return 0;
}
static const struct dev_pm_ops smb1351_pm_ops = {
.suspend = smb1351_suspend,
.suspend_noirq = smb1351_suspend_noirq,
.resume = smb1351_resume,
};
static const struct of_device_id smb1351_match_table[] = {
{ .compatible = "qcom,smb1351-charger",},
{ },
};
static const struct i2c_device_id smb1351_charger_id[] = {
{"smb1351-charger", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, smb1351_charger_id);
static struct i2c_driver smb1351_charger_driver = {
.driver = {
.name = "smb1351-charger",
.owner = THIS_MODULE,
.of_match_table = smb1351_match_table,
.pm = &smb1351_pm_ops,
},
.probe = smb1351_charger_probe,
.remove = smb1351_charger_remove,
.id_table = smb1351_charger_id,
};
module_i2c_driver(smb1351_charger_driver);
MODULE_DESCRIPTION("smb1351 Charger");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("i2c:smb1351-charger");