Commit 8eb48fc7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset updates from Sebastian Reichel:
 "Power-supply core:

   - Introduce "Bypass" charging type used by USB PPS standard

   - Refactor power_supply_set_input_current_limit_from_supplier()

   - Add fwnode support to power_supply_get_battery_info()

  Drivers:

   - ab8500: continue migrating towards using standard core APIs

   - axp288 fuel-gauge: refactor driver to be fully resource managed

   - battery-samsung-sdi: new in-kernel provider for (constant) Samsung
     battery info

   - bq24190: disable boost regulator on shutdown

   - bq24190: add support for battery-info on ACPI based systems

   - bq25890: prepare driver for usage on ACPI based systems

   - bq25890: add boost regulator support

   - cpcap-battery: add NVMEM based battery detection support

   - injoinic ip5xxx: new driver for power bank IC

   - upi ug3105: new battery driver

   - misc small improvements and fixes"

* tag 'for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (94 commits)
  power: ab8500_chargalg: Use CLOCK_MONOTONIC
  power: supply: Add a driver for Injoinic power bank ICs
  dt-bindings: trivial-devices: Add Injoinic power bank ICs
  dt-bindings: vendor-prefixes: Add Injoinic
  power: supply: ab8500: Remove unused variable
  power: supply: da9150-fg: Remove unnecessary print function dev_err()
  power: supply: ab8500: fix a handful of spelling mistakes
  power: supply: ab8500_fg: Account for line impedance
  dt-bindings: power: supply: ab8500_fg: Add line impedance
  power: supply: axp20x_usb_power: fix platform_get_irq.cocci warnings
  power: supply: axp20x_ac_power: fix platform_get_irq.cocci warning
  power: supply: wm8350-power: Add missing free in free_charger_irq
  power: supply: wm8350-power: Handle error for wm8350_register_irq
  power: supply: Static data for Samsung batteries
  power: supply: ab8500_fg: Use VBAT-to-Ri if possible
  power: supply: Support VBAT-to-Ri lookup tables
  power: supply: ab8500: Standardize BTI resistance
  power: supply: ab8500: Standardize alert mode charging
  power: supply: ab8500: Standardize maintenance charging
  power: supply: bq24190_charger: Delay applying charge_type changes when OTG 5V Vbus boost is on
  ...
parents 148a6504 c22fca40
......@@ -380,13 +380,17 @@ Description:
algorithm to adjust the charge rate dynamically, without
any user configuration required. "Custom" means that the charger
uses the charge_control_* properties as configuration for some
different algorithm.
different algorithm. "Long Life" means the charger reduces its
charging rate in order to prolong the battery health. "Bypass"
means the charger bypasses the charging path around the
integrated converter allowing for a "smart" wall adaptor to
perform the power conversion externally.
Access: Read, Write
Valid values:
"Unknown", "N/A", "Trickle", "Fast", "Standard",
"Adaptive", "Custom"
"Adaptive", "Custom", "Long Life", "Bypass"
What: /sys/class/power_supply/<supply_name>/charge_term_current
Date: July 2014
......
......@@ -25,6 +25,11 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle
deprecated: true
line-impedance-micro-ohms:
description: The line impedance between the battery and the
AB8500 inputs, to compensate for this when determining internal
resistance.
interrupts:
maxItems: 5
......
......@@ -143,6 +143,14 @@ properties:
- infineon,xdpe12254
# Infineon Multi-phase Digital VR Controller xdpe12284
- infineon,xdpe12284
# Injoinic IP5108 2.0A Power Bank IC with I2C
- injoinic,ip5108
# Injoinic IP5109 2.1A Power Bank IC with I2C
- injoinic,ip5109
# Injoinic IP5207 1.2A Power Bank IC with I2C
- injoinic,ip5207
# Injoinic IP5209 2.4A Power Bank IC with I2C
- injoinic,ip5209
# Inspur Power System power supply unit version 1
- inspur,ipsps1
# Intersil ISL29028 Ambient Light and Proximity Sensor
......
......@@ -571,6 +571,8 @@ patternProperties:
description: InfoVision Optoelectronics Kunshan Co. Ltd.
"^ingenic,.*":
description: Ingenic Semiconductor
"^injoinic,.*":
description: Injoinic Technology Corp.
"^innolux,.*":
description: Innolux Corporation
"^inside-secure,.*":
......
......@@ -9537,6 +9537,11 @@ F: include/linux/mfd/ingenic-tcu.h
F: sound/soc/codecs/jz47*
F: sound/soc/jz4740/
INJOINIC IP5xxx POWER BANK IC DRIVER
M: Samuel Holland <samuel@sholland.org>
S: Maintained
F: drivers/power/supply/ip5xxx_power.c
INOTIFY
M: Jan Kara <jack@suse.cz>
R: Amir Goldstein <amir73il@gmail.com>
......
......@@ -61,6 +61,8 @@ config EXTCON_INTEL_INT3496
config EXTCON_INTEL_CHT_WC
tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver"
depends on INTEL_SOC_PMIC_CHTWC
depends on USB_SUPPORT
select USB_ROLE_SWITCH
help
Say Y here to enable extcon support for charger detection / control
on the Intel Cherrytrail Whiskey Cove PMIC.
......
......@@ -14,8 +14,12 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/usb/role.h>
#include "extcon-intel.h"
......@@ -101,8 +105,13 @@ struct cht_wc_extcon_data {
struct device *dev;
struct regmap *regmap;
struct extcon_dev *edev;
struct usb_role_switch *role_sw;
struct regulator *vbus_boost;
struct power_supply *psy;
enum power_supply_usb_type usb_type;
unsigned int previous_cable;
bool usb_host;
bool vbus_boost_enabled;
};
static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
......@@ -112,13 +121,21 @@ static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
return INTEL_USB_ID_GND;
case CHT_WC_PWRSRC_RID_FLOAT:
return INTEL_USB_ID_FLOAT;
case CHT_WC_PWRSRC_RID_ACA:
default:
/*
* Once we have IIO support for the GPADC we should read
* the USBID GPADC channel here and determine ACA role
* based on that.
* According to the spec. we should read the USB-ID pin ADC value here
* to determine the resistance of the used pull-down resister and then
* return RID_A / RID_B / RID_C based on this. But all "Accessory
* Charger Adapter"s (ACAs) which users can actually buy always use
* a combination of a charging port with one or more USB-A ports, so
* they should always use a resistor indicating RID_A. But the spec
* is hard to read / badly-worded so some of them actually indicate
* they are a RID_B ACA evnen though they clearly are a RID_A ACA.
* To workaround this simply always return INTEL_USB_RID_A, which
* matches all the ACAs which users can actually buy.
*/
case CHT_WC_PWRSRC_RID_ACA:
return INTEL_USB_RID_A;
default:
return INTEL_USB_ID_FLOAT;
}
}
......@@ -147,14 +164,15 @@ static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
} while (time_before(jiffies, timeout));
if (status != CHT_WC_USBSRC_STS_SUCCESS) {
if (ignore_errors)
return EXTCON_CHG_USB_SDP; /* Save fallback */
if (!ignore_errors) {
if (status == CHT_WC_USBSRC_STS_FAIL)
dev_warn(ext->dev, "Could not detect charger type\n");
else
dev_warn(ext->dev, "Timeout detecting charger type\n");
return EXTCON_CHG_USB_SDP; /* Save fallback */
}
/* Safe fallback */
usbsrc = CHT_WC_USBSRC_TYPE_SDP << CHT_WC_USBSRC_TYPE_SHIFT;
}
usbsrc = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;
......@@ -163,18 +181,23 @@ static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
dev_warn(ext->dev,
"Unhandled charger type %d, defaulting to SDP\n",
ret);
ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP;
return EXTCON_CHG_USB_SDP;
case CHT_WC_USBSRC_TYPE_SDP:
case CHT_WC_USBSRC_TYPE_FLOATING:
case CHT_WC_USBSRC_TYPE_OTHER:
ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP;
return EXTCON_CHG_USB_SDP;
case CHT_WC_USBSRC_TYPE_CDP:
ext->usb_type = POWER_SUPPLY_USB_TYPE_CDP;
return EXTCON_CHG_USB_CDP;
case CHT_WC_USBSRC_TYPE_DCP:
case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
ext->usb_type = POWER_SUPPLY_USB_TYPE_DCP;
return EXTCON_CHG_USB_DCP;
case CHT_WC_USBSRC_TYPE_ACA:
ext->usb_type = POWER_SUPPLY_USB_TYPE_ACA;
return EXTCON_CHG_USB_ACA;
}
}
......@@ -216,6 +239,18 @@ static void cht_wc_extcon_set_otgmode(struct cht_wc_extcon_data *ext,
CHT_WC_CHGRCTRL1_OTGMODE, val);
if (ret)
dev_err(ext->dev, "Error updating CHGRCTRL1 reg: %d\n", ret);
if (ext->vbus_boost && ext->vbus_boost_enabled != enable) {
if (enable)
ret = regulator_enable(ext->vbus_boost);
else
ret = regulator_disable(ext->vbus_boost);
if (ret)
dev_err(ext->dev, "Error updating Vbus boost regulator: %d\n", ret);
else
ext->vbus_boost_enabled = enable;
}
}
static void cht_wc_extcon_enable_charging(struct cht_wc_extcon_data *ext,
......@@ -245,6 +280,9 @@ static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext)
unsigned int cable = EXTCON_NONE;
/* Ignore errors in host mode, as the 5v boost converter is on then */
bool ignore_get_charger_errors = ext->usb_host;
enum usb_role role;
ext->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
if (ret) {
......@@ -288,6 +326,21 @@ static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext)
ext->usb_host = ((id == INTEL_USB_ID_GND) || (id == INTEL_USB_RID_A));
extcon_set_state_sync(ext->edev, EXTCON_USB_HOST, ext->usb_host);
if (ext->usb_host)
role = USB_ROLE_HOST;
else if (pwrsrc_sts & CHT_WC_PWRSRC_VBUS)
role = USB_ROLE_DEVICE;
else
role = USB_ROLE_NONE;
/* Note: this is a no-op when ext->role_sw is NULL */
ret = usb_role_switch_set_role(ext->role_sw, role);
if (ret)
dev_err(ext->dev, "Error setting USB-role: %d\n", ret);
if (ext->psy)
power_supply_changed(ext->psy);
}
static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
......@@ -333,6 +386,114 @@ static int cht_wc_extcon_sw_control(struct cht_wc_extcon_data *ext, bool enable)
return ret;
}
static int cht_wc_extcon_find_role_sw(struct cht_wc_extcon_data *ext)
{
const struct software_node *swnode;
struct fwnode_handle *fwnode;
swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
if (!swnode)
return -EPROBE_DEFER;
fwnode = software_node_fwnode(swnode);
ext->role_sw = usb_role_switch_find_by_fwnode(fwnode);
fwnode_handle_put(fwnode);
return ext->role_sw ? 0 : -EPROBE_DEFER;
}
static void cht_wc_extcon_put_role_sw(void *data)
{
struct cht_wc_extcon_data *ext = data;
usb_role_switch_put(ext->role_sw);
}
/* Some boards require controlling the role-sw and Vbus based on the id-pin */
static int cht_wc_extcon_get_role_sw_and_regulator(struct cht_wc_extcon_data *ext)
{
int ret;
ret = cht_wc_extcon_find_role_sw(ext);
if (ret)
return ret;
ret = devm_add_action_or_reset(ext->dev, cht_wc_extcon_put_role_sw, ext);
if (ret)
return ret;
/*
* On x86/ACPI platforms the regulator <-> consumer link is provided
* by platform_data passed to the regulator driver. This means that
* this info is not available before the regulator driver has bound.
* Use devm_regulator_get_optional() to avoid getting a dummy
* regulator and wait for the regulator to show up if necessary.
*/
ext->vbus_boost = devm_regulator_get_optional(ext->dev, "vbus");
if (IS_ERR(ext->vbus_boost)) {
ret = PTR_ERR(ext->vbus_boost);
if (ret == -ENODEV)
ret = -EPROBE_DEFER;
return dev_err_probe(ext->dev, ret, "getting Vbus regulator");
}
return 0;
}
static int cht_wc_extcon_psy_get_prop(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct cht_wc_extcon_data *ext = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_USB_TYPE:
val->intval = ext->usb_type;
break;
case POWER_SUPPLY_PROP_ONLINE:
val->intval = ext->usb_type ? 1 : 0;
break;
default:
return -EINVAL;
}
return 0;
}
static const enum power_supply_usb_type cht_wc_extcon_psy_usb_types[] = {
POWER_SUPPLY_USB_TYPE_SDP,
POWER_SUPPLY_USB_TYPE_CDP,
POWER_SUPPLY_USB_TYPE_DCP,
POWER_SUPPLY_USB_TYPE_ACA,
POWER_SUPPLY_USB_TYPE_UNKNOWN,
};
static const enum power_supply_property cht_wc_extcon_psy_props[] = {
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_ONLINE,
};
static const struct power_supply_desc cht_wc_extcon_psy_desc = {
.name = "cht_wcove_pwrsrc",
.type = POWER_SUPPLY_TYPE_USB,
.usb_types = cht_wc_extcon_psy_usb_types,
.num_usb_types = ARRAY_SIZE(cht_wc_extcon_psy_usb_types),
.properties = cht_wc_extcon_psy_props,
.num_properties = ARRAY_SIZE(cht_wc_extcon_psy_props),
.get_property = cht_wc_extcon_psy_get_prop,
};
static int cht_wc_extcon_register_psy(struct cht_wc_extcon_data *ext)
{
struct power_supply_config psy_cfg = { .drv_data = ext };
ext->psy = devm_power_supply_register(ext->dev,
&cht_wc_extcon_psy_desc,
&psy_cfg);
return PTR_ERR_OR_ZERO(ext->psy);
}
static int cht_wc_extcon_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
......@@ -358,6 +519,8 @@ static int cht_wc_extcon_probe(struct platform_device *pdev)
if (IS_ERR(ext->edev))
return PTR_ERR(ext->edev);
switch (pmic->cht_wc_model) {
case INTEL_CHT_WC_GPD_WIN_POCKET:
/*
* When a host-cable is detected the BIOS enables an external 5v boost
* converter to power connected devices there are 2 problems with this:
......@@ -372,6 +535,31 @@ static int cht_wc_extcon_probe(struct platform_device *pdev)
* external 5v boost converter off and leave it off entirely.
*/
cht_wc_extcon_set_5v_boost(ext, false);
break;
case INTEL_CHT_WC_LENOVO_YOGABOOK1:
/* Do this first, as it may very well return -EPROBE_DEFER. */
ret = cht_wc_extcon_get_role_sw_and_regulator(ext);
if (ret)
return ret;
/*
* The bq25890 used here relies on this driver's BC-1.2 charger
* detection, and the bq25890 driver expect this info to be
* available through a parent power_supply class device which
* models the detected charger (idem to how the Type-C TCPM code
* registers a power_supply classdev for the connected charger).
*/
ret = cht_wc_extcon_register_psy(ext);
if (ret)
return ret;
break;
case INTEL_CHT_WC_XIAOMI_MIPAD2:
ret = cht_wc_extcon_get_role_sw_and_regulator(ext);
if (ret)
return ret;
break;
default:
break;
}
/* Enable sw control */
ret = cht_wc_extcon_sw_control(ext, true);
......
......@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power/bq24190_charger.h>
#include <linux/power/bq25890_charger.h>
#include <linux/slab.h>
#define CHT_WC_I2C_CTRL 0x5e24
......@@ -270,6 +271,7 @@ static const struct irq_chip cht_wc_i2c_irq_chip = {
.name = "cht_wc_ext_chrg_irq_chip",
};
/********** GPD Win / Pocket charger IC settings **********/
static const char * const bq24190_suppliers[] = {
"tcpm-source-psy-i2c-fusb302" };
......@@ -304,17 +306,92 @@ static struct bq24190_platform_data bq24190_pdata = {
.regulator_init_data = &bq24190_vbus_init_data,
};
static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
struct cht_wc_i2c_adap *adap;
struct i2c_board_info board_info = {
static struct i2c_board_info gpd_win_board_info = {
.type = "bq24190",
.addr = 0x6b,
.dev_name = "bq24190",
.swnode = &bq24190_node,
.platform_data = &bq24190_pdata,
};
};
/********** Xiaomi Mi Pad 2 charger IC settings **********/
static struct regulator_consumer_supply bq2589x_vbus_consumer = {
.supply = "vbus",
.dev_name = "cht_wcove_pwrsrc",
};
static const struct regulator_init_data bq2589x_vbus_init_data = {
.constraints = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.consumer_supplies = &bq2589x_vbus_consumer,
.num_consumer_supplies = 1,
};
static struct bq25890_platform_data bq2589x_pdata = {
.regulator_init_data = &bq2589x_vbus_init_data,
};
static const struct property_entry xiaomi_mipad2_props[] = {
PROPERTY_ENTRY_BOOL("linux,skip-reset"),
PROPERTY_ENTRY_BOOL("linux,read-back-settings"),
{ }
};
static const struct software_node xiaomi_mipad2_node = {
.properties = xiaomi_mipad2_props,
};
static struct i2c_board_info xiaomi_mipad2_board_info = {
.type = "bq25890",
.addr = 0x6a,
.dev_name = "bq25890",
.swnode = &xiaomi_mipad2_node,
.platform_data = &bq2589x_pdata,
};
/********** Lenovo Yogabook YB1-X90F/-X91F/-X91L charger settings **********/
static const char * const lenovo_yb1_bq25892_suppliers[] = { "cht_wcove_pwrsrc" };
static const struct property_entry lenovo_yb1_bq25892_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from",
lenovo_yb1_bq25892_suppliers),
PROPERTY_ENTRY_U32("linux,pump-express-vbus-max", 12000000),
PROPERTY_ENTRY_BOOL("linux,skip-reset"),
/*
* The firmware sets everything to the defaults, which leads to a
* somewhat low charge-current of 2048mA and worse to a battery-voltage
* of 4.2V instead of 4.35V (when booted without a charger connected).
* Use our own values instead of "linux,read-back-settings" to fix this.
*/
PROPERTY_ENTRY_U32("ti,charge-current", 4224000),
PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
PROPERTY_ENTRY_U32("ti,termination-current", 256000),
PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3500000),
PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
PROPERTY_ENTRY_U32("ti,boost-max-current", 1400000),
PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"),
{ }
};
static const struct software_node lenovo_yb1_bq25892_node = {
.properties = lenovo_yb1_bq25892_props,
};
static struct i2c_board_info lenovo_yogabook1_board_info = {
.type = "bq25892",
.addr = 0x6b,
.dev_name = "bq25892",
.swnode = &lenovo_yb1_bq25892_node,
.platform_data = &bq2589x_pdata,
};
static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
struct i2c_board_info *board_info = NULL;
struct cht_wc_i2c_adap *adap;
int ret, reg, irq;
irq = platform_get_irq(pdev, 0);
......@@ -379,17 +456,24 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
if (ret)
goto remove_irq_domain;
/*
* Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger,
* connected to this i2c bus, and a max17047 fuel-gauge and a fusb302
* USB Type-C controller connected to another i2c bus. In this setup
* the max17047 and fusb302 devices are enumerated through an INT33FE
* ACPI device. If this device is present register an i2c-client for
* the TI bq24292i charger.
*/
if (acpi_dev_present("INT33FE", NULL, -1)) {
board_info.irq = adap->client_irq;
adap->client = i2c_new_client_device(&adap->adapter, &board_info);
switch (pmic->cht_wc_model) {
case INTEL_CHT_WC_GPD_WIN_POCKET:
board_info = &gpd_win_board_info;
break;
case INTEL_CHT_WC_XIAOMI_MIPAD2:
board_info = &xiaomi_mipad2_board_info;
break;
case INTEL_CHT_WC_LENOVO_YOGABOOK1:
board_info = &lenovo_yogabook1_board_info;
break;
default:
dev_warn(&pdev->dev, "Unknown model, not instantiating charger device\n");
break;
}
if (board_info) {
board_info->irq = adap->client_irq;
adap->client = i2c_new_client_device(&adap->adapter, board_info);
if (IS_ERR(adap->client)) {
ret = PTR_ERR(adap->client);
goto del_adapter;
......
......@@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
......@@ -134,9 +135,44 @@ static const struct regmap_irq_chip cht_wc_regmap_irq_chip = {
.num_regs = 1,
};
static const struct dmi_system_id cht_wc_model_dmi_ids[] = {
{
/* GPD win / GPD pocket mini laptops */
.driver_data = (void *)(long)INTEL_CHT_WC_GPD_WIN_POCKET,
/*
* This DMI match may not seem unique, but it is. In the 67000+
* DMI decode dumps from linux-hardware.org only 116 have
* board_vendor set to "AMI Corporation" and of those 116 only
* the GPD win's and pocket's board_name is "Default string".
*/
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
},
}, {
/* Xiaomi Mi Pad 2 */
.driver_data = (void *)(long)INTEL_CHT_WC_XIAOMI_MIPAD2,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
},
}, {
/* Lenovo Yoga Book X90F / X91F / X91L */
.driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1,
.matches = {
/* Non exact match to match all versions */
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"),
},
},
{ }
};
static int cht_wc_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
const struct dmi_system_id *id;
struct intel_soc_pmic *pmic;
acpi_status status;
unsigned long long hrv;
......@@ -160,6 +196,10 @@ static int cht_wc_probe(struct i2c_client *client)
if (!pmic)
return -ENOMEM;
id = dmi_first_match(cht_wc_model_dmi_ids);
if (id)
pmic->cht_wc_model = (long)id->driver_data;
pmic->irq = client->irq;
pmic->dev = dev;
i2c_set_clientdata(client, pmic);
......
......@@ -107,8 +107,8 @@ static int gemini_poweroff_probe(struct platform_device *pdev)
return PTR_ERR(gpw->base);
irq = platform_get_irq(pdev, 0);
if (!irq)
return -EINVAL;
if (irq < 0)
return irq;
gpw->dev = dev;
......
......@@ -51,6 +51,14 @@ config GENERIC_ADC_BATTERY
Say Y here to enable support for the generic battery driver
which uses IIO framework to read adc.
config IP5XXX_POWER
tristate "Injoinic IP5xxx power bank IC driver"
depends on I2C
select REGMAP_I2C
help
Say Y to include support for Injoinic IP5xxx power bank ICs,
which include a battery charger and a boost converter.
config MAX8925_POWER
tristate "MAX8925 battery charger support"
depends on MFD_MAX8925
......@@ -181,6 +189,12 @@ config BATTERY_OLPC
help
Say Y to enable support for the battery on the OLPC laptop.
config BATTERY_SAMSUNG_SDI
bool "Samsung SDI batteries"
help
Say Y to enable support for Samsung SDI battery data.
These batteries are used in Samsung mobile phones.
config BATTERY_TOSA
tristate "Sharp SL-6000 (tosa) battery"
depends on MACH_TOSA && MFD_TC6393XB && TOUCHSCREEN_WM97XX
......@@ -351,14 +365,14 @@ config AXP20X_POWER
config AXP288_CHARGER
tristate "X-Powers AXP288 Charger"
depends on MFD_AXP20X && EXTCON_AXP288 && IOSF_MBI
depends on MFD_AXP20X && EXTCON_AXP288 && IOSF_MBI && ACPI
help
Say yes here to have support X-Power AXP288 power management IC (PMIC)
integrated charger.
config AXP288_FUEL_GAUGE
tristate "X-Powers AXP288 Fuel Gauge"
depends on MFD_AXP20X && IIO && IOSF_MBI
depends on MFD_AXP20X && IIO && IOSF_MBI && ACPI
help
Say yes here to have support for X-Power power management IC (PMIC)
Fuel Gauge. The device provides battery statistics and status
......@@ -728,6 +742,8 @@ config BATTERY_GAUGE_LTC2941
config AB8500_BM
bool "AB8500 Battery Management Driver"
depends on AB8500_CORE && AB8500_GPADC && (IIO = y) && OF
select THERMAL
select THERMAL_OF
help
Say Y to include support for AB8500 battery management.
......@@ -866,4 +882,19 @@ config CHARGER_SURFACE
Microsoft Surface devices, i.e. Surface Pro 7, Surface Laptop 3,
Surface Book 3, and Surface Laptop Go.
config BATTERY_UG3105
tristate "uPI uG3105 battery monitor driver"
depends on I2C
help
Battery monitor driver for the uPI uG3105 battery monitor.
Note the uG3105 is not a full-featured autonomous fuel-gauge. Instead
it is expected to be use in combination with some always on
microcontroller reading its coulomb-counter before it can wrap
(it must be read every 400 seconds!).
Since Linux does not monitor coulomb-counter changes while the
device is off or suspended, the functionality of this driver is
limited to reporting capacity only.
endif # POWER_SUPPLY
......@@ -12,6 +12,7 @@ obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
obj-$(CONFIG_PDA_POWER) += pda_power.o
obj-$(CONFIG_APM_POWER) += apm_power.o
obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o
obj-$(CONFIG_IP5XXX_POWER) += ip5xxx_power.o
obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
......@@ -34,6 +35,7 @@ obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
obj-$(CONFIG_BATTERY_LEGO_EV3) += lego_ev3_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_SAMSUNG_SDI) += samsung-sdi-battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
obj-$(CONFIG_BATTERY_INGENIC) += ingenic-battery.o
......@@ -105,3 +107,4 @@ obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o
obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o
obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o
......@@ -260,30 +260,6 @@ enum bup_vch_sel {
#define BUS_PP_PRECHG_CURRENT_MASK 0x0E
#define BUS_POWER_PATH_PRECHG_ENA 0x01
/*
* ADC for the battery thermistor.
* When using the AB8500_ADC_THERM_BATCTRL the battery ID resistor is combined
* with a NTC resistor to both identify the battery and to measure its
* temperature. Different phone manufactures uses different techniques to both
* identify the battery and to read its temperature.
*/
enum ab8500_adc_therm {
AB8500_ADC_THERM_BATCTRL,
AB8500_ADC_THERM_BATTEMP,
};
/**
* struct ab8500_res_to_temp - defines one point in a temp to res curve. To
* be used in battery packs that combines the identification resistor with a
* NTC resistor.
* @temp: battery pack temperature in Celsius
* @resist: NTC resistor net total resistance
*/
struct ab8500_res_to_temp {
int temp;
int resist;
};
/* Forward declaration */
struct ab8500_fg;
......@@ -351,36 +327,6 @@ struct ab8500_maxim_parameters {
int charger_curr_step_ua;
};
/**
* struct ab8500_battery_type - different batteries supported
* @resis_high: battery upper resistance limit
* @resis_low: battery lower resistance limit
* @maint_a_cur_lvl: charger current in maintenance A state in mA
* @maint_a_vol_lvl: charger voltage in maintenance A state in mV
* @maint_a_chg_timer_h: charge time in maintenance A state
* @maint_b_cur_lvl: charger current in maintenance B state in mA
* @maint_b_vol_lvl: charger voltage in maintenance B state in mV
* @maint_b_chg_timer_h: charge time in maintenance B state
* @low_high_cur_lvl: charger current in temp low/high state in mA
* @low_high_vol_lvl: charger voltage in temp low/high state in mV'
* @n_r_t_tbl_elements: number of elements in r_to_t_tbl
* @r_to_t_tbl: table containing resistance to temp points
*/
struct ab8500_battery_type {
int resis_high;
int resis_low;
int maint_a_cur_lvl;
int maint_a_vol_lvl;
int maint_a_chg_timer_h;
int maint_b_cur_lvl;
int maint_b_vol_lvl;
int maint_b_chg_timer_h;
int low_high_cur_lvl;
int low_high_vol_lvl;
int n_temp_tbl_elements;
const struct ab8500_res_to_temp *r_to_t_tbl;
};
/**
* struct ab8500_bm_capacity_levels - ab8500 capacity level data
* @critical: critical capacity level in percent
......@@ -421,9 +367,7 @@ struct ab8500_bm_charger_parameters {
* @usb_safety_tmr_h safety timer for usb charger
* @bkup_bat_v voltage which we charge the backup battery with
* @bkup_bat_i current which we charge the backup battery with
* @no_maintenance indicates that maintenance charging is disabled
* @capacity_scaling indicates whether capacity scaling is to be used
* @ab8500_adc_therm placement of thermistor, batctrl or battemp adc
* @chg_unknown_bat flag to enable charging of unknown batteries
* @enable_overshoot flag to enable VBAT overshoot control
* @auto_trig flag to enable auto adc trigger
......@@ -431,10 +375,8 @@ struct ab8500_bm_charger_parameters {
* @interval_charging charge alg cycle period time when charging (sec)
* @interval_not_charging charge alg cycle period time when not charging (sec)
* @temp_hysteresis temperature hysteresis
* @gnd_lift_resistance Battery ground to phone ground resistance (mOhm)
* @maxi maximization parameters
* @cap_levels capacity in percent for the different capacity levels
* @bat_type table of supported battery types
* @chg_params charger parameters
* @fg_params fuel gauge parameters
*/
......@@ -447,41 +389,20 @@ struct ab8500_bm_data {
int usb_safety_tmr_h;
int bkup_bat_v;
int bkup_bat_i;
bool no_maintenance;
bool capacity_scaling;
bool chg_unknown_bat;
bool enable_overshoot;
bool auto_trig;
enum ab8500_adc_therm adc_therm;
int fg_res;
int interval_charging;
int interval_not_charging;
int temp_hysteresis;
int gnd_lift_resistance;
const struct ab8500_maxim_parameters *maxi;
const struct ab8500_bm_capacity_levels *cap_levels;
struct ab8500_battery_type *bat_type;
const struct ab8500_bm_charger_parameters *chg_params;
const struct ab8500_fg_parameters *fg_params;
};
enum {
NTC_EXTERNAL = 0,
NTC_INTERNAL,
};
/**
* struct res_to_temp - defines one point in a temp to res curve. To
* be used in battery packs that combines the identification resistor with a
* NTC resistor.
* @temp: battery pack temperature in Celsius
* @resist: NTC resistor net total resistance
*/
struct res_to_temp {
int temp;
int resist;
};
/* Forward declaration */
struct ab8500_fg;
......
......@@ -43,28 +43,6 @@ static struct power_supply_battery_ocv_table ocv_cap_tbl[] = {
{ .ocv = 3094000, .capacity = 0},
};
/*
* Note that the res_to_temp table must be strictly sorted by falling
* resistance values to work.
*/
static const struct ab8500_res_to_temp temp_tbl[] = {
{-5, 214834},
{ 0, 162943},
{ 5, 124820},
{10, 96520},
{15, 75306},
{20, 59254},
{25, 47000},
{30, 37566},
{35, 30245},
{40, 24520},
{45, 20010},
{50, 16432},
{55, 13576},
{60, 11280},
{65, 9425},
};
/*
* Note that the batres_vs_temp table must be strictly sorted by falling
* temperature values to work. Factory resistance is 300 mOhm and the
......@@ -80,20 +58,19 @@ static struct power_supply_resistance_temp_table temp_to_batres_tbl_thermistor[]
{ .temp = -20, .resistance = 198 /* 595 mOhm */ },
};
/* Default battery type for reference designs is the unknown type */
static struct ab8500_battery_type bat_type_thermistor_unknown = {
.resis_high = 0,
.resis_low = 0,
.maint_a_cur_lvl = 400,
.maint_a_vol_lvl = 4050,
.maint_a_chg_timer_h = 60,
.maint_b_cur_lvl = 400,
.maint_b_vol_lvl = 4000,
.maint_b_chg_timer_h = 200,
.low_high_cur_lvl = 300,
.low_high_vol_lvl = 4000,
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
.r_to_t_tbl = temp_tbl,
static struct power_supply_maintenance_charge_table ab8500_maint_charg_table[] = {
{
/* Maintenance charging phase A, 60 hours */
.charge_current_max_ua = 400000,
.charge_voltage_max_uv = 4050000,
.charge_safety_timer_minutes = 60*60,
},
{
/* Maintenance charging phase B, 200 hours */
.charge_current_max_ua = 400000,
.charge_voltage_max_uv = 4000000,
.charge_safety_timer_minutes = 200*60,
}
};
static const struct ab8500_bm_capacity_levels cap_levels = {
......@@ -148,17 +125,13 @@ struct ab8500_bm_data ab8500_bm_data = {
.usb_safety_tmr_h = 4,
.bkup_bat_v = BUP_VCH_SEL_2P6V,
.bkup_bat_i = BUP_ICH_SEL_150UA,
.no_maintenance = false,
.capacity_scaling = false,
.adc_therm = AB8500_ADC_THERM_BATCTRL,
.chg_unknown_bat = false,
.enable_overshoot = false,
.fg_res = 100,
.cap_levels = &cap_levels,
.bat_type = &bat_type_thermistor_unknown,
.interval_charging = 5,
.interval_not_charging = 120,
.gnd_lift_resistance = 34,
.maxi = &ab8500_maxi_params,
.chg_params = &chg,
.fg_params = &fg,
......@@ -188,13 +161,11 @@ int ab8500_bm_of_probe(struct power_supply *psy,
* fall back to safe defaults.
*/
if ((bi->voltage_min_design_uv < 0) ||
(bi->voltage_max_design_uv < 0) ||
(bi->overvoltage_limit_uv < 0)) {
(bi->voltage_max_design_uv < 0)) {
/* Nominal voltage is 3.7V for unknown batteries */
bi->voltage_min_design_uv = 3700000;
bi->voltage_max_design_uv = 3700000;
/* Termination voltage (overcharge limit) 4.05V */
bi->overvoltage_limit_uv = 4050000;
/* Termination voltage 4.05V */
bi->voltage_max_design_uv = 4050000;
}
if (bi->constant_charge_current_max_ua < 0)
......@@ -207,6 +178,24 @@ int ab8500_bm_of_probe(struct power_supply *psy,
/* Charging stops when we drop below this current */
bi->charge_term_current_ua = 200000;
if (!bi->maintenance_charge || !bi->maintenance_charge_size) {
bi->maintenance_charge = ab8500_maint_charg_table;
bi->maintenance_charge_size = ARRAY_SIZE(ab8500_maint_charg_table);
}
if (bi->alert_low_temp_charge_current_ua < 0 ||
bi->alert_low_temp_charge_voltage_uv < 0)
{
bi->alert_low_temp_charge_current_ua = 300000;
bi->alert_low_temp_charge_voltage_uv = 4000000;
}
if (bi->alert_high_temp_charge_current_ua < 0 ||
bi->alert_high_temp_charge_voltage_uv < 0)
{
bi->alert_high_temp_charge_current_ua = 300000;
bi->alert_high_temp_charge_voltage_uv = 4000000;
}
/*
* Internal resistance and factory resistance are tightly coupled
* so both MUST be defined or we fall back to defaults.
......@@ -218,6 +207,13 @@ int ab8500_bm_of_probe(struct power_supply *psy,
bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor);
}
/* The default battery is emulated by a resistor at 7K */
if (bi->bti_resistance_ohm < 0 ||
bi->bti_resistance_tolerance < 0) {
bi->bti_resistance_ohm = 7000;
bi->bti_resistance_tolerance = 20;
}
if (!bi->ocv_table[0]) {
/* Default capacity table at say 25 degrees Celsius */
bi->ocv_temp[0] = 25;
......
This diff is collapsed.
This diff is collapsed.
......@@ -163,7 +163,7 @@ enum ab8500_usb_state {
#define USB_CH_IP_CUR_LVL_1P4 1400000
#define USB_CH_IP_CUR_LVL_1P5 1500000
#define VBAT_TRESH_IP_CUR_RED 3800
#define VBAT_TRESH_IP_CUR_RED 3800000
#define to_ab8500_charger_usb_device_info(x) container_of((x), \
struct ab8500_charger, usb_chg)
......@@ -171,7 +171,7 @@ enum ab8500_usb_state {
struct ab8500_charger, ac_chg)
/**
* struct ab8500_charger_interrupts - ab8500 interupts
* struct ab8500_charger_interrupts - ab8500 interrupts
* @name: name of the interrupt
* @isr function pointer to the isr
*/
......@@ -1083,7 +1083,7 @@ static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr_ua)
/**
* ab8500_charger_get_usb_cur() - get usb current
* @di: pointer to the ab8500_charger structre
* @di: pointer to the ab8500_charger structure
*
* The usb stack provides the maximum current that can be drawn from
* the standard usb host. This will be in uA.
......@@ -1920,7 +1920,11 @@ static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data)
di = to_ab8500_charger_usb_device_info(usb_chg);
/* For all psy where the driver name appears in any supplied_to */
/*
* For all psy where the driver name appears in any supplied_to
* in practice what we will find will always be "ab8500_fg" as
* the fuel gauge is responsible of keeping track of VBAT.
*/
j = match_string(supplicants, ext->num_supplicants, psy->desc->name);
if (j < 0)
return 0;
......@@ -1937,7 +1941,10 @@ static int ab8500_charger_get_ext_psy_data(struct device *dev, void *data)
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
switch (ext->desc->type) {
case POWER_SUPPLY_TYPE_BATTERY:
di->vbat = ret.intval / 1000;
/* This will always be "ab8500_fg" */
dev_dbg(di->dev, "get VBAT from %s\n",
dev_name(&ext->dev));
di->vbat = ret.intval;
break;
default:
break;
......@@ -1966,7 +1973,7 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work)
struct ab8500_charger, check_vbat_work.work);
class_for_each_device(power_supply_class, NULL,
di->usb_chg.psy, ab8500_charger_get_ext_psy_data);
&di->usb_chg, ab8500_charger_get_ext_psy_data);
/* First run old_vbat is 0. */
if (di->old_vbat == 0)
......@@ -1991,8 +1998,8 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work)
* No need to check the battery voltage every second when not close to
* the threshold.
*/
if (di->vbat < (VBAT_TRESH_IP_CUR_RED + 100) &&
(di->vbat > (VBAT_TRESH_IP_CUR_RED - 100)))
if (di->vbat < (VBAT_TRESH_IP_CUR_RED + 100000) &&
(di->vbat > (VBAT_TRESH_IP_CUR_RED - 100000)))
t = 1;
queue_delayed_work(di->charger_wq, &di->check_vbat_work, t * HZ);
......@@ -3443,6 +3450,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->parent = dev_get_drvdata(pdev->dev.parent);
/* Get ADC channels */
if (!is_ab8505(di->parent)) {
di->adc_main_charger_v = devm_iio_channel_get(dev, "main_charger_v");
if (IS_ERR(di->adc_main_charger_v)) {
ret = dev_err_probe(dev, PTR_ERR(di->adc_main_charger_v),
......@@ -3455,6 +3463,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
"failed to get ADC main charger current\n");
return ret;
}
}
di->adc_vbus_v = devm_iio_channel_get(dev, "vbus_v");
if (IS_ERR(di->adc_vbus_v)) {
ret = dev_err_probe(dev, PTR_ERR(di->adc_vbus_v),
......
This diff is collapsed.
......@@ -377,11 +377,9 @@ static int axp20x_ac_power_probe(struct platform_device *pdev)
/* Request irqs after registering, as irqs may trigger immediately */
for (i = 0; i < axp_data->num_irq_names; i++) {
irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]);
if (irq < 0) {
dev_err(&pdev->dev, "No IRQ for %s: %d\n",
axp_data->irq_names[i], irq);
if (irq < 0)
return irq;
}
power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i],
axp20x_ac_power_irq, 0,
......
......@@ -186,7 +186,6 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
union power_supply_propval *val)
{
struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
struct iio_channel *chan;
int ret = 0, reg, val1;
switch (psp) {
......@@ -266,12 +265,12 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
if (ret)
return ret;
if (reg & AXP20X_PWR_STATUS_BAT_CHARGING)
chan = axp20x_batt->batt_chrg_i;
else
chan = axp20x_batt->batt_dischrg_i;
ret = iio_read_channel_processed(chan, &val->intval);
if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) {
ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval);
} else {
ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i, &val1);
val->intval = -val1;
}
if (ret)
return ret;
......
......@@ -637,11 +637,9 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
/* Request irqs after registering, as irqs may trigger immediately */
for (i = 0; i < axp_data->num_irq_names; i++) {
irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]);
if (irq < 0) {
dev_err(&pdev->dev, "No IRQ for %s: %d\n",
axp_data->irq_names[i], irq);
if (irq < 0)
return irq;
}
power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i],
axp20x_usb_power_irq, 0,
......
......@@ -42,11 +42,11 @@
#define VBUS_ISPOUT_CUR_LIM_1500MA 0x1 /* 1500mA */
#define VBUS_ISPOUT_CUR_LIM_2000MA 0x2 /* 2000mA */
#define VBUS_ISPOUT_CUR_NO_LIM 0x3 /* 2500mA */
#define VBUS_ISPOUT_VHOLD_SET_MASK 0x31
#define VBUS_ISPOUT_VHOLD_SET_MASK 0x38
#define VBUS_ISPOUT_VHOLD_SET_BIT_POS 0x3
#define VBUS_ISPOUT_VHOLD_SET_OFFSET 4000 /* 4000mV */
#define VBUS_ISPOUT_VHOLD_SET_LSB_RES 100 /* 100mV */
#define VBUS_ISPOUT_VHOLD_SET_4300MV 0x3 /* 4300mV */
#define VBUS_ISPOUT_VHOLD_SET_4400MV 0x4 /* 4400mV */
#define VBUS_ISPOUT_VBUS_PATH_DIS BIT(7)
#define CHRG_CCCV_CC_MASK 0xf /* 4 bits */
......@@ -769,6 +769,16 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info)
ret = axp288_charger_vbus_path_select(info, true);
if (ret < 0)
return ret;
} else {
/* Set Vhold to the factory default / recommended 4.4V */
val = VBUS_ISPOUT_VHOLD_SET_4400MV << VBUS_ISPOUT_VHOLD_SET_BIT_POS;
ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT,
VBUS_ISPOUT_VHOLD_SET_MASK, val);
if (ret < 0) {
dev_err(&info->pdev->dev, "register(%x) write error(%d)\n",
AXP20X_VBUS_IPSOUT_MGMT, ret);
return ret;
}
}
/* Read current charge voltage and current limit */
......@@ -828,6 +838,13 @@ static int axp288_charger_probe(struct platform_device *pdev)
struct power_supply_config charger_cfg = {};
unsigned int val;
/*
* Normally the native AXP288 fg/charger drivers are preferred but
* on some devices the ACPI drivers should be used instead.
*/
if (!acpi_quirk_skip_acpi_ac_and_battery())
return -ENODEV;
/*
* On some devices the fuelgauge and charger parts of the axp288 are
* not used, check that the fuelgauge is enabled (CC_CTRL != 0).
......
This diff is collapsed.
......@@ -39,6 +39,7 @@
#define BQ24190_REG_POC_CHG_CONFIG_DISABLE 0x0
#define BQ24190_REG_POC_CHG_CONFIG_CHARGE 0x1
#define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2
#define BQ24190_REG_POC_CHG_CONFIG_OTG_ALT 0x3
#define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1))
#define BQ24190_REG_POC_SYS_MIN_SHIFT 1
#define BQ24190_REG_POC_SYS_MIN_MIN 3000
......@@ -162,15 +163,24 @@ struct bq24190_dev_info {
char model_name[I2C_NAME_SIZE];
bool initialized;
bool irq_event;
bool otg_vbus_enabled;
int charge_type;
u16 sys_min;
u16 iprechg;
u16 iterm;
u32 ichg;
u32 ichg_max;
u32 vreg;
u32 vreg_max;
struct mutex f_reg_lock;
u8 f_reg;
u8 ss_reg;
u8 watchdog;
};
static int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi,
const union power_supply_propval *val);
static const unsigned int bq24190_usb_extcon_cable[] = {
EXTCON_USB,
EXTCON_NONE,
......@@ -497,10 +507,9 @@ static ssize_t bq24190_sysfs_store(struct device *dev,
}
#endif
#ifdef CONFIG_REGULATOR
static int bq24190_set_charge_mode(struct regulator_dev *dev, u8 val)
static int bq24190_set_otg_vbus(struct bq24190_dev_info *bdi, bool enable)
{
struct bq24190_dev_info *bdi = rdev_get_drvdata(dev);
union power_supply_propval val = { .intval = bdi->charge_type };
int ret;
ret = pm_runtime_get_sync(bdi->dev);
......@@ -510,9 +519,14 @@ static int bq24190_set_charge_mode(struct regulator_dev *dev, u8 val)
return ret;
}
bdi->otg_vbus_enabled = enable;
if (enable)
ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
BQ24190_REG_POC_CHG_CONFIG_MASK,
BQ24190_REG_POC_CHG_CONFIG_SHIFT, val);
BQ24190_REG_POC_CHG_CONFIG_SHIFT,
BQ24190_REG_POC_CHG_CONFIG_OTG);
else
ret = bq24190_charger_set_charge_type(bdi, &val);
pm_runtime_mark_last_busy(bdi->dev);
pm_runtime_put_autosuspend(bdi->dev);
......@@ -520,14 +534,15 @@ static int bq24190_set_charge_mode(struct regulator_dev *dev, u8 val)
return ret;
}
#ifdef CONFIG_REGULATOR
static int bq24190_vbus_enable(struct regulator_dev *dev)
{
return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_OTG);
return bq24190_set_otg_vbus(rdev_get_drvdata(dev), true);
}
static int bq24190_vbus_disable(struct regulator_dev *dev)
{
return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_CHARGE);
return bq24190_set_otg_vbus(rdev_get_drvdata(dev), false);
}
static int bq24190_vbus_is_enabled(struct regulator_dev *dev)
......@@ -550,7 +565,12 @@ static int bq24190_vbus_is_enabled(struct regulator_dev *dev)
pm_runtime_mark_last_busy(bdi->dev);
pm_runtime_put_autosuspend(bdi->dev);
return ret ? ret : val == BQ24190_REG_POC_CHG_CONFIG_OTG;
if (ret)
return ret;
bdi->otg_vbus_enabled = (val == BQ24190_REG_POC_CHG_CONFIG_OTG ||
val == BQ24190_REG_POC_CHG_CONFIG_OTG_ALT);
return bdi->otg_vbus_enabled;
}
static const struct regulator_ops bq24190_vbus_ops = {
......@@ -659,6 +679,28 @@ static int bq24190_set_config(struct bq24190_dev_info *bdi)
return ret;
}
if (bdi->ichg) {
ret = bq24190_set_field_val(bdi, BQ24190_REG_CCC,
BQ24190_REG_CCC_ICHG_MASK,
BQ24190_REG_CCC_ICHG_SHIFT,
bq24190_ccc_ichg_values,
ARRAY_SIZE(bq24190_ccc_ichg_values),
bdi->ichg);
if (ret < 0)
return ret;
}
if (bdi->vreg) {
ret = bq24190_set_field_val(bdi, BQ24190_REG_CVC,
BQ24190_REG_CVC_VREG_MASK,
BQ24190_REG_CVC_VREG_SHIFT,
bq24190_cvc_vreg_values,
ARRAY_SIZE(bq24190_cvc_vreg_values),
bdi->vreg);
if (ret < 0)
return ret;
}
return 0;
}
......@@ -775,6 +817,14 @@ static int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi,
return -EINVAL;
}
bdi->charge_type = val->intval;
/*
* If the 5V Vbus boost regulator is enabled delay setting
* the charge-type until its gets disabled.
*/
if (bdi->otg_vbus_enabled)
return 0;
if (chg_config) { /* Enabling the charger */
ret = bq24190_write_mask(bdi, BQ24190_REG_CCC,
BQ24190_REG_CCC_FORCE_20PCT_MASK,
......@@ -976,15 +1026,6 @@ static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
return 0;
}
static int bq24190_charger_get_current_max(struct bq24190_dev_info *bdi,
union power_supply_propval *val)
{
int idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1;
val->intval = bq24190_ccc_ichg_values[idx];
return 0;
}
static int bq24190_charger_set_current(struct bq24190_dev_info *bdi,
const union power_supply_propval *val)
{
......@@ -1001,10 +1042,19 @@ static int bq24190_charger_set_current(struct bq24190_dev_info *bdi,
if (v)
curr *= 5;
return bq24190_set_field_val(bdi, BQ24190_REG_CCC,
if (curr > bdi->ichg_max)
return -EINVAL;
ret = bq24190_set_field_val(bdi, BQ24190_REG_CCC,
BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
bq24190_ccc_ichg_values,
ARRAY_SIZE(bq24190_ccc_ichg_values), curr);
if (ret < 0)
return ret;
bdi->ichg = curr;
return 0;
}
static int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi,
......@@ -1023,22 +1073,24 @@ static int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi,
return 0;
}
static int bq24190_charger_get_voltage_max(struct bq24190_dev_info *bdi,
union power_supply_propval *val)
{
int idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1;
val->intval = bq24190_cvc_vreg_values[idx];
return 0;
}
static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi,
const union power_supply_propval *val)
{
return bq24190_set_field_val(bdi, BQ24190_REG_CVC,
int ret;
if (val->intval > bdi->vreg_max)
return -EINVAL;
ret = bq24190_set_field_val(bdi, BQ24190_REG_CVC,
BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
bq24190_cvc_vreg_values,
ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval);
if (ret < 0)
return ret;
bdi->vreg = val->intval;
return 0;
}
static int bq24190_charger_get_iinlimit(struct bq24190_dev_info *bdi,
......@@ -1108,13 +1160,15 @@ static int bq24190_charger_get_property(struct power_supply *psy,
ret = bq24190_charger_get_current(bdi, val);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
ret = bq24190_charger_get_current_max(bdi, val);
val->intval = bdi->ichg_max;
ret = 0;
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
ret = bq24190_charger_get_voltage(bdi, val);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
ret = bq24190_charger_get_voltage_max(bdi, val);
val->intval = bdi->vreg_max;
ret = 0;
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = bq24190_charger_get_iinlimit(bdi, val);
......@@ -1206,8 +1260,18 @@ static void bq24190_input_current_limit_work(struct work_struct *work)
struct bq24190_dev_info *bdi =
container_of(work, struct bq24190_dev_info,
input_current_limit_work.work);
union power_supply_propval val;
int ret;
power_supply_set_input_current_limit_from_supplier(bdi->charger);
ret = power_supply_get_property_from_supplier(bdi->charger,
POWER_SUPPLY_PROP_CURRENT_MAX,
&val);
if (ret)
return;
bq24190_charger_set_property(bdi->charger,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
&val);
}
/* Sync the input-current-limit with our parent supply (if we have one) */
......@@ -1671,7 +1735,13 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi)
{
const char * const s = "ti,system-minimum-microvolt";
struct power_supply_battery_info *info;
int v;
int v, idx;
idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1;
bdi->ichg_max = bq24190_ccc_ichg_values[idx];
idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1;
bdi->vreg_max = bq24190_cvc_vreg_values[idx];
if (device_property_read_u32(bdi->dev, s, &v) == 0) {
v /= 1000;
......@@ -1682,8 +1752,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi)
dev_warn(bdi->dev, "invalid value for %s: %u\n", s, v);
}
if (bdi->dev->of_node &&
!power_supply_get_battery_info(bdi->charger, &info)) {
if (!power_supply_get_battery_info(bdi->charger, &info)) {
v = info->precharge_current_ua / 1000;
if (v >= BQ24190_REG_PCTCC_IPRECHG_MIN
&& v <= BQ24190_REG_PCTCC_IPRECHG_MAX)
......@@ -1699,6 +1768,15 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi)
else
dev_warn(bdi->dev, "invalid value for battery:charge-term-current-microamp: %d\n",
v);
/* These are optional, so no warning when not set */
v = info->constant_charge_current_max_ua;
if (v >= bq24190_ccc_ichg_values[0] && v <= bdi->ichg_max)
bdi->ichg = bdi->ichg_max = v;
v = info->constant_charge_voltage_max_uv;
if (v >= bq24190_cvc_vreg_values[0] && v <= bdi->vreg_max)
bdi->vreg = bdi->vreg_max = v;
}
return 0;
......@@ -1728,6 +1806,7 @@ static int bq24190_probe(struct i2c_client *client,
bdi->dev = dev;
strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
mutex_init(&bdi->f_reg_lock);
bdi->charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
bdi->f_reg = 0;
bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
INIT_DELAYED_WORK(&bdi->input_current_limit_work,
......@@ -1860,6 +1939,14 @@ static int bq24190_remove(struct i2c_client *client)
return 0;
}
static void bq24190_shutdown(struct i2c_client *client)
{
struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
/* Turn off 5V boost regulator on shutdown */
bq24190_set_otg_vbus(bdi, false);
}
static __maybe_unused int bq24190_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -1970,6 +2057,7 @@ MODULE_DEVICE_TABLE(of, bq24190_of_match);
static struct i2c_driver bq24190_driver = {
.probe = bq24190_probe,
.remove = bq24190_remove,
.shutdown = bq24190_shutdown,
.id_table = bq24190_i2c_ids,
.driver = {
.name = "bq24190-charger",
......
This diff is collapsed.
......@@ -764,7 +764,7 @@ static int bq25980_get_charger_property(struct power_supply *psy,
if (!state.ce)
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
else if (state.bypass)
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
val->intval = POWER_SUPPLY_CHARGE_TYPE_BYPASS;
else if (!state.bypass)
val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
break;
......
......@@ -28,6 +28,7 @@
#include <linux/power_supply.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/nvmem-consumer.h>
#include <linux/moduleparam.h>
#include <linux/iio/consumer.h>
......@@ -73,6 +74,9 @@
#define CPCAP_BATTERY_CC_SAMPLE_PERIOD_MS 250
#define CPCAP_BATTERY_EB41_HW4X_ID 0x9E
#define CPCAP_BATTERY_BW8X_ID 0x98
enum {
CPCAP_BATTERY_IIO_BATTDET,
CPCAP_BATTERY_IIO_VOLTAGE,
......@@ -138,6 +142,7 @@ struct cpcap_battery_ddata {
int charge_full;
int status;
u16 vendor;
bool check_nvmem;
unsigned int is_full:1;
};
......@@ -354,6 +359,88 @@ cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata,
ccd->offset);
}
/*
* Based on the values from Motorola mapphone Linux kernel for the
* stock Droid 4 battery eb41. In the Motorola mapphone Linux
* kernel tree the value for pm_cd_factor is passed to the kernel
* via device tree. If it turns out to be something device specific
* we can consider that too later. These values are also fine for
* Bionic's hw4x.
*
* And looking at the battery full and shutdown values for the stock
* kernel on droid 4, full is 4351000 and software initiates shutdown
* at 3078000. The device will die around 2743000.
*/
static const struct cpcap_battery_config cpcap_battery_eb41_data = {
.cd_factor = 0x3cc,
.info.technology = POWER_SUPPLY_TECHNOLOGY_LION,
.info.voltage_max_design = 4351000,
.info.voltage_min_design = 3100000,
.info.charge_full_design = 1740000,
.bat.constant_charge_voltage_max_uv = 4200000,
};
/* Values for the extended Droid Bionic battery bw8x. */
static const struct cpcap_battery_config cpcap_battery_bw8x_data = {
.cd_factor = 0x3cc,
.info.technology = POWER_SUPPLY_TECHNOLOGY_LION,
.info.voltage_max_design = 4200000,
.info.voltage_min_design = 3200000,
.info.charge_full_design = 2760000,
.bat.constant_charge_voltage_max_uv = 4200000,
};
/*
* Safe values for any lipo battery likely to fit into a mapphone
* battery bay.
*/
static const struct cpcap_battery_config cpcap_battery_unkown_data = {
.cd_factor = 0x3cc,
.info.technology = POWER_SUPPLY_TECHNOLOGY_LION,
.info.voltage_max_design = 4200000,
.info.voltage_min_design = 3200000,
.info.charge_full_design = 3000000,
.bat.constant_charge_voltage_max_uv = 4200000,
};
static int cpcap_battery_match_nvmem(struct device *dev, const void *data)
{
if (strcmp(dev_name(dev), "89-500029ba0f73") == 0)
return 1;
else
return 0;
}
static void cpcap_battery_detect_battery_type(struct cpcap_battery_ddata *ddata)
{
struct nvmem_device *nvmem;
u8 battery_id = 0;
ddata->check_nvmem = false;
nvmem = nvmem_device_find(NULL, &cpcap_battery_match_nvmem);
if (IS_ERR_OR_NULL(nvmem)) {
ddata->check_nvmem = true;
dev_info_once(ddata->dev, "Can not find battery nvmem device. Assuming generic lipo battery\n");
} else if (nvmem_device_read(nvmem, 2, 1, &battery_id) < 0) {
battery_id = 0;
ddata->check_nvmem = true;
dev_warn(ddata->dev, "Can not read battery nvmem device. Assuming generic lipo battery\n");
}
switch (battery_id) {
case CPCAP_BATTERY_EB41_HW4X_ID:
ddata->config = cpcap_battery_eb41_data;
break;
case CPCAP_BATTERY_BW8X_ID:
ddata->config = cpcap_battery_bw8x_data;
break;
default:
ddata->config = cpcap_battery_unkown_data;
}
}
/**
* cpcap_battery_cc_get_avg_current - read cpcap coulumb counter
* @ddata: cpcap battery driver device data
......@@ -571,6 +658,9 @@ static int cpcap_battery_get_property(struct power_supply *psy,
latest = cpcap_battery_latest(ddata);
previous = cpcap_battery_previous(ddata);
if (ddata->check_nvmem)
cpcap_battery_detect_battery_type(ddata);
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
if (latest->temperature > CPCAP_NO_BATTERY || ignore_temperature_probe)
......@@ -982,30 +1072,10 @@ static int cpcap_battery_calibrate(struct cpcap_battery_ddata *ddata)
return error;
}
/*
* Based on the values from Motorola mapphone Linux kernel. In the
* the Motorola mapphone Linux kernel tree the value for pm_cd_factor
* is passed to the kernel via device tree. If it turns out to be
* something device specific we can consider that too later.
*
* And looking at the battery full and shutdown values for the stock
* kernel on droid 4, full is 4351000 and software initiates shutdown
* at 3078000. The device will die around 2743000.
*/
static const struct cpcap_battery_config cpcap_battery_default_data = {
.cd_factor = 0x3cc,
.info.technology = POWER_SUPPLY_TECHNOLOGY_LION,
.info.voltage_max_design = 4351000,
.info.voltage_min_design = 3100000,
.info.charge_full_design = 1740000,
.bat.constant_charge_voltage_max_uv = 4200000,
};
#ifdef CONFIG_OF
static const struct of_device_id cpcap_battery_id_table[] = {
{
.compatible = "motorola,cpcap-battery",
.data = &cpcap_battery_default_data,
},
{},
};
......@@ -1028,19 +1098,15 @@ static int cpcap_battery_probe(struct platform_device *pdev)
struct cpcap_battery_ddata *ddata;
struct power_supply_config psy_cfg = {};
int error;
const struct cpcap_battery_config *cfg;
cfg = device_get_match_data(&pdev->dev);
if (!cfg)
return -ENODEV;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
cpcap_battery_detect_battery_type(ddata);
INIT_LIST_HEAD(&ddata->irq_list);
ddata->dev = &pdev->dev;
memcpy(&ddata->config, cfg, sizeof(ddata->config));
ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
if (!ddata->reg)
......
......@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/stringify.h>
#include <linux/types.h>
#include <asm/unaligned.h>
#define DRV_NAME "cros-ec-pchg"
#define PCHG_DIR_PREFIX "peripheral"
......@@ -237,46 +238,22 @@ static int cros_pchg_event(const struct charger_data *charger,
return NOTIFY_OK;
}
static u32 cros_get_device_event(const struct charger_data *charger)
{
struct ec_params_device_event req;
struct ec_response_device_event rsp;
struct device *dev = charger->dev;
int ret;
req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS;
ret = cros_pchg_ec_command(charger, 0, EC_CMD_DEVICE_EVENT,
&req, sizeof(req), &rsp, sizeof(rsp));
if (ret < 0) {
dev_warn(dev, "Unable to get device events (err:%d)\n", ret);
return 0;
}
return rsp.event_mask;
}
static int cros_ec_notify(struct notifier_block *nb,
unsigned long queued_during_suspend,
void *data)
{
struct cros_ec_device *ec_dev = (struct cros_ec_device *)data;
u32 host_event = cros_ec_get_host_event(ec_dev);
struct cros_ec_device *ec_dev = data;
struct charger_data *charger =
container_of(nb, struct charger_data, notifier);
u32 device_event_mask;
u32 host_event;
if (!host_event)
if (ec_dev->event_data.event_type != EC_MKBP_EVENT_PCHG ||
ec_dev->event_size != sizeof(host_event))
return NOTIFY_DONE;
if (!(host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_DEVICE)))
return NOTIFY_DONE;
host_event = get_unaligned_le32(&ec_dev->event_data.data.host_event);
/*
* todo: Retrieve device event mask in common place
* (e.g. cros_ec_proto.c).
*/
device_event_mask = cros_get_device_event(charger);
if (!(device_event_mask & EC_DEVICE_EVENT_MASK(EC_DEVICE_EVENT_WLC)))
if (!(host_event & EC_MKBP_PCHG_DEVICE_EVENT))
return NOTIFY_DONE;
return cros_pchg_event(charger, host_event);
......
......@@ -104,7 +104,7 @@ static int cros_usbpd_charger_ec_command(struct charger_data *charger,
struct cros_ec_command *msg;
int ret;
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
msg = kzalloc(struct_size(msg, data, max(outsize, insize)), GFP_KERNEL);
if (!msg)
return -ENOMEM;
......
......@@ -20,6 +20,7 @@
#include <asm/div64.h>
#include <linux/mfd/da9150/core.h>
#include <linux/mfd/da9150/registers.h>
#include <linux/devm-helpers.h>
/* Core2Wire */
#define DA9150_QIF_READ (0x0 << 7)
......@@ -506,41 +507,28 @@ static int da9150_fg_probe(struct platform_device *pdev)
* work for reporting data updates.
*/
if (fg->interval) {
INIT_DELAYED_WORK(&fg->work, da9150_fg_work);
ret = devm_delayed_work_autocancel(dev, &fg->work,
da9150_fg_work);
if (ret) {
dev_err(dev, "Failed to init work\n");
return ret;
}
schedule_delayed_work(&fg->work,
msecs_to_jiffies(fg->interval));
}
/* Register IRQ */
irq = platform_get_irq_byname(pdev, "FG");
if (irq < 0) {
dev_err(dev, "Failed to get IRQ FG: %d\n", irq);
ret = irq;
goto irq_fail;
}
if (irq < 0)
return irq;
ret = devm_request_threaded_irq(dev, irq, NULL, da9150_fg_irq,
IRQF_ONESHOT, "FG", fg);
if (ret) {
dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret);
goto irq_fail;
}
return 0;
irq_fail:
if (fg->interval)
cancel_delayed_work(&fg->work);
return ret;
}
static int da9150_fg_remove(struct platform_device *pdev)
{
struct da9150_fg *fg = platform_get_drvdata(pdev);
if (fg->interval)
cancel_delayed_work(&fg->work);
}
return 0;
}
......@@ -564,7 +552,6 @@ static struct platform_driver da9150_fg_driver = {
.name = "da9150-fuel-gauge",
},
.probe = da9150_fg_probe,
.remove = da9150_fg_remove,
.resume = da9150_fg_resume,
};
......
This diff is collapsed.
......@@ -112,7 +112,8 @@ static int ltc294x_read_regs(struct i2c_client *client,
ret = i2c_transfer(client->adapter, &msgs[0], 2);
if (ret < 0) {
dev_err(&client->dev, "ltc2941 read_reg failed!\n");
dev_err(&client->dev, "ltc2941 read_reg(0x%x[%d]) failed: %pe\n",
reg, num_regs, ERR_PTR(ret));
return ret;
}
......@@ -130,7 +131,8 @@ static int ltc294x_write_regs(struct i2c_client *client,
ret = i2c_smbus_write_i2c_block_data(client, reg_start, num_regs, buf);
if (ret < 0) {
dev_err(&client->dev, "ltc2941 write_reg failed!\n");
dev_err(&client->dev, "ltc2941 write_reg(0x%x[%d]) failed: %pe\n",
reg, num_regs, ERR_PTR(ret));
return ret;
}
......@@ -148,11 +150,8 @@ static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
/* Read status and control registers */
ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
if (ret < 0) {
dev_err(&info->client->dev,
"Could not read registers from device\n");
goto error_exit;
}
if (ret < 0)
return ret;
control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
......@@ -172,17 +171,11 @@ static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
if (value != control) {
ret = ltc294x_write_regs(info->client,
LTC294X_REG_CONTROL, &control, 1);
if (ret < 0) {
dev_err(&info->client->dev,
"Could not write register\n");
goto error_exit;
}
if (ret < 0)
return ret;
}
return 0;
error_exit:
return ret;
}
static int ltc294x_read_charge_register(const struct ltc294x_info *info,
......@@ -472,11 +465,9 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
/* r_sense can be negative, when sense+ is connected to the battery
* instead of the sense-. This results in reversed measurements. */
ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense);
if (ret < 0) {
dev_err(&client->dev,
if (ret < 0)
return dev_err_probe(&client->dev, ret,
"Could not find lltc,resistor-sense in devicetree\n");
return ret;
}
info->r_sense = r_sense;
ret = of_property_read_u32(np, "lltc,prescaler-exponent",
......@@ -490,23 +481,21 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
if (info->id == LTC2943_ID) {
if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP)
prescaler_exp = LTC2943_MAX_PRESCALER_EXP;
info->Qlsb = ((340 * 50000) / r_sense) /
(4096 / (1 << (2*prescaler_exp)));
info->Qlsb = ((340 * 50000) / r_sense) >>
(12 - 2*prescaler_exp);
} else {
if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP)
prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
info->Qlsb = ((85 * 50000) / r_sense) /
(128 / (1 << prescaler_exp));
info->Qlsb = ((85 * 50000) / r_sense) >>
(7 - prescaler_exp);
}
/* Read status register to check for LTC2942 */
if (info->id == LTC2941_ID || info->id == LTC2942_ID) {
ret = ltc294x_read_regs(client, LTC294X_REG_STATUS, &status, 1);
if (ret < 0) {
dev_err(&client->dev,
if (ret < 0)
return dev_err_probe(&client->dev, ret,
"Could not read status register\n");
return ret;
}
if (status & LTC2941_REG_STATUS_CHIP_ID)
info->id = LTC2941_ID;
else
......@@ -545,19 +534,17 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
return ret;
ret = ltc294x_reset(info, prescaler_exp);
if (ret < 0) {
dev_err(&client->dev, "Communication with chip failed\n");
return ret;
}
if (ret < 0)
return dev_err_probe(&client->dev, ret,
"Communication with chip failed\n");
info->supply = devm_power_supply_register(&client->dev,
&info->supply_desc, &psy_cfg);
if (IS_ERR(info->supply)) {
dev_err(&client->dev, "failed to register ltc2941\n");
return PTR_ERR(info->supply);
} else {
if (IS_ERR(info->supply))
return dev_err_probe(&client->dev, PTR_ERR(info->supply),
"failed to register ltc2941\n");
schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
}
return 0;
}
......
......@@ -18,6 +18,7 @@
#include <linux/of_device.h>
#include <linux/workqueue.h>
#include <linux/power_supply.h>
#include <linux/devm-helpers.h>
#define MAX14656_MANUFACTURER "Maxim Integrated"
#define MAX14656_NAME "max14656"
......@@ -233,14 +234,6 @@ static enum power_supply_property max14656_battery_props[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
};
static void stop_irq_work(void *data)
{
struct max14656_chip *chip = data;
cancel_delayed_work_sync(&chip->irq_work);
}
static int max14656_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -286,10 +279,10 @@ static int max14656_probe(struct i2c_client *client,
return -EINVAL;
}
INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker);
ret = devm_add_action(dev, stop_irq_work, chip);
ret = devm_delayed_work_autocancel(dev, &chip->irq_work,
max14656_irq_worker);
if (ret) {
dev_err(dev, "devm_add_action %d failed\n", ret);
dev_err(dev, "devm_delayed_work_autocancel %d failed\n", ret);
return ret;
}
......
......@@ -9,6 +9,7 @@
// This driver is based on max17040_battery.c
#include <linux/acpi.h>
#include <linux/devm-helpers.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
......@@ -1030,13 +1031,6 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
.num_properties = ARRAY_SIZE(max17042_battery_props) - 2,
};
static void max17042_stop_work(void *data)
{
struct max17042_chip *chip = data;
cancel_work_sync(&chip->work);
}
static int max17042_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -1142,8 +1136,8 @@ static int max17042_probe(struct i2c_client *client,
regmap_read(chip->regmap, MAX17042_STATUS, &val);
if (val & STATUS_POR_BIT) {
INIT_WORK(&chip->work, max17042_init_worker);
ret = devm_add_action(&client->dev, max17042_stop_work, chip);
ret = devm_work_autocancel(&client->dev, &chip->work,
max17042_init_worker);
if (ret)
return ret;
schedule_work(&chip->work);
......
......@@ -14,6 +14,7 @@
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
#include <linux/regulator/consumer.h>
#include <linux/devm-helpers.h>
/* MAX8997_REG_STATUS4 */
#define DCINOK_SHIFT 1
......@@ -94,13 +95,6 @@ static int max8997_battery_get_property(struct power_supply *psy,
return 0;
}
static void max8997_battery_extcon_evt_stop_work(void *data)
{
struct charger_data *charger = data;
cancel_work_sync(&charger->extcon_work);
}
static void max8997_battery_extcon_evt_worker(struct work_struct *work)
{
struct charger_data *charger =
......@@ -255,8 +249,8 @@ static int max8997_battery_probe(struct platform_device *pdev)
}
if (!IS_ERR(charger->reg) && !IS_ERR_OR_NULL(charger->edev)) {
INIT_WORK(&charger->extcon_work, max8997_battery_extcon_evt_worker);
ret = devm_add_action(&pdev->dev, max8997_battery_extcon_evt_stop_work, charger);
ret = devm_work_autocancel(&pdev->dev, &charger->extcon_work,
max8997_battery_extcon_evt_worker);
if (ret) {
dev_err(&pdev->dev, "failed to add extcon evt stop action: %d\n", ret);
return ret;
......
......@@ -580,11 +580,9 @@ static int mp2629_charger_probe(struct platform_device *pdev)
charger->dev = dev;
platform_set_drvdata(pdev, charger);
irq = platform_get_irq_optional(to_platform_device(dev->parent), 0);
if (irq < 0) {
dev_err(dev, "get irq fail: %d\n", irq);
irq = platform_get_irq(to_platform_device(dev->parent), 0);
if (irq < 0)
return irq;
}
for (i = 0; i < MP2629_MAX_FIELD; i++) {
charger->regmap_fields[i] = devm_regmap_field_alloc(dev,
......
This diff is collapsed.
This diff is collapsed.
......@@ -89,6 +89,7 @@ static const char * const POWER_SUPPLY_CHARGE_TYPE_TEXT[] = {
[POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE] = "Adaptive",
[POWER_SUPPLY_CHARGE_TYPE_CUSTOM] = "Custom",
[POWER_SUPPLY_CHARGE_TYPE_LONGLIFE] = "Long Life",
[POWER_SUPPLY_CHARGE_TYPE_BYPASS] = "Bypass",
};
static const char * const POWER_SUPPLY_HEALTH_TEXT[] = {
......
......@@ -1716,7 +1716,7 @@ static int rt9455_remove(struct i2c_client *client)
cancel_delayed_work_sync(&info->max_charging_time_work);
cancel_delayed_work_sync(&info->batt_presence_work);
return ret;
return 0;
}
static const struct i2c_device_id rt9455_i2c_id_table[] = {
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
#if IS_ENABLED(CONFIG_BATTERY_SAMSUNG_SDI)
extern int samsung_sdi_battery_get_info(struct device *dev,
const char *compatible,
struct power_supply_battery_info **info);
#else
static inline int samsung_sdi_battery_get_info(struct device *dev,
const char *compatible,
struct power_supply_battery_info **info)
{
return -ENODEV;
}
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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