Commit 6b402bdf authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-v4.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull more power-supply updates from Sebastian Reichel:
 "The power-supply subsystem has a few more changes for the v4.12 merge
  window:

   - New battery driver for AXP20X and AXP22X PMICs

   - Improve max17042_battery for usage on x86

   - Misc small cleanups & fixes"

* tag 'for-v4.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (34 commits)
  power: supply: cpcap-charger: Keep trickle charger bits disabled
  power: supply: cpcap-charger: Fix enable for 3.8V charge setting
  power: supply: cpcap-charger: Fix charge voltage configuration
  power: supply: cpcap-charger: Fix charger name
  power: supply: twl4030-charger: make twl4030_bci_property_is_writeable static
  power: supply: sbs-battery: Add alert callback
  mailmap: add Sebastian Reichel
  power: supply: avoid unused twl4030-madc.h
  power: supply: sbs-battery: Correct supply status with current draw
  power: supply: sbs-battery: Don't ignore the first external power change
  power: supply: pda_power: move from timer to delayed_work
  power: supply: max17042_battery: Add support for the SCOPE property
  power: supply: max17042_battery: Add support for the CHARGE_NOW property
  power: supply: max17042_battery: Add support for the CHARGE_FULL_DESIGN property
  power: supply: max17042_battery: mAh readings depend on r_sns value
  power: supply: max17042_battery: Add support for the VOLT_MIN property
  power: supply: max17042_battery: Add support for the TECHNOLOGY attribute
  power: supply: max17042_battery: Add external_power_changed callback
  power: supply: max17042_battery: Add support for the STATUS property
  power: supply: max17042_battery: Add default platform_data fallback data
  ...
parents 6a776e47 35f4f99c
......@@ -146,6 +146,8 @@ Santosh Shilimkar <ssantosh@kernel.org>
Santosh Shilimkar <santosh.shilimkar@oracle.org>
Sascha Hauer <s.hauer@pengutronix.de>
S.Çağlar Onur <caglar@pardus.org.tr>
Sebastian Reichel <sre@kernel.org> <sre@debian.org>
Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
......
AXP20x and AXP22x battery power supply
Required Properties:
- compatible, one of:
"x-powers,axp209-battery-power-supply"
"x-powers,axp221-battery-power-supply"
This node is a subnode of the axp20x/axp22x PMIC.
The AXP20X and AXP22X can read the battery voltage, charge and discharge
currents of the battery by reading ADC channels from the AXP20X/AXP22X
ADC.
Example:
&axp209 {
battery_power_supply: battery-power-supply {
compatible = "x-powers,axp209-battery-power-supply";
}
};
......@@ -238,6 +238,26 @@ config CHARGER_AXP20X
This driver can also be built as a module. If so, the module will be
called axp20x_ac_power.
config BATTERY_AXP20X
tristate "X-Powers AXP20X battery driver"
depends on MFD_AXP20X
depends on AXP20X_ADC
depends on IIO
help
Say Y here to enable support for X-Powers AXP20X PMICs' battery power
supply.
This driver can also be built as a module. If so, the module will be
called axp20x_battery.
config AXP20X_POWER
tristate "AXP20x power supply driver"
depends on MFD_AXP20X
depends on IIO
help
This driver provides support for the power supply features of
AXP20x PMIC.
config AXP288_CHARGER
tristate "X-Powers AXP288 Charger"
depends on MFD_AXP20X && EXTCON_AXP288
......@@ -541,11 +561,4 @@ config CHARGER_RT9455
help
Say Y to enable support for Richtek RT9455 battery charger.
config AXP20X_POWER
tristate "AXP20x power supply driver"
depends on MFD_AXP20X
help
This driver provides support for the power supply features of
AXP20x PMIC.
endif # POWER_SUPPLY
......@@ -18,6 +18,7 @@ obj-$(CONFIG_TEST_POWER) += test_power.o
obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
obj-$(CONFIG_BATTERY_AXP20X) += axp20x_battery.o
obj-$(CONFIG_CHARGER_AXP20X) += axp20x_ac_power.o
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
......
......@@ -3238,7 +3238,7 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
BUS_PP_PRECHG_CURRENT_MASK, 0);
if (ret) {
dev_err(di->dev,
"failed to setup usb power path prechage current\n");
"failed to setup usb power path precharge current\n");
goto out;
}
}
......
This diff is collapsed.
......@@ -533,6 +533,9 @@ static int bq24190_register_reset(struct bq24190_dev_info *bdi)
int ret, limit = 100;
u8 v;
if (device_property_read_bool(bdi->dev, "disable-reset"))
return 0;
/* Reset the registers */
ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
BQ24190_REG_POC_RESET_MASK,
......@@ -659,22 +662,25 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
v = bdi->f_reg;
mutex_unlock(&bdi->f_reg_lock);
if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
/*
* This could be over-current or over-voltage but there's
* no way to tell which. Return 'OVERVOLTAGE' since there
* isn't an 'OVERCURRENT' value defined that we can return
* even if it was over-current.
*/
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
} else {
v &= BQ24190_REG_F_CHRG_FAULT_MASK;
v >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
switch (v) {
case 0x0: /* Normal */
health = POWER_SUPPLY_HEALTH_GOOD;
if (v & BQ24190_REG_F_NTC_FAULT_MASK) {
switch (v >> BQ24190_REG_F_NTC_FAULT_SHIFT & 0x7) {
case 0x1: /* TS1 Cold */
case 0x3: /* TS2 Cold */
case 0x5: /* Both Cold */
health = POWER_SUPPLY_HEALTH_COLD;
break;
case 0x2: /* TS1 Hot */
case 0x4: /* TS2 Hot */
case 0x6: /* Both Hot */
health = POWER_SUPPLY_HEALTH_OVERHEAT;
break;
default:
health = POWER_SUPPLY_HEALTH_UNKNOWN;
}
} else if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
} else if (v & BQ24190_REG_F_CHRG_FAULT_MASK) {
switch (v >> BQ24190_REG_F_CHRG_FAULT_SHIFT & 0x3) {
case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */
/*
* This could be over-voltage or under-voltage
......@@ -691,9 +697,19 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
case 0x3: /* Charge Safety Timer Expiration */
health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
break;
default:
health = POWER_SUPPLY_HEALTH_UNKNOWN;
default: /* prevent compiler warning */
health = -1;
}
} else if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
/*
* This could be over-current or over-voltage but there's
* no way to tell which. Return 'OVERVOLTAGE' since there
* isn't an 'OVERCURRENT' value defined that we can return
* even if it was over-current.
*/
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
} else {
health = POWER_SUPPLY_HEALTH_GOOD;
}
val->intval = health;
......@@ -704,19 +720,59 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
static int bq24190_charger_get_online(struct bq24190_dev_info *bdi,
union power_supply_propval *val)
{
u8 v;
u8 pg_stat, batfet_disable;
int ret;
ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
BQ24190_REG_SS_PG_STAT_MASK,
BQ24190_REG_SS_PG_STAT_SHIFT, &v);
BQ24190_REG_SS_PG_STAT_SHIFT, &pg_stat);
if (ret < 0)
return ret;
ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
BQ24190_REG_MOC_BATFET_DISABLE_MASK,
BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable);
if (ret < 0)
return ret;
val->intval = v;
val->intval = pg_stat && !batfet_disable;
return 0;
}
static int bq24190_battery_set_online(struct bq24190_dev_info *bdi,
const union power_supply_propval *val);
static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
union power_supply_propval *val);
static int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi,
union power_supply_propval *val);
static int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi,
const union power_supply_propval *val);
static int bq24190_charger_set_online(struct bq24190_dev_info *bdi,
const union power_supply_propval *val)
{
return bq24190_battery_set_online(bdi, val);
}
static int bq24190_charger_get_status(struct bq24190_dev_info *bdi,
union power_supply_propval *val)
{
return bq24190_battery_get_status(bdi, val);
}
static int bq24190_charger_get_temp_alert_max(struct bq24190_dev_info *bdi,
union power_supply_propval *val)
{
return bq24190_battery_get_temp_alert_max(bdi, val);
}
static int bq24190_charger_set_temp_alert_max(struct bq24190_dev_info *bdi,
const union power_supply_propval *val)
{
return bq24190_battery_set_temp_alert_max(bdi, val);
}
static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
union power_supply_propval *val)
{
......@@ -831,6 +887,12 @@ static int bq24190_charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_ONLINE:
ret = bq24190_charger_get_online(bdi, val);
break;
case POWER_SUPPLY_PROP_STATUS:
ret = bq24190_charger_get_status(bdi, val);
break;
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = bq24190_charger_get_temp_alert_max(bdi, val);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
ret = bq24190_charger_get_current(bdi, val);
break;
......@@ -879,6 +941,12 @@ static int bq24190_charger_set_property(struct power_supply *psy,
return ret;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
ret = bq24190_charger_set_online(bdi, val);
break;
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = bq24190_charger_set_temp_alert_max(bdi, val);
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
ret = bq24190_charger_set_charge_type(bdi, val);
break;
......@@ -904,6 +972,8 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy,
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
case POWER_SUPPLY_PROP_CHARGE_TYPE:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
......@@ -920,6 +990,8 @@ static enum power_supply_property bq24190_charger_properties[] = {
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
......@@ -1093,6 +1165,7 @@ static int bq24190_battery_get_property(struct power_supply *psy,
struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
int ret;
dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
dev_dbg(bdi->dev, "prop: %d\n", psp);
ret = pm_runtime_get_sync(bdi->dev);
......@@ -1138,6 +1211,7 @@ static int bq24190_battery_set_property(struct power_supply *psy,
struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
int ret;
dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
dev_dbg(bdi->dev, "prop: %d\n", psp);
ret = pm_runtime_get_sync(bdi->dev);
......@@ -1266,9 +1340,9 @@ static void bq24190_check_status(struct bq24190_dev_info *bdi)
bdi->ss_reg = ss_reg;
}
if (alert_charger)
if (alert_charger || alert_battery)
power_supply_changed(bdi->charger);
if (alert_battery)
if (alert_battery && bdi->battery)
power_supply_changed(bdi->battery);
dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg);
......@@ -1473,6 +1547,9 @@ static int bq24190_probe(struct i2c_client *client,
goto out_pmrt;
}
/* the battery class is deprecated and will be removed. */
/* in the interim, this property hides it. */
if (!device_property_read_bool(dev, "omit-battery-class")) {
battery_cfg.drv_data = bdi;
bdi->battery = power_supply_register(dev, &bq24190_battery_desc,
&battery_cfg);
......@@ -1481,11 +1558,12 @@ static int bq24190_probe(struct i2c_client *client,
ret = PTR_ERR(bdi->battery);
goto out_charger;
}
}
ret = bq24190_sysfs_create_group(bdi);
if (ret) {
dev_err(dev, "Can't create sysfs entries\n");
goto out_battery;
goto out_charger;
}
bdi->initialized = true;
......@@ -1523,10 +1601,9 @@ static int bq24190_probe(struct i2c_client *client,
out_sysfs:
bq24190_sysfs_remove_group(bdi);
out_battery:
power_supply_unregister(bdi->battery);
out_charger:
if (!IS_ERR_OR_NULL(bdi->battery))
power_supply_unregister(bdi->battery);
power_supply_unregister(bdi->charger);
out_pmrt:
......@@ -1549,6 +1626,7 @@ static int bq24190_remove(struct i2c_client *client)
bq24190_register_reset(bdi);
bq24190_sysfs_remove_group(bdi);
if (bdi->battery)
power_supply_unregister(bdi->battery);
power_supply_unregister(bdi->charger);
if (error >= 0)
......@@ -1636,6 +1714,7 @@ static __maybe_unused int bq24190_pm_resume(struct device *dev)
/* Things may have changed while suspended so alert upper layer */
power_supply_changed(bdi->charger);
if (bdi->battery)
power_supply_changed(bdi->battery);
return 0;
......
......@@ -76,7 +76,7 @@
#define CPCAP_REG_CRM_VCHRG_4V30 CPCAP_REG_CRM_VCHRG(0x8)
#define CPCAP_REG_CRM_VCHRG_4V32 CPCAP_REG_CRM_VCHRG(0x9)
#define CPCAP_REG_CRM_VCHRG_4V34 CPCAP_REG_CRM_VCHRG(0xa)
#define CPCAP_REG_CRM_VCHRG_4V36 CPCAP_REG_CRM_VCHRG(0xb)
#define CPCAP_REG_CRM_VCHRG_4V35 CPCAP_REG_CRM_VCHRG(0xb)
#define CPCAP_REG_CRM_VCHRG_4V38 CPCAP_REG_CRM_VCHRG(0xc)
#define CPCAP_REG_CRM_VCHRG_4V40 CPCAP_REG_CRM_VCHRG(0xd)
#define CPCAP_REG_CRM_VCHRG_4V42 CPCAP_REG_CRM_VCHRG(0xe)
......@@ -262,7 +262,7 @@ static int cpcap_charger_set_state(struct cpcap_charger_ddata *ddata,
bool enable;
int error;
enable = max_voltage && (charge_current || trickle_current);
enable = (charge_current || trickle_current);
dev_dbg(ddata->dev, "%s enable: %i\n", __func__, enable);
if (!enable) {
......@@ -433,9 +433,8 @@ static void cpcap_usb_detect(struct work_struct *work)
max_current = CPCAP_REG_CRM_ICHRG_0A528;
error = cpcap_charger_set_state(ddata,
CPCAP_REG_CRM_VCHRG_4V20,
max_current,
CPCAP_REG_CRM_TR_0A72);
CPCAP_REG_CRM_VCHRG_4V35,
max_current, 0);
if (error)
goto out_err;
} else {
......@@ -566,7 +565,7 @@ static int cpcap_charger_init_iio(struct cpcap_charger_ddata *ddata)
}
static const struct power_supply_desc cpcap_charger_usb_desc = {
.name = "cpcap_usb",
.name = "usb",
.type = POWER_SUPPLY_TYPE_USB,
.properties = cpcap_charger_props,
.num_properties = ARRAY_SIZE(cpcap_charger_props),
......
......@@ -383,8 +383,7 @@ static int gab_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int gab_suspend(struct device *dev)
static int __maybe_unused gab_suspend(struct device *dev)
{
struct gab *adc_bat = dev_get_drvdata(dev);
......@@ -393,7 +392,7 @@ static int gab_suspend(struct device *dev)
return 0;
}
static int gab_resume(struct device *dev)
static int __maybe_unused gab_resume(struct device *dev)
{
struct gab *adc_bat = dev_get_drvdata(dev);
struct gab_platform_data *pdata = adc_bat->pdata;
......@@ -407,20 +406,12 @@ static int gab_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops gab_pm_ops = {
.suspend = gab_suspend,
.resume = gab_resume,
};
#define GAB_PM_OPS (&gab_pm_ops)
#else
#define GAB_PM_OPS (NULL)
#endif
static SIMPLE_DEV_PM_OPS(gab_pm_ops, gab_suspend, gab_resume);
static struct platform_driver gab_driver = {
.driver = {
.name = "generic-adc-battery",
.pm = GAB_PM_OPS
.pm = &gab_pm_ops,
},
.probe = gab_probe,
.remove = gab_remove,
......
......@@ -418,6 +418,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct isp1704_charger_data), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto fail0;
}
pdata->enable_gpio = gpio;
dev_info(&pdev->dev, "init gpio %d\n", pdata->enable_gpio);
......
This diff is collapsed.
......@@ -30,9 +30,9 @@ static inline unsigned int get_irq_flags(struct resource *res)
static struct device *dev;
static struct pda_power_pdata *pdata;
static struct resource *ac_irq, *usb_irq;
static struct timer_list charger_timer;
static struct timer_list supply_timer;
static struct timer_list polling_timer;
static struct delayed_work charger_work;
static struct delayed_work polling_work;
static struct delayed_work supply_work;
static int polling;
static struct power_supply *pda_psy_ac, *pda_psy_usb;
......@@ -140,7 +140,7 @@ static void update_charger(void)
}
}
static void supply_timer_func(unsigned long unused)
static void supply_work_func(struct work_struct *work)
{
if (ac_status == PDA_PSY_TO_CHANGE) {
ac_status = new_ac_status;
......@@ -161,11 +161,12 @@ static void psy_changed(void)
* Okay, charger set. Now wait a bit before notifying supplicants,
* charge power should stabilize.
*/
mod_timer(&supply_timer,
jiffies + msecs_to_jiffies(pdata->wait_for_charger));
cancel_delayed_work(&supply_work);
schedule_delayed_work(&supply_work,
msecs_to_jiffies(pdata->wait_for_charger));
}
static void charger_timer_func(unsigned long unused)
static void charger_work_func(struct work_struct *work)
{
update_status();
psy_changed();
......@@ -184,13 +185,14 @@ static irqreturn_t power_changed_isr(int irq, void *power_supply)
* Wait a bit before reading ac/usb line status and setting charger,
* because ac/usb status readings may lag from irq.
*/
mod_timer(&charger_timer,
jiffies + msecs_to_jiffies(pdata->wait_for_status));
cancel_delayed_work(&charger_work);
schedule_delayed_work(&charger_work,
msecs_to_jiffies(pdata->wait_for_status));
return IRQ_HANDLED;
}
static void polling_timer_func(unsigned long unused)
static void polling_work_func(struct work_struct *work)
{
int changed = 0;
......@@ -211,8 +213,9 @@ static void polling_timer_func(unsigned long unused)
if (changed)
psy_changed();
mod_timer(&polling_timer,
jiffies + msecs_to_jiffies(pdata->polling_interval));
cancel_delayed_work(&polling_work);
schedule_delayed_work(&polling_work,
msecs_to_jiffies(pdata->polling_interval));
}
#if IS_ENABLED(CONFIG_USB_PHY)
......@@ -250,8 +253,9 @@ static int otg_handle_notification(struct notifier_block *nb,
* Wait a bit before reading ac/usb line status and setting charger,
* because ac/usb status readings may lag from irq.
*/
mod_timer(&charger_timer,
jiffies + msecs_to_jiffies(pdata->wait_for_status));
cancel_delayed_work(&charger_work);
schedule_delayed_work(&charger_work,
msecs_to_jiffies(pdata->wait_for_status));
return NOTIFY_OK;
}
......@@ -300,8 +304,8 @@ static int pda_power_probe(struct platform_device *pdev)
if (!pdata->ac_max_uA)
pdata->ac_max_uA = 500000;
setup_timer(&charger_timer, charger_timer_func, 0);
setup_timer(&supply_timer, supply_timer_func, 0);
INIT_DELAYED_WORK(&charger_work, charger_work_func);
INIT_DELAYED_WORK(&supply_work, supply_work_func);
ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
......@@ -385,9 +389,10 @@ static int pda_power_probe(struct platform_device *pdev)
if (polling) {
dev_dbg(dev, "will poll for status\n");
setup_timer(&polling_timer, polling_timer_func, 0);
mod_timer(&polling_timer,
jiffies + msecs_to_jiffies(pdata->polling_interval));
INIT_DELAYED_WORK(&polling_work, polling_work_func);
cancel_delayed_work(&polling_work);
schedule_delayed_work(&polling_work,
msecs_to_jiffies(pdata->polling_interval));
}
if (ac_irq || usb_irq)
......@@ -433,9 +438,9 @@ static int pda_power_remove(struct platform_device *pdev)
free_irq(ac_irq->start, pda_psy_ac);
if (polling)
del_timer_sync(&polling_timer);
del_timer_sync(&charger_timer);
del_timer_sync(&supply_timer);
cancel_delayed_work_sync(&polling_work);
cancel_delayed_work_sync(&charger_work);
cancel_delayed_work_sync(&supply_work);
if (pdata->is_usb_online)
power_supply_unregister(pda_psy_usb);
......
......@@ -280,13 +280,19 @@ static inline int power_supply_check_supplies(struct power_supply *psy)
}
#endif
static int __power_supply_am_i_supplied(struct device *dev, void *data)
struct psy_am_i_supplied_data {
struct power_supply *psy;
unsigned int count;
};
static int __power_supply_am_i_supplied(struct device *dev, void *_data)
{
union power_supply_propval ret = {0,};
struct power_supply *psy = data;
struct power_supply *epsy = dev_get_drvdata(dev);
struct psy_am_i_supplied_data *data = _data;
if (__power_supply_is_supplied_by(epsy, psy))
data->count++;
if (__power_supply_is_supplied_by(epsy, data->psy))
if (!epsy->desc->get_property(epsy, POWER_SUPPLY_PROP_ONLINE,
&ret))
return ret.intval;
......@@ -296,12 +302,16 @@ static int __power_supply_am_i_supplied(struct device *dev, void *data)
int power_supply_am_i_supplied(struct power_supply *psy)
{
struct psy_am_i_supplied_data data = { psy, 0 };
int error;
error = class_for_each_device(power_supply_class, NULL, psy,
error = class_for_each_device(power_supply_class, NULL, &data,
__power_supply_am_i_supplied);
dev_dbg(&psy->dev, "%s %d\n", __func__, error);
dev_dbg(&psy->dev, "%s count %u err %d\n", __func__, data.count, error);
if (data.count == 0)
return -ENODEV;
return error;
}
......
......@@ -23,7 +23,6 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/i2c/twl4030-madc.h>
#include <linux/iio/consumer.h>
#include <linux/of.h>
......
......@@ -171,7 +171,6 @@ struct sbs_info {
u32 i2c_retry_count;
u32 poll_retry_count;
struct delayed_work work;
int ignore_changes;
};
static char model_name[I2C_SMBUS_BLOCK_MAX + 1];
......@@ -296,6 +295,31 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address,
return 0;
}
static int sbs_status_correct(struct i2c_client *client, int *intval)
{
int ret;
ret = sbs_read_word_data(client, sbs_data[REG_CURRENT].addr);
if (ret < 0)
return ret;
ret = (s16)ret;
/* Not drawing current means full (cannot be not charging) */
if (ret == 0)
*intval = POWER_SUPPLY_STATUS_FULL;
if (*intval == POWER_SUPPLY_STATUS_FULL) {
/* Drawing or providing current when full */
if (ret > 0)
*intval = POWER_SUPPLY_STATUS_CHARGING;
else if (ret < 0)
*intval = POWER_SUPPLY_STATUS_DISCHARGING;
}
return 0;
}
static int sbs_get_battery_presence_and_health(
struct i2c_client *client, enum power_supply_property psp,
union power_supply_propval *val)
......@@ -402,6 +426,8 @@ static int sbs_get_battery_property(struct i2c_client *client,
else
val->intval = POWER_SUPPLY_STATUS_CHARGING;
sbs_status_correct(client, &val->intval);
if (chip->poll_time == 0)
chip->last_state = val->intval;
else if (chip->last_state != val->intval) {
......@@ -675,30 +701,34 @@ static int sbs_get_property(struct power_supply *psy,
return 0;
}
static irqreturn_t sbs_irq(int irq, void *devid)
static void sbs_supply_changed(struct sbs_info *chip)
{
struct sbs_info *chip = devid;
struct power_supply *battery = chip->power_supply;
int ret;
ret = gpiod_get_value_cansleep(chip->gpio_detect);
if (ret < 0)
return ret;
return;
chip->is_present = ret;
power_supply_changed(battery);
}
static irqreturn_t sbs_irq(int irq, void *devid)
{
sbs_supply_changed(devid);
return IRQ_HANDLED;
}
static void sbs_alert(struct i2c_client *client, enum i2c_alert_protocol prot,
unsigned int data)
{
sbs_supply_changed(i2c_get_clientdata(client));
}
static void sbs_external_power_changed(struct power_supply *psy)
{
struct sbs_info *chip = power_supply_get_drvdata(psy);
if (chip->ignore_changes > 0) {
chip->ignore_changes--;
return;
}
/* cancel outstanding work */
cancel_delayed_work_sync(&chip->work);
......@@ -727,6 +757,8 @@ static void sbs_delayed_work(struct work_struct *work)
else
ret = POWER_SUPPLY_STATUS_CHARGING;
sbs_status_correct(chip->client, &ret);
if (chip->last_state != ret) {
chip->poll_time = 0;
power_supply_changed(chip->power_supply);
......@@ -775,10 +807,6 @@ static int sbs_probe(struct i2c_client *client,
chip->enable_detection = false;
psy_cfg.of_node = client->dev.of_node;
psy_cfg.drv_data = chip;
/* ignore first notification of external change, it is generated
* from the power_supply_register call back
*/
chip->ignore_changes = 1;
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
/* use pdata if available, fall back to DT properties,
......@@ -820,7 +848,7 @@ static int sbs_probe(struct i2c_client *client,
}
rc = devm_request_threaded_irq(&client->dev, irq, NULL, sbs_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(&client->dev), chip);
if (rc) {
dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
......@@ -917,6 +945,7 @@ MODULE_DEVICE_TABLE(of, sbs_dt_ids);
static struct i2c_driver sbs_battery_driver = {
.probe = sbs_probe,
.remove = sbs_remove,
.alert = sbs_alert,
.id_table = sbs_id,
.driver = {
.name = "sbs-battery",
......
......@@ -205,35 +205,6 @@ static int twl4030bci_read_adc_val(u8 reg)
return temp | val;
}
/*
* Check if Battery Pack was present
*/
static int twl4030_is_battery_present(struct twl4030_bci *bci)
{
int ret;
u8 val = 0;
/* Battery presence in Main charge? */
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMFSTS3);
if (ret)
return ret;
if (val & TWL4030_BATSTSMCHG)
return 0;
/*
* OK, It could be that bootloader did not enable main charger,
* pre-charge is h/w auto. So, Battery presence in Pre-charge?
*/
ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &val,
TWL4030_BCIMFSTS1);
if (ret)
return ret;
if (val & TWL4030_BATSTSPCHG)
return 0;
return -ENODEV;
}
/*
* TI provided formulas:
* CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85
......@@ -922,6 +893,28 @@ static int twl4030_bci_get_property(struct power_supply *psy,
twl4030_bci_state_to_status(state) !=
POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
val->intval = -1;
if (psy->desc->type != POWER_SUPPLY_TYPE_USB) {
if (!bci->ac_is_active)
val->intval = bci->ac_cur;
} else {
if (bci->ac_is_active)
val->intval = bci->usb_cur_target;
}
if (val->intval < 0) {
u8 bcictl1;
val->intval = twl4030bci_read_adc_val(TWL4030_BCIIREF1);
if (val->intval < 0)
return val->intval;
ret = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1);
if (ret < 0)
return ret;
val->intval = regval2ua(val->intval, bcictl1 &
TWL4030_CGAIN);
}
break;
default:
return -EINVAL;
}
......@@ -929,11 +922,44 @@ static int twl4030_bci_get_property(struct power_supply *psy,
return 0;
}
static int twl4030_bci_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct twl4030_bci *bci = dev_get_drvdata(psy->dev.parent);
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
if (psy->desc->type == POWER_SUPPLY_TYPE_USB)
bci->usb_cur_target = val->intval;
else
bci->ac_cur = val->intval;
twl4030_charger_update_current(bci);
break;
default:
return -EINVAL;
}
return 0;
}
static int twl4030_bci_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return true;
default:
return false;
}
}
static enum power_supply_property twl4030_charger_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
};
#ifdef CONFIG_OF
......@@ -970,6 +996,8 @@ static const struct power_supply_desc twl4030_bci_ac_desc = {
.properties = twl4030_charger_props,
.num_properties = ARRAY_SIZE(twl4030_charger_props),
.get_property = twl4030_bci_get_property,
.set_property = twl4030_bci_set_property,
.property_is_writeable = twl4030_bci_property_is_writeable,
};
static const struct power_supply_desc twl4030_bci_usb_desc = {
......@@ -978,6 +1006,8 @@ static const struct power_supply_desc twl4030_bci_usb_desc = {
.properties = twl4030_charger_props,
.num_properties = ARRAY_SIZE(twl4030_charger_props),
.get_property = twl4030_bci_get_property,
.set_property = twl4030_bci_set_property,
.property_is_writeable = twl4030_bci_property_is_writeable,
};
static int twl4030_bci_probe(struct platform_device *pdev)
......@@ -1009,13 +1039,6 @@ static int twl4030_bci_probe(struct platform_device *pdev)
bci->irq_chg = platform_get_irq(pdev, 0);
bci->irq_bci = platform_get_irq(pdev, 1);
/* Only proceed further *IF* battery is physically present */
ret = twl4030_is_battery_present(bci);
if (ret) {
dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret);
return ret;
}
platform_set_drvdata(pdev, bci);
bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc,
......
......@@ -17,7 +17,6 @@
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/i2c/twl4030-madc.h>
#include <linux/power/twl4030_madc_battery.h>
#include <linux/iio/consumer.h>
......
......@@ -24,8 +24,15 @@
#define __MAX17042_BATTERY_H_
#define MAX17042_STATUS_BattAbsent (1 << 3)
#define MAX17042_BATTERY_FULL (100)
#define MAX17042_BATTERY_FULL (95) /* Recommend. FullSOCThr value */
#define MAX17042_DEFAULT_SNS_RESISTOR (10000)
#define MAX17042_DEFAULT_VMIN (3000)
#define MAX17042_DEFAULT_VMAX (4500) /* LiHV cell max */
#define MAX17042_DEFAULT_TEMP_MIN (0) /* For sys without temp sensor */
#define MAX17042_DEFAULT_TEMP_MAX (700) /* 70 degrees Celcius */
/* Consider RepCap which is less then 10 units below FullCAP full */
#define MAX17042_FULL_THRESHOLD 10
#define MAX17042_CHARACTERIZATION_DATA_SIZE 48
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment