power supply and reset changes for the v5.4 series
Core: * Ensure HWMON devices are registered with valid names * Fix device wakeup code Drivers: * bq25890_charger: Add BQ25895 support * axp288_fuel_gauge: Add Minix Neo Z83-4 to blacklist * sc27xx: improve battery calibration * misc. small fixes all over drivers -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAl2HhCsACgkQ2O7X88g7 +ppoKw//cPn+LOj1AJYGphqzMz207rJlgn7QFF0a0LhfQHdf6gPtrqVuZ1Mp9+RB +3aJqp6ORLpKEw7/x8IOlFVACwPRm+ikMqjchb3kYqMZCBuqmr0xYukzxvRWNf/K LIRkRWMETmaXj1KCIYdFyIt7Ff0HqlXZaFPrgCFK9DO6+wAgoE3LmgZXpya0h5ev PUYz8MnDjVd5+nkdBDpuBFvpsK66Lg0pZs5ScH1JUKrG6xoXEIU+7VeYJ7EEsfGE C54g0ZFYLGf+4zxeAyhg9sPb7/tzlM+SChZdUGk6bJ9txgWoalsfNxytb8huSfeK 9dhTVMoZ9seBEq5mfJRUTnmQMRYpLJLWxJjz0MrQotOlSnIN73tlEpuIrUzWl0p7 WIWkYu/hz+OOX0mBBngHXvnTWRQrjO+QIu9P23obFzBedtOL7LVqPtCd5FrJ48y3 xQZAZUyyEUqhq2+HZaTn9HvTbFgnbHmWd/RQDarZcojC+836MlwWC7k3XqkfIa4i h3P/t6qyc/Kf7o5YT+/TkTpUR5yh2gSwfPGwTQH4hhOxPIN4prC7sF/oySm9tEgw qLZJ8XP0KuQpBEN8qdhd00bCwEEbDc4+qRJWyjjG0WN2my8BVlzKtrcAVCWspD15 07TV84+OdIzvTXzgWUT1H47WG6RQfpX2rUSCtTwteh710beoctU= =cIXy -----END PGP SIGNATURE----- Merge tag 'for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset updates from Sebastian Reichel: "Core: - Ensure HWMON devices are registered with valid names - Fix device wakeup code Drivers: - bq25890_charger: Add BQ25895 support - axp288_fuel_gauge: Add Minix Neo Z83-4 to blacklist - sc27xx: improve battery calibration - misc small fixes all over drivers" * tag 'for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (24 commits) power: supply: cpcap-charger: Enable vbus boost voltage power: supply: sc27xx: Add POWER_SUPPLY_PROP_CALIBRATE attribute power: supply: sc27xx: Optimize the battery capacity calibration power: supply: sc27xx: Make sure the alarm capacity is larger than 0 power: supply: sc27xx: Fix the the accuracy issue of coulomb calculation power: supply: sc27xx: Fix conditon to enable the FGU interrupt power: supply: sc27xx: Add POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN attribute power: supply: max77650: add MODULE_ALIAS() power: supply: isp1704: remove redundant assignment to variable ret power: supply: bq25890_charger: Add the BQ25895 part power: supply: sc27xx: Replace devm_add_action() followed by failure action with devm_add_action_or_reset() power: supply: sc27xx: Introduce local variable 'struct device *dev' power: reset: reboot-mode: Fix author email format power: supply: ab8500: remove set but not used variables 'vbup33_vrtcn' and 'bup_vch_range' power: supply: max17042_battery: Fix a typo in function names power: reset: gpio-restart: Fix typo when gpio reset is not found power: supply: Init device wakeup after device_add() power: supply: ab8500_charger: Mark expected switch fall-through power: supply: sbs-battery: only return health when battery present MAINTAINERS: N900: Remove isp1704_charger.h record ...
This commit is contained in:
commit
619e17cf75
15 changed files with 247 additions and 130 deletions
|
@ -11511,7 +11511,6 @@ NOKIA N900 POWER SUPPLY DRIVERS
|
|||
R: Pali Rohár <pali.rohar@gmail.com>
|
||||
F: include/linux/power/bq2415x_charger.h
|
||||
F: include/linux/power/bq27xxx_battery.h
|
||||
F: include/linux/power/isp1704_charger.h
|
||||
F: drivers/power/supply/bq2415x_charger.c
|
||||
F: drivers/power/supply/bq27xxx_battery.c
|
||||
F: drivers/power/supply/bq27xxx_battery_i2c.c
|
||||
|
|
|
@ -231,8 +231,9 @@ static void cpcap_usb_detect(struct work_struct *work)
|
|||
goto out_err;
|
||||
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
|
||||
CPCAP_BIT_VBUSSTBY_EN,
|
||||
CPCAP_BIT_VBUSSTBY_EN);
|
||||
CPCAP_BIT_VBUSSTBY_EN |
|
||||
CPCAP_BIT_VBUSEN_SPI,
|
||||
CPCAP_BIT_VBUSEN_SPI);
|
||||
if (error)
|
||||
goto out_err;
|
||||
|
||||
|
@ -240,7 +241,8 @@ static void cpcap_usb_detect(struct work_struct *work)
|
|||
}
|
||||
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
|
||||
CPCAP_BIT_VBUSSTBY_EN, 0);
|
||||
CPCAP_BIT_VBUSSTBY_EN |
|
||||
CPCAP_BIT_VBUSEN_SPI, 0);
|
||||
if (error)
|
||||
goto out_err;
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ static int gpio_restart_probe(struct platform_device *pdev)
|
|||
gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL,
|
||||
open_source ? GPIOD_IN : GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio_restart->reset_gpio)) {
|
||||
dev_err(&pdev->dev, "Could net get reset GPIO\n");
|
||||
dev_err(&pdev->dev, "Could not get reset GPIO\n");
|
||||
return PTR_ERR(gpio_restart->reset_gpio);
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,6 @@ void devm_reboot_mode_unregister(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(devm_reboot_mode_unregister);
|
||||
|
||||
MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com");
|
||||
MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("System reboot mode core library");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -742,7 +742,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
|
|||
USB_CH_IP_CUR_LVL_1P5;
|
||||
break;
|
||||
}
|
||||
/* Else, fall through */
|
||||
/* else, fall through */
|
||||
case USB_STAT_HM_IDGND:
|
||||
dev_err(di->dev, "USB Type - Charging not allowed\n");
|
||||
di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05;
|
||||
|
@ -3011,7 +3011,6 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy,
|
|||
static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 bup_vch_range = 0, vbup33_vrtcn = 0;
|
||||
|
||||
/* Setup maximum charger current and voltage for ABB cut2.0 */
|
||||
if (!is_ab8500_1p1_or_earlier(di->parent)) {
|
||||
|
@ -3112,12 +3111,6 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Backup battery voltage and current */
|
||||
if (di->bm->bkup_bat_v > BUP_VCH_SEL_3P1V)
|
||||
bup_vch_range = BUP_VCH_RANGE;
|
||||
if (di->bm->bkup_bat_v == BUP_VCH_SEL_3P3V)
|
||||
vbup33_vrtcn = VBUP33_VRTCN;
|
||||
|
||||
ret = abx500_set_register_interruptible(di->dev,
|
||||
AB8500_RTC,
|
||||
AB8500_RTC_BACKUP_CHG_REG,
|
||||
|
|
|
@ -674,6 +674,7 @@ intr_failed:
|
|||
/*
|
||||
* Some devices have no battery (HDMI sticks) and the axp288 battery's
|
||||
* detection reports one despite it not being there.
|
||||
* Please keep this listed sorted alphabetically.
|
||||
*/
|
||||
static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
|
||||
{
|
||||
|
@ -696,6 +697,12 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
|
|||
DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1.000"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* ECS EF20EA */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Intel Cherry Trail Compute Stick, Windows version */
|
||||
.matches = {
|
||||
|
@ -720,10 +727,11 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
|
|||
},
|
||||
},
|
||||
{
|
||||
/* ECS EF20EA */
|
||||
/* Minix Neo Z83-4 mini PC */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
|
||||
},
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define BQ25890_IRQ_PIN "bq25890_irq"
|
||||
|
||||
#define BQ25890_ID 3
|
||||
#define BQ25895_ID 7
|
||||
#define BQ25896_ID 0
|
||||
|
||||
enum bq25890_fields {
|
||||
|
@ -171,7 +172,7 @@ static const struct reg_field bq25890_reg_fields[] = {
|
|||
[F_WD] = REG_FIELD(0x07, 4, 5),
|
||||
[F_TMR_EN] = REG_FIELD(0x07, 3, 3),
|
||||
[F_CHG_TMR] = REG_FIELD(0x07, 1, 2),
|
||||
[F_JEITA_ISET] = REG_FIELD(0x07, 0, 0),
|
||||
[F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), // reserved on BQ25895
|
||||
/* REG08 */
|
||||
[F_BATCMP] = REG_FIELD(0x08, 5, 7),
|
||||
[F_VCLAMP] = REG_FIELD(0x08, 2, 4),
|
||||
|
@ -180,7 +181,7 @@ static const struct reg_field bq25890_reg_fields[] = {
|
|||
[F_FORCE_ICO] = REG_FIELD(0x09, 7, 7),
|
||||
[F_TMR2X_EN] = REG_FIELD(0x09, 6, 6),
|
||||
[F_BATFET_DIS] = REG_FIELD(0x09, 5, 5),
|
||||
[F_JEITA_VSET] = REG_FIELD(0x09, 4, 4),
|
||||
[F_JEITA_VSET] = REG_FIELD(0x09, 4, 4), // reserved on BQ25895
|
||||
[F_BATFET_DLY] = REG_FIELD(0x09, 3, 3),
|
||||
[F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2),
|
||||
[F_PUMPX_UP] = REG_FIELD(0x09, 1, 1),
|
||||
|
@ -188,7 +189,7 @@ static const struct reg_field bq25890_reg_fields[] = {
|
|||
/* REG0A */
|
||||
[F_BOOSTV] = REG_FIELD(0x0A, 4, 7),
|
||||
/* PFM_OTG_DIS 3 on BQ25896 */
|
||||
[F_BOOSTI] = REG_FIELD(0x0A, 0, 2),
|
||||
[F_BOOSTI] = REG_FIELD(0x0A, 0, 2), // reserved on BQ25895
|
||||
/* REG0B */
|
||||
[F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7),
|
||||
[F_CHG_STAT] = REG_FIELD(0x0B, 3, 4),
|
||||
|
@ -392,6 +393,8 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
if (bq->chip_id == BQ25890_ID)
|
||||
val->strval = "BQ25890";
|
||||
else if (bq->chip_id == BQ25895_ID)
|
||||
val->strval = "BQ25895";
|
||||
else if (bq->chip_id == BQ25896_ID)
|
||||
val->strval = "BQ25896";
|
||||
else
|
||||
|
@ -862,7 +865,8 @@ static int bq25890_probe(struct i2c_client *client,
|
|||
return bq->chip_id;
|
||||
}
|
||||
|
||||
if ((bq->chip_id != BQ25890_ID) && (bq->chip_id != BQ25896_ID)) {
|
||||
if ((bq->chip_id != BQ25890_ID) && (bq->chip_id != BQ25895_ID)
|
||||
&& (bq->chip_id != BQ25896_ID)) {
|
||||
dev_err(dev, "Chip with ID=%d, not supported!\n", bq->chip_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -108,6 +108,9 @@
|
|||
#define CPCAP_REG_CRM_ICHRG_1A596 CPCAP_REG_CRM_ICHRG(0xe)
|
||||
#define CPCAP_REG_CRM_ICHRG_NO_LIMIT CPCAP_REG_CRM_ICHRG(0xf)
|
||||
|
||||
/* CPCAP_REG_VUSBC register bits needed for VBUS */
|
||||
#define CPCAP_BIT_VBUS_SWITCH BIT(0) /* VBUS boost to 5V */
|
||||
|
||||
enum {
|
||||
CPCAP_CHARGER_IIO_BATTDET,
|
||||
CPCAP_CHARGER_IIO_VOLTAGE,
|
||||
|
@ -130,7 +133,8 @@ struct cpcap_charger_ddata {
|
|||
struct power_supply *usb;
|
||||
|
||||
struct phy_companion comparator; /* For USB VBUS */
|
||||
bool vbus_enabled;
|
||||
unsigned int vbus_enabled:1;
|
||||
unsigned int feeding_vbus:1;
|
||||
atomic_t active;
|
||||
|
||||
int status;
|
||||
|
@ -325,7 +329,6 @@ static bool cpcap_charger_vbus_valid(struct cpcap_charger_ddata *ddata)
|
|||
}
|
||||
|
||||
/* VBUS control functions for the USB PHY companion */
|
||||
|
||||
static void cpcap_charger_vbus_work(struct work_struct *work)
|
||||
{
|
||||
struct cpcap_charger_ddata *ddata;
|
||||
|
@ -343,6 +346,7 @@ static void cpcap_charger_vbus_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
ddata->feeding_vbus = true;
|
||||
cpcap_charger_set_cable_path(ddata, false);
|
||||
cpcap_charger_set_inductive_path(ddata, false);
|
||||
|
||||
|
@ -350,12 +354,23 @@ static void cpcap_charger_vbus_work(struct work_struct *work)
|
|||
if (error)
|
||||
goto out_err;
|
||||
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC,
|
||||
CPCAP_BIT_VBUS_SWITCH,
|
||||
CPCAP_BIT_VBUS_SWITCH);
|
||||
if (error)
|
||||
goto out_err;
|
||||
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM,
|
||||
CPCAP_REG_CRM_RVRSMODE,
|
||||
CPCAP_REG_CRM_RVRSMODE);
|
||||
if (error)
|
||||
goto out_err;
|
||||
} else {
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_VUSBC,
|
||||
CPCAP_BIT_VBUS_SWITCH, 0);
|
||||
if (error)
|
||||
goto out_err;
|
||||
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_CRM,
|
||||
CPCAP_REG_CRM_RVRSMODE, 0);
|
||||
if (error)
|
||||
|
@ -363,6 +378,7 @@ static void cpcap_charger_vbus_work(struct work_struct *work)
|
|||
|
||||
cpcap_charger_set_cable_path(ddata, true);
|
||||
cpcap_charger_set_inductive_path(ddata, true);
|
||||
ddata->feeding_vbus = false;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -431,7 +447,8 @@ static void cpcap_usb_detect(struct work_struct *work)
|
|||
if (error)
|
||||
return;
|
||||
|
||||
if (cpcap_charger_vbus_valid(ddata) && s.chrgcurr1) {
|
||||
if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
|
||||
s.chrgcurr1) {
|
||||
int max_current;
|
||||
|
||||
if (cpcap_charger_battery_found(ddata))
|
||||
|
|
|
@ -342,7 +342,7 @@ static inline int isp1704_test_ulpi(struct isp1704_charger *isp)
|
|||
int vendor;
|
||||
int product;
|
||||
int i;
|
||||
int ret = -ENODEV;
|
||||
int ret;
|
||||
|
||||
/* Test ULPI interface */
|
||||
ret = isp1704_write(isp, ULPI_SCRATCH, 0xaa);
|
||||
|
|
|
@ -511,7 +511,7 @@ static inline void max17042_override_por(struct regmap *map,
|
|||
regmap_write(map, reg, value);
|
||||
}
|
||||
|
||||
static inline void max10742_unlock_model(struct max17042_chip *chip)
|
||||
static inline void max17042_unlock_model(struct max17042_chip *chip)
|
||||
{
|
||||
struct regmap *map = chip->regmap;
|
||||
|
||||
|
@ -519,7 +519,7 @@ static inline void max10742_unlock_model(struct max17042_chip *chip)
|
|||
regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
|
||||
}
|
||||
|
||||
static inline void max10742_lock_model(struct max17042_chip *chip)
|
||||
static inline void max17042_lock_model(struct max17042_chip *chip)
|
||||
{
|
||||
struct regmap *map = chip->regmap;
|
||||
|
||||
|
@ -577,7 +577,7 @@ static int max17042_init_model(struct max17042_chip *chip)
|
|||
if (!temp_data)
|
||||
return -ENOMEM;
|
||||
|
||||
max10742_unlock_model(chip);
|
||||
max17042_unlock_model(chip);
|
||||
max17042_write_model_data(chip, MAX17042_MODELChrTbl,
|
||||
table_size);
|
||||
max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
|
||||
|
@ -589,7 +589,7 @@ static int max17042_init_model(struct max17042_chip *chip)
|
|||
temp_data,
|
||||
table_size);
|
||||
|
||||
max10742_lock_model(chip);
|
||||
max17042_lock_model(chip);
|
||||
kfree(temp_data);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -366,3 +366,4 @@ module_platform_driver(max77650_charger_driver);
|
|||
MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:max77650-charger");
|
||||
|
|
|
@ -1051,14 +1051,14 @@ __power_supply_register(struct device *parent,
|
|||
}
|
||||
|
||||
spin_lock_init(&psy->changed_lock);
|
||||
rc = device_init_wakeup(dev, ws);
|
||||
if (rc)
|
||||
goto wakeup_init_failed;
|
||||
|
||||
rc = device_add(dev);
|
||||
if (rc)
|
||||
goto device_add_failed;
|
||||
|
||||
rc = device_init_wakeup(dev, ws);
|
||||
if (rc)
|
||||
goto wakeup_init_failed;
|
||||
|
||||
rc = psy_register_thermal(psy);
|
||||
if (rc)
|
||||
goto register_thermal_failed;
|
||||
|
@ -1101,8 +1101,8 @@ register_cooler_failed:
|
|||
psy_unregister_thermal(psy);
|
||||
register_thermal_failed:
|
||||
device_del(dev);
|
||||
device_add_failed:
|
||||
wakeup_init_failed:
|
||||
device_add_failed:
|
||||
check_supplies_failed:
|
||||
dev_set_name_failed:
|
||||
put_device(dev);
|
||||
|
|
|
@ -284,6 +284,7 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
|
|||
struct device *dev = &psy->dev;
|
||||
struct device *hwmon;
|
||||
int ret, i;
|
||||
const char *name;
|
||||
|
||||
if (!devres_open_group(dev, power_supply_add_hwmon_sysfs,
|
||||
GFP_KERNEL))
|
||||
|
@ -334,7 +335,19 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
|
|||
}
|
||||
}
|
||||
|
||||
hwmon = devm_hwmon_device_register_with_info(dev, psy->desc->name,
|
||||
name = psy->desc->name;
|
||||
if (strchr(name, '-')) {
|
||||
char *new_name;
|
||||
|
||||
new_name = devm_kstrdup(dev, name, GFP_KERNEL);
|
||||
if (!new_name) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
strreplace(new_name, '-', '_');
|
||||
name = new_name;
|
||||
}
|
||||
hwmon = devm_hwmon_device_register_with_info(dev, name,
|
||||
psyhw,
|
||||
&power_supply_hwmon_chip_info,
|
||||
NULL);
|
||||
|
|
|
@ -314,17 +314,22 @@ static int sbs_get_battery_presence_and_health(
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT) {
|
||||
/* Dummy command; if it succeeds, battery is present. */
|
||||
ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
|
||||
if (ret < 0)
|
||||
val->intval = 0; /* battery disconnected */
|
||||
else
|
||||
val->intval = 1; /* battery present */
|
||||
} else { /* POWER_SUPPLY_PROP_HEALTH */
|
||||
/* Dummy command; if it succeeds, battery is present. */
|
||||
ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
|
||||
|
||||
if (ret < 0) { /* battery not present*/
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT) {
|
||||
val->intval = 0;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT)
|
||||
val->intval = 1; /* battery present */
|
||||
else /* POWER_SUPPLY_PROP_HEALTH */
|
||||
/* SBS spec doesn't have a general health command. */
|
||||
val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -620,12 +625,14 @@ static int sbs_get_property(struct power_supply *psy,
|
|||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
if (client->flags & SBS_FLAGS_TI_BQ20Z75)
|
||||
if (chip->flags & SBS_FLAGS_TI_BQ20Z75)
|
||||
ret = sbs_get_ti_battery_presence_and_health(client,
|
||||
psp, val);
|
||||
else
|
||||
ret = sbs_get_battery_presence_and_health(client, psp,
|
||||
val);
|
||||
|
||||
/* this can only be true if no gpio is used */
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT)
|
||||
return 0;
|
||||
break;
|
||||
|
|
|
@ -109,6 +109,9 @@ struct sc27xx_fgu_data {
|
|||
};
|
||||
|
||||
static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity);
|
||||
static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
|
||||
int cap, bool int_mode);
|
||||
static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap);
|
||||
|
||||
static const char * const sc27xx_charger_supply_name[] = {
|
||||
"sc2731_charger",
|
||||
|
@ -326,8 +329,6 @@ static int sc27xx_fgu_set_clbcnt(struct sc27xx_fgu_data *data, int clbcnt)
|
|||
{
|
||||
int ret;
|
||||
|
||||
clbcnt *= SC27XX_FGU_SAMPLE_HZ;
|
||||
|
||||
ret = regmap_update_bits(data->regmap,
|
||||
data->base + SC27XX_FGU_CLBCNT_SETL,
|
||||
SC27XX_FGU_CLBCNT_MASK, clbcnt);
|
||||
|
@ -362,7 +363,6 @@ static int sc27xx_fgu_get_clbcnt(struct sc27xx_fgu_data *data, int *clb_cnt)
|
|||
|
||||
*clb_cnt = ccl & SC27XX_FGU_CLBCNT_MASK;
|
||||
*clb_cnt |= (cch & SC27XX_FGU_CLBCNT_MASK) << SC27XX_FGU_CLBCNT_SHIFT;
|
||||
*clb_cnt /= SC27XX_FGU_SAMPLE_HZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -380,10 +380,10 @@ static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap)
|
|||
|
||||
/*
|
||||
* Convert coulomb counter to delta capacity (mAh), and set multiplier
|
||||
* as 100 to improve the precision.
|
||||
* as 10 to improve the precision.
|
||||
*/
|
||||
temp = DIV_ROUND_CLOSEST(delta_clbcnt, 360);
|
||||
temp = sc27xx_fgu_adc_to_current(data, temp);
|
||||
temp = DIV_ROUND_CLOSEST(delta_clbcnt * 10, 36 * SC27XX_FGU_SAMPLE_HZ);
|
||||
temp = sc27xx_fgu_adc_to_current(data, temp / 1000);
|
||||
|
||||
/*
|
||||
* Convert to capacity percent of the battery total capacity,
|
||||
|
@ -392,6 +392,9 @@ static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap)
|
|||
delta_cap = DIV_ROUND_CLOSEST(temp * 100, data->total_cap);
|
||||
*cap = delta_cap + data->init_cap;
|
||||
|
||||
/* Calibrate the battery capacity in a normal range. */
|
||||
sc27xx_fgu_capacity_calibration(data, *cap, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -587,6 +590,10 @@ static int sc27xx_fgu_get_property(struct power_supply *psy,
|
|||
val->intval = value * 1000;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
|
||||
val->intval = data->total_cap * 1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
|
@ -604,18 +611,26 @@ static int sc27xx_fgu_set_property(struct power_supply *psy,
|
|||
struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy);
|
||||
int ret;
|
||||
|
||||
if (psp != POWER_SUPPLY_PROP_CAPACITY)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ret = sc27xx_fgu_save_last_cap(data, val->intval);
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = sc27xx_fgu_save_last_cap(data, val->intval);
|
||||
if (ret < 0)
|
||||
dev_err(data->dev, "failed to save battery capacity\n");
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CALIBRATE:
|
||||
sc27xx_fgu_adjust_cap(data, val->intval);
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(data->dev, "failed to save battery capacity\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -629,7 +644,8 @@ static void sc27xx_fgu_external_power_changed(struct power_supply *psy)
|
|||
static int sc27xx_fgu_property_is_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
return psp == POWER_SUPPLY_PROP_CAPACITY;
|
||||
return psp == POWER_SUPPLY_PROP_CAPACITY ||
|
||||
psp == POWER_SUPPLY_PROP_CALIBRATE;
|
||||
}
|
||||
|
||||
static enum power_supply_property sc27xx_fgu_props[] = {
|
||||
|
@ -644,6 +660,8 @@ static enum power_supply_property sc27xx_fgu_props[] = {
|
|||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CALIBRATE,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc sc27xx_fgu_desc = {
|
||||
|
@ -659,14 +677,108 @@ static const struct power_supply_desc sc27xx_fgu_desc = {
|
|||
|
||||
static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap)
|
||||
{
|
||||
int ret;
|
||||
|
||||
data->init_cap = cap;
|
||||
data->init_clbcnt = sc27xx_fgu_cap_to_clbcnt(data, data->init_cap);
|
||||
ret = sc27xx_fgu_get_clbcnt(data, &data->init_clbcnt);
|
||||
if (ret)
|
||||
dev_err(data->dev, "failed to get init coulomb counter\n");
|
||||
}
|
||||
|
||||
static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
|
||||
int cap, bool int_mode)
|
||||
{
|
||||
int ret, ocv, chg_sts, adc;
|
||||
|
||||
ret = sc27xx_fgu_get_vbat_ocv(data, &ocv);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "get battery ocv error.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = sc27xx_fgu_get_status(data, &chg_sts);
|
||||
if (ret) {
|
||||
dev_err(data->dev, "get charger status error.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are in charging mode, then we do not need to calibrate the
|
||||
* lower capacity.
|
||||
*/
|
||||
if (chg_sts == POWER_SUPPLY_STATUS_CHARGING)
|
||||
return;
|
||||
|
||||
if ((ocv > data->cap_table[0].ocv && cap < 100) || cap > 100) {
|
||||
/*
|
||||
* If current OCV value is larger than the max OCV value in
|
||||
* OCV table, or the current capacity is larger than 100,
|
||||
* we should force the inititial capacity to 100.
|
||||
*/
|
||||
sc27xx_fgu_adjust_cap(data, 100);
|
||||
} else if (ocv <= data->cap_table[data->table_len - 1].ocv) {
|
||||
/*
|
||||
* If current OCV value is leass than the minimum OCV value in
|
||||
* OCV table, we should force the inititial capacity to 0.
|
||||
*/
|
||||
sc27xx_fgu_adjust_cap(data, 0);
|
||||
} else if ((ocv > data->cap_table[data->table_len - 1].ocv && cap <= 0) ||
|
||||
(ocv > data->min_volt && cap <= data->alarm_cap)) {
|
||||
/*
|
||||
* If current OCV value is not matchable with current capacity,
|
||||
* we should re-calculate current capacity by looking up the
|
||||
* OCV table.
|
||||
*/
|
||||
int cur_cap = power_supply_ocv2cap_simple(data->cap_table,
|
||||
data->table_len, ocv);
|
||||
|
||||
sc27xx_fgu_adjust_cap(data, cur_cap);
|
||||
} else if (ocv <= data->min_volt) {
|
||||
/*
|
||||
* If current OCV value is less than the low alarm voltage, but
|
||||
* current capacity is larger than the alarm capacity, we should
|
||||
* adjust the inititial capacity to alarm capacity.
|
||||
*/
|
||||
if (cap > data->alarm_cap) {
|
||||
sc27xx_fgu_adjust_cap(data, data->alarm_cap);
|
||||
} else {
|
||||
int cur_cap;
|
||||
|
||||
/*
|
||||
* If current capacity is equal with 0 or less than 0
|
||||
* (some error occurs), we should adjust inititial
|
||||
* capacity to the capacity corresponding to current OCV
|
||||
* value.
|
||||
*/
|
||||
cur_cap = power_supply_ocv2cap_simple(data->cap_table,
|
||||
data->table_len,
|
||||
ocv);
|
||||
sc27xx_fgu_adjust_cap(data, cur_cap);
|
||||
}
|
||||
|
||||
if (!int_mode)
|
||||
return;
|
||||
|
||||
/*
|
||||
* After adjusting the battery capacity, we should set the
|
||||
* lowest alarm voltage instead.
|
||||
*/
|
||||
data->min_volt = data->cap_table[data->table_len - 1].ocv;
|
||||
data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table,
|
||||
data->table_len,
|
||||
data->min_volt);
|
||||
|
||||
adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000);
|
||||
regmap_update_bits(data->regmap,
|
||||
data->base + SC27XX_FGU_LOW_OVERLOAD,
|
||||
SC27XX_FGU_LOW_OVERLOAD_MASK, adc);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct sc27xx_fgu_data *data = dev_id;
|
||||
int ret, cap, ocv, adc;
|
||||
int ret, cap;
|
||||
u32 status;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
@ -692,49 +804,7 @@ static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = sc27xx_fgu_get_vbat_ocv(data, &ocv);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If current OCV value is less than the minimum OCV value in OCV table,
|
||||
* which means now battery capacity is 0%, and we should adjust the
|
||||
* inititial capacity to 0.
|
||||
*/
|
||||
if (ocv <= data->cap_table[data->table_len - 1].ocv) {
|
||||
sc27xx_fgu_adjust_cap(data, 0);
|
||||
} else if (ocv <= data->min_volt) {
|
||||
/*
|
||||
* If current OCV value is less than the low alarm voltage, but
|
||||
* current capacity is larger than the alarm capacity, we should
|
||||
* adjust the inititial capacity to alarm capacity.
|
||||
*/
|
||||
if (cap > data->alarm_cap) {
|
||||
sc27xx_fgu_adjust_cap(data, data->alarm_cap);
|
||||
} else if (cap <= 0) {
|
||||
int cur_cap;
|
||||
|
||||
/*
|
||||
* If current capacity is equal with 0 or less than 0
|
||||
* (some error occurs), we should adjust inititial
|
||||
* capacity to the capacity corresponding to current OCV
|
||||
* value.
|
||||
*/
|
||||
cur_cap = power_supply_ocv2cap_simple(data->cap_table,
|
||||
data->table_len,
|
||||
ocv);
|
||||
sc27xx_fgu_adjust_cap(data, cur_cap);
|
||||
}
|
||||
|
||||
/*
|
||||
* After adjusting the battery capacity, we should set the
|
||||
* lowest alarm voltage instead.
|
||||
*/
|
||||
data->min_volt = data->cap_table[data->table_len - 1].ocv;
|
||||
adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000);
|
||||
regmap_update_bits(data->regmap, data->base + SC27XX_FGU_LOW_OVERLOAD,
|
||||
SC27XX_FGU_LOW_OVERLOAD_MASK, adc);
|
||||
}
|
||||
sc27xx_fgu_capacity_calibration(data, cap, true);
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->lock);
|
||||
|
@ -785,7 +855,7 @@ static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity)
|
|||
* Convert current capacity (mAh) to coulomb counter according to the
|
||||
* formula: 1 mAh =3.6 coulomb.
|
||||
*/
|
||||
return DIV_ROUND_CLOSEST(cur_cap * 36 * data->cur_1000ma_adc, 10);
|
||||
return DIV_ROUND_CLOSEST(cur_cap * 36 * data->cur_1000ma_adc * SC27XX_FGU_SAMPLE_HZ, 10);
|
||||
}
|
||||
|
||||
static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data)
|
||||
|
@ -856,6 +926,8 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data)
|
|||
data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table,
|
||||
data->table_len,
|
||||
data->min_volt);
|
||||
if (!data->alarm_cap)
|
||||
data->alarm_cap += 1;
|
||||
|
||||
power_supply_put_battery_info(data->battery, &info);
|
||||
|
||||
|
@ -957,81 +1029,81 @@ disable_fgu:
|
|||
|
||||
static int sc27xx_fgu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct power_supply_config fgu_cfg = { };
|
||||
struct sc27xx_fgu_data *data;
|
||||
int ret, irq;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
data->regmap = dev_get_regmap(dev->parent, NULL);
|
||||
if (!data->regmap) {
|
||||
dev_err(&pdev->dev, "failed to get regmap\n");
|
||||
dev_err(dev, "failed to get regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "reg", &data->base);
|
||||
ret = device_property_read_u32(dev, "reg", &data->base);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to get fgu address\n");
|
||||
dev_err(dev, "failed to get fgu address\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->channel = devm_iio_channel_get(&pdev->dev, "bat-temp");
|
||||
data->channel = devm_iio_channel_get(dev, "bat-temp");
|
||||
if (IS_ERR(data->channel)) {
|
||||
dev_err(&pdev->dev, "failed to get IIO channel\n");
|
||||
dev_err(dev, "failed to get IIO channel\n");
|
||||
return PTR_ERR(data->channel);
|
||||
}
|
||||
|
||||
data->charge_chan = devm_iio_channel_get(&pdev->dev, "charge-vol");
|
||||
data->charge_chan = devm_iio_channel_get(dev, "charge-vol");
|
||||
if (IS_ERR(data->charge_chan)) {
|
||||
dev_err(&pdev->dev, "failed to get charge IIO channel\n");
|
||||
dev_err(dev, "failed to get charge IIO channel\n");
|
||||
return PTR_ERR(data->charge_chan);
|
||||
}
|
||||
|
||||
data->gpiod = devm_gpiod_get(&pdev->dev, "bat-detect", GPIOD_IN);
|
||||
data->gpiod = devm_gpiod_get(dev, "bat-detect", GPIOD_IN);
|
||||
if (IS_ERR(data->gpiod)) {
|
||||
dev_err(&pdev->dev, "failed to get battery detection GPIO\n");
|
||||
dev_err(dev, "failed to get battery detection GPIO\n");
|
||||
return PTR_ERR(data->gpiod);
|
||||
}
|
||||
|
||||
ret = gpiod_get_value_cansleep(data->gpiod);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get gpio state\n");
|
||||
dev_err(dev, "failed to get gpio state\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->bat_present = !!ret;
|
||||
mutex_init(&data->lock);
|
||||
data->dev = &pdev->dev;
|
||||
data->dev = dev;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
fgu_cfg.drv_data = data;
|
||||
fgu_cfg.of_node = np;
|
||||
data->battery = devm_power_supply_register(&pdev->dev, &sc27xx_fgu_desc,
|
||||
data->battery = devm_power_supply_register(dev, &sc27xx_fgu_desc,
|
||||
&fgu_cfg);
|
||||
if (IS_ERR(data->battery)) {
|
||||
dev_err(&pdev->dev, "failed to register power supply\n");
|
||||
dev_err(dev, "failed to register power supply\n");
|
||||
return PTR_ERR(data->battery);
|
||||
}
|
||||
|
||||
ret = sc27xx_fgu_hw_init(data);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize fgu hardware\n");
|
||||
dev_err(dev, "failed to initialize fgu hardware\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action(&pdev->dev, sc27xx_fgu_disable, data);
|
||||
ret = devm_add_action_or_reset(dev, sc27xx_fgu_disable, data);
|
||||
if (ret) {
|
||||
sc27xx_fgu_disable(data);
|
||||
dev_err(&pdev->dev, "failed to add fgu disable action\n");
|
||||
dev_err(dev, "failed to add fgu disable action\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource specified\n");
|
||||
dev_err(dev, "no irq resource specified\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
|
@ -1046,17 +1118,17 @@ static int sc27xx_fgu_probe(struct platform_device *pdev)
|
|||
|
||||
irq = gpiod_to_irq(data->gpiod);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to translate GPIO to IRQ\n");
|
||||
dev_err(dev, "failed to translate GPIO to IRQ\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
sc27xx_fgu_bat_detection,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
pdev->name, data);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
dev_err(dev, "failed to request IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1093,7 +1165,8 @@ static int sc27xx_fgu_suspend(struct device *dev)
|
|||
* If we are charging, then no need to enable the FGU interrupts to
|
||||
* adjust the battery capacity.
|
||||
*/
|
||||
if (status != POWER_SUPPLY_STATUS_NOT_CHARGING)
|
||||
if (status != POWER_SUPPLY_STATUS_NOT_CHARGING &&
|
||||
status != POWER_SUPPLY_STATUS_DISCHARGING)
|
||||
return 0;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_EN,
|
||||
|
|
Loading…
Reference in a new issue