// SPDX-License-Identifier: GPL-2.0-or-later
/* ROHM BD71815, BD71828 and BD71878 Charger driver */
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
/* common defines */
#define BD7182x_MASK_VBAT_U 0x1f
#define BD7182x_MASK_VDCIN_U 0x0f
#define BD7182x_MASK_IBAT_U 0x3f
#define BD7182x_MASK_CURDIR_DISCHG 0x80
#define BD7182x_MASK_CHG_STATE 0x7f
#define BD7182x_MASK_BAT_TEMP 0x07
#define BD7182x_MASK_DCIN_DET BIT(0)
#define BD7182x_MASK_CONF_PON BIT(0)
#define BD71815_MASK_CONF_XSTB BIT(1)
#define BD7182x_MASK_BAT_STAT 0x3f
#define BD7182x_MASK_DCIN_STAT 0x07
#define BD7182x_MASK_WDT_AUTO 0x40
#define BD7182x_MASK_VBAT_ALM_LIMIT_U 0x01
#define BD7182x_MASK_CHG_EN 0x01
#define BD7182x_DCIN_COLLAPSE_DEFAULT 0x36
#define MAX_CURRENT_DEFAULT 890000 /* uA */
#define AC_NAME "bd71828_ac"
#define BAT_NAME "bd71828_bat"
#define BAT_OPEN 0x7
/*
* VBAT Low voltage detection Threshold
* 0x00D4*16mV = 212*0.016 = 3.392v
*/
#define VBAT_LOW_TH 0x00D4
struct pwr_regs {
u8 vbat_avg;
u8 ibat;
u8 ibat_avg;
u8 btemp_vth;
u8 chg_state;
u8 bat_temp;
u8 dcin_stat;
u8 dcin_collapse_limit;
u8 chg_set1;
u8 chg_en;
u8 vbat_alm_limit_u;
u8 conf;
u8 vdcin;
};
static const struct pwr_regs pwr_regs_bd71828 = {
.vbat_avg = BD71828_REG_VBAT_U,
.ibat = BD71828_REG_IBAT_U,
.ibat_avg = BD71828_REG_IBAT_AVG_U,
.btemp_vth = BD71828_REG_VM_BTMP_U,
.chg_state = BD71828_REG_CHG_STATE,
.bat_temp = BD71828_REG_BAT_TEMP,
.dcin_stat = BD71828_REG_DCIN_STAT,
.dcin_collapse_limit = BD71828_REG_DCIN_CLPS,
.chg_set1 = BD71828_REG_CHG_SET1,
.chg_en = BD71828_REG_CHG_EN,
.vbat_alm_limit_u = BD71828_REG_ALM_VBAT_LIMIT_U,
.conf = BD71828_REG_CONF,
.vdcin = BD71828_REG_VDCIN_U,
};
static const struct pwr_regs pwr_regs_bd71815 = {
.vbat_avg = BD71815_REG_VM_SA_VBAT_U,
/* BD71815 does not have separate current and current avg */
.ibat = BD71815_REG_CC_CURCD_U,
.ibat_avg = BD71815_REG_CC_CURCD_U,
.btemp_vth = BD71815_REG_VM_BTMP,
.chg_state = BD71815_REG_CHG_STATE,
.bat_temp = BD71815_REG_BAT_TEMP,
.dcin_stat = BD71815_REG_DCIN_STAT,
.dcin_collapse_limit = BD71815_REG_DCIN_CLPS,
.chg_set1 = BD71815_REG_CHG_SET1,
.chg_en = BD71815_REG_CHG_SET1,
.vbat_alm_limit_u = BD71815_REG_ALM_VBAT_TH_U,
.conf = BD71815_REG_CONF,
.vdcin = BD71815_REG_VM_DCIN_U,
};
struct bd71828_power {
struct regmap *regmap;
enum rohm_chip_type chip_type;
struct device *dev;
struct power_supply *ac;
struct power_supply *bat;
const struct pwr_regs *regs;
/* Reg val to uA */
int curr_factor;
int rsens;
int (*get_temp)(struct bd71828_power *pwr, int *temp);
int (*bat_inserted)(struct bd71828_power *pwr);
};
static int bd7182x_write16(struct bd71828_power *pwr, int reg, u16 val)
{
__be16 tmp;
tmp = cpu_to_be16(val);
return regmap_bulk_write(pwr->regmap, reg, &tmp, sizeof(tmp));
}
static int bd7182x_read16_himask(struct bd71828_power *pwr, int reg, int himask,
u16 *val)
{
struct regmap *regmap = pwr->regmap;
int ret;
__be16 rvals;
u8 *tmp = (u8 *)&rvals;
ret = regmap_bulk_read(regmap, reg, &rvals, sizeof(*val));
if (!ret) {
*tmp &= himask;
*val = be16_to_cpu(rvals);
}
return ret;
}
static int bd71828_get_vbat(struct bd71828_power *pwr, int *vcell)
{
u16 tmp_vcell;
int ret;
ret = bd7182x_read16_himask(pwr, pwr->regs->vbat_avg,
BD7182x_MASK_VBAT_U, &tmp_vcell);
if (ret)
dev_err(pwr->dev