/*
* Battery power supply driver for X-Powers AXP20X and AXP22X PMICs
*
* Copyright 2016 Free Electrons NextThing Co.
* Quentin Schulz <quentin.schulz@free-electrons.com>
*
* This driver is based on a previous upstreaming attempt by:
* Bruno Prémont <bonbons@linux-vserver.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
* archive for more details.
*
* 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.
*/
#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/iio/iio.h>
#include <linux/iio/consumer.h>
#include <linux/mfd/axp20x.h>
#define AXP20X_PWR_STATUS_BAT_CHARGING BIT(2)
#define AXP717_PWR_STATUS_MASK GENMASK(6, 5)
#define AXP717_PWR_STATUS_BAT_STANDBY 0
#define AXP717_PWR_STATUS_BAT_CHRG 1
#define AXP717_PWR_STATUS_BAT_DISCHRG 2
#define AXP20X_PWR_OP_BATT_PRESENT BIT(5)
#define AXP20X_PWR_OP_BATT_ACTIVATED BIT(3)
#define AXP717_PWR_OP_BATT_PRESENT BIT(3)
#define AXP717_BATT_PMU_FAULT_MASK GENMASK(2, 0)
#define AXP717_BATT_UVLO_2_5V BIT(2)
#define AXP717_BATT_OVER_TEMP BIT(1)
#define AXP717_BATT_UNDER_TEMP BIT(0)
#define AXP209_FG_PERCENT GENMASK(6, 0)
#define AXP22X_FG_VALID BIT(7)
#define AXP20X_CHRG_CTRL1_ENABLE BIT(7)
#define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5)
#define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5)
#define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5)
#define AXP20X_CHRG_CTRL1_TGT_4_2V (2 << 5)
#define AXP20X_CHRG_CTRL1_TGT_4_36V (3 << 5)
#define AXP22X_CHRG_CTRL1_TGT_4_22V (1 << 5)
#define AXP22X_CHRG_CTRL1_TGT_4_24V (3 << 5)
#define AXP717_CHRG_ENABLE BIT(1)
#define AXP717_CHRG_CV_VOLT_MASK GENMASK(2, 0)
#define AXP717_CHRG_CV_4_0V 0
#define AXP717_CHRG_CV_4_1V 1
#define AXP717_CHRG_CV_4_2V 2
#define AXP717_CHRG_CV_4_35V 3
#define AXP717_CHRG_CV_4_4V 4
/* Values 5 and 6 reserved. */
#define AXP717_CHRG_CV_5_0V 7
#define AXP813_CHRG_CTRL1_TGT_4_35V (3 << 5)
#define AXP20X_CHRG_CTRL1_TGT_CURR GENMASK(3, 0)
#define AXP717_ICC_CHARGER_LIM_MASK GENMASK(5, 0)
#define AXP717_ITERM_CHG_LIM_MASK GENMASK(3, 0)
#define AXP717_ITERM_CC_STEP 64000
#define AXP20X_V_OFF_MASK GENMASK(2, 0)
#define AXP717_V_OFF_MASK GENMASK(6, 4)
#define AXP717_BAT_VMIN_MIN_UV 2600000
#define AXP717_BAT_VMIN_MAX_UV 3300000
#define AXP717_BAT_VMIN_STEP 100000
#define AXP717_BAT_CV_MIN_UV 4000000
#define AXP717_BAT_CV_MAX_UV 5000000
#define AXP717_BAT_CC_MIN_UA 0
#define AXP717_BAT_CC_MAX_UA 3008000
#define AXP717_TS_PIN_DISABLE BIT(4)
struct axp20x_batt_ps;
struct axp_data {
int ccc_scale;
int ccc_offset;
unsigned int ccc_reg;
unsigned int ccc_mask;
bool has_fg_valid;
const struct power_supply_desc *bat_ps_desc;
int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);
int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val);
int (*cfg_iio_chan)(struct platform_device *pdev,
struct axp20x_batt_ps *axp_batt);
void (*set_bat_info)(struct platform_device *pdev,
struct axp20x_batt_ps *axp_batt,
struct power_supply_battery_info *info);
};
struct axp20x_batt_ps {
struct regmap *regmap;
struct power_supply *batt;
struct device *dev;
struct iio_channel *batt_chrg_i;
struct iio_channel *batt_dischrg_i;
struct iio_channel *batt_v;
/* Maximum constant charge current */
unsigned int max_ccc;
const struct axp_data *data;
bool ts_disable;
};
static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
int *val)
{
int ret, reg;
ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®);
if (ret)
return ret;
switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
case AXP20X_CHRG_CTRL1_TGT_4_1V:
*val = 4100000;
break;
case AXP20X_CHRG_CTRL1_TGT_4_15V:
*val = 4150000;
break;
case AXP20X_CHRG_CTRL1_TGT_4_2V:
*val = 4200000;
break;
case AXP20X_CHRG_CTRL1_TGT_4_36V:
*val = 4360000;
break;
default:
return -EINVAL;
}
return 0;
}
static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
int *val)
{
int ret, reg;
ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®);
if (ret)
return ret;
switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
case AXP20X_CHRG_CTRL1_TGT_4_1V:
*val = 4100000;
break;
case AXP20X_CHRG_CTRL1_TGT_4_2V:
*val = 4200000;
break;
case AXP22X_CHRG_CTRL1_TGT_4_22V:
*val = 4220000;
break;
case AXP22X_CHRG_CTRL1_TGT_4_24V:
*val = 4240000;
break;
default:
return -EINVAL;
}
return 0;
}
static int axp717_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
int *val)
{
int ret, reg;
ret = regmap_read(axp20x_batt->regmap, AXP717_CV_CHG_SET, ®);
if (ret)
return ret;
switch (reg & AXP717_CHRG_CV_VOLT_MASK) {
case AXP717_CHRG_CV_4_0V:
*val = 4000000;
return 0;
case AXP717_CHRG_CV_4_1V<