power supply and reset changes for the v4.4 series

* new AXP20X USB Power driver
  * new Qualcomm SMBB driver
  * new TPS65217 Charger driver
  * BQ24257: add BQ24250/BQ24251 support
  * overhaul bq27x00 battery driver, rename to bq27xxx
  * misc. fixes and cleanups
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCgAGBQJWOn8oAAoJENju1/PIO/qahrEP/RPHXvTxtYv8YvhaFbqcr07x
 11gRB8RRthKK5woC3s70QKlMtcHijFeCwKuacut+7tfgK2oZDIm+Bd43Pl93aypU
 Yk4oTwop5OyrLsGIGiTIPPV9HTwr4q69Or2Q91mqUAUe2wGB5uCuJiJmCowUwfZs
 piv+ISLSOcH+i1bTx3hQ7h7axsdAlaSz2o1JprZaxm3rM67M8zF1ZHSK7wlpAeBa
 DiDrtUvEDCeLL8dmCA9xkFV4yFB9T+KNh0730N2RY+zlZS6WjSpzryqwsUWWyQ6h
 U9gFgcs+DjVaGHuMsIX2zm7xXfXHgUBtXdSQoCBhpSrZsdufMsT/8VQqVZ0yqpXL
 pQ2EXy63k6tXnXEyAKTA0tAOX/WZNfmmNblkea4JiyZULn7b/WH09waMZUBJqe84
 Yn3SatVdGDN4nawsivzdiM3zR9/WTE9R3DmEeAE+g1RRsSraNwWlkzpDXcmnWmbc
 DoprnjLsDJfqL3/1ysF2V2I4B26Bws73qq6UUjJ4KEGWf8Y1fVawxrbcYmnrvg1K
 zW/saEgtl70FYqtee/0lIqTpjOZRX/O6QH5i8p7VC8cUzftX0Twc8MvfvpamDywX
 Cr1Y7pIMEhc6TFUP5lOzx9xJelA5PHJMpAT+02fh6YXMAzCcBUzL113rY5zBrVVl
 gce0iHDKAybmvww77z1r
 =0be4
 -----END PGP SIGNATURE-----

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

Pull power supply and reset updates from Sebastian Reichel:
 - new AXP20X USB Power driver
 - new Qualcomm SMBB driver
 - new TPS65217 Charger driver
 - BQ24257: add BQ24250/BQ24251 support
 - overhaul bq27x00 battery driver, rename to bq27xxx
 - misc fixes and cleanups

* tag 'for-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (54 commits)
  power: bq27xxx_battery: Remove unneeded dependency in Kconfig
  power: bq27xxx_battery: move irq handler to i2c section
  power: bq27xxx_battery: fix platform probe
  twl4030_charger: add missing iio dependency
  power_supply: charger-manager: add missing of_node_put
  Documentation: power: bq24257: Document exported sysfs entries
  power: bq24257: Add various device-specific sysfs properties
  power: bq24257: Allow input current limit sysfs access
  power: bq24257: Add input DPM voltage threshold setting support
  power: bq24257: Add over voltage protection setting support
  power: bq24257: Add SW-based approach for Power Good determination
  power: bq24257: Allow manual setting of input current limit
  power: bq24257: Add bit definition for temp sense enable
  power: bq24257: Add basic support for bq24250/bq24251
  dt: power: bq24257-charger: Cover additional devices
  power: bq24257: Simplify bq24257_power_supply_init()
  power: bq24257: Use managed power supply register
  power: bq24257: Streamline input current limit setup
  power: bq24257: Remove IRQ config through stat-gpios
  power: bq27xxx_battery: fix signedness bug in bq27xxx_battery_read_health()
  ...
This commit is contained in:
Linus Torvalds 2015-11-05 12:28:15 -08:00
commit 400c5bd5a5
39 changed files with 3818 additions and 1474 deletions

View file

@ -74,3 +74,61 @@ Description:
Valid values:
- 0 - 70 (minutes), step by 10 (rounded down)
What: /sys/class/power_supply/bq24257-charger/ovp_voltage
Date: October 2015
KernelVersion: 4.4.0
Contact: Andreas Dannenberg <dannenberg@ti.com>
Description:
This entry configures the overvoltage protection feature of bq24257-
type charger devices. This feature protects the device and other
components against damage from overvoltage on the input supply. See
device datasheet for details.
Valid values:
- 6000000, 6500000, 7000000, 8000000, 9000000, 9500000, 10000000,
10500000 (all uV)
What: /sys/class/power_supply/bq24257-charger/in_dpm_voltage
Date: October 2015
KernelVersion: 4.4.0
Contact: Andreas Dannenberg <dannenberg@ti.com>
Description:
This entry configures the input dynamic power path management voltage of
bq24257-type charger devices. Once the supply drops to the configured
voltage, the input current limit is reduced down to prevent the further
drop of the supply. When the IC enters this mode, the charge current is
lower than the set value. See device datasheet for details.
Valid values:
- 4200000, 4280000, 4360000, 4440000, 4520000, 4600000, 4680000,
4760000 (all uV)
What: /sys/class/power_supply/bq24257-charger/high_impedance_enable
Date: October 2015
KernelVersion: 4.4.0
Contact: Andreas Dannenberg <dannenberg@ti.com>
Description:
This entry allows enabling the high-impedance mode of bq24257-type
charger devices. If enabled, it places the charger IC into low power
standby mode with the switch mode controller disabled. When disabled,
the charger operates normally. See device datasheet for details.
Valid values:
- 1: enabled
- 0: disabled
What: /sys/class/power_supply/bq24257-charger/sysoff_enable
Date: October 2015
KernelVersion: 4.4.0
Contact: Andreas Dannenberg <dannenberg@ti.com>
Description:
This entry allows enabling the sysoff mode of bq24257-type charger
devices. If enabled and the input is removed, the internal battery FET
is turned off in order to reduce the leakage from the BAT pin to less
than 1uA. Note that on some devices/systems this disconnects the battery
from the system. See device datasheet for details.
Valid values:
- 1: enabled
- 0: disabled

View file

@ -1,21 +1,64 @@
Binding for TI bq24257 Li-Ion Charger
Binding for TI bq24250/bq24251/bq24257 Li-Ion Charger
Required properties:
- compatible: Should contain one of the following:
* "ti,bq24250"
* "ti,bq24251"
* "ti,bq24257"
- reg: integer, i2c address of the device.
- reg: integer, i2c address of the device.
- interrupt-parent: Should be the phandle for the interrupt controller. Use in
conjunction with "interrupts".
- interrupts: Interrupt mapping for GPIO IRQ (configure for both edges). Use in
conjunction with "interrupt-parent".
- ti,battery-regulation-voltage: integer, maximum charging voltage in uV.
- ti,charge-current: integer, maximum charging current in uA.
- ti,termination-current: integer, charge will be terminated when current in
constant-voltage phase drops below this value (in uA).
- ti,charge-current: integer, maximum charging current in uA.
- ti,termination-current: integer, charge will be terminated when current in
constant-voltage phase drops below this value (in uA).
Optional properties:
- pg-gpios: GPIO used for connecting the bq2425x device PG (Power Good) pin.
This pin is not available on all devices however it should be used if
possible as this is the recommended way to obtain the charger's input PG
state. If this pin is not specified a software-based approach for PG
detection is used.
- ti,current-limit: The maximum current to be drawn from the charger's input
(in uA). If this property is not specified, the input limit current is
set automatically using USB D+/D- signal based charger type detection.
If the hardware does not support the D+/D- based detection, a default
of 500,000 is used (=500mA) instead.
- ti,ovp-voltage: Configures the over voltage protection voltage (in uV). If
not specified a default of 6,5000,000 (=6.5V) is used.
- ti,in-dpm-voltage: Configures the threshold input voltage for the dynamic
power path management (in uV). If not specified a default of 4,360,000
(=4.36V) is used.
Example:
bq24257 {
compatible = "ti,bq24257";
reg = <0x6a>;
interrupt-parent = <&gpio1>;
interrupts = <16 IRQ_TYPE_EDGE_BOTH>;
pg-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
ti,battery-regulation-voltage = <4200000>;
ti,charge-current = <1000000>;
ti,termination-current = <50000>;
};
Example:
bq24250 {
compatible = "ti,bq24250";
reg = <0x6a>;
interrupt-parent = <&gpio1>;
interrupts = <16 IRQ_TYPE_EDGE_BOTH>;
ti,battery-regulation-voltage = <4200000>;
ti,charge-current = <500000>;
ti,termination-current = <50000>;
ti,current-limit = <900000>;
ti,ovp-voltage = <9500000>;
ti,in-dpm-voltage = <4440000>;
};

View file

@ -0,0 +1,34 @@
AXP20x USB power supply
Required Properties:
-compatible: "x-powers,axp202-usb-power-supply"
This node is a subnode of the axp20x PMIC.
Example:
axp209: pmic@34 {
compatible = "x-powers,axp209";
reg = <0x34>;
interrupt-parent = <&nmi_intc>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <1>;
regulators {
x-powers,dcdc-freq = <1500>;
vdd_cpu: dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1450000>;
regulator-name = "vdd-cpu";
};
...
};
usb-power-supply: usb-power-supply {
compatible = "x-powers,axp202-usb-power-supply";
};
};

View file

@ -0,0 +1,131 @@
Qualcomm Switch-Mode Battery Charger and Boost
PROPERTIES
- compatible:
Usage: required
Value type: <stringlist>
Description: Must be one of:
- "qcom,pm8941-charger"
- reg:
Usage: required
Value type: <prop-encoded-array>
Description: Base address of registers for SMBB block
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Description: The format of the specifier is defined by the binding document
describing the node's interrupt parent. Must contain one
specifier for each of the following interrupts, in order:
- charge done
- charge fast mode
- charge trickle mode
- battery temperature ok
- battery present
- charger disconnected
- USB-in valid
- DC-in valid
- interrupt-names:
Usage: required
Value type: <stringlist>
Description: Must contain the following list, strictly ordered:
"chg-done",
"chg-fast",
"chg-trkl",
"bat-temp-ok",
"bat-present",
"chg-gone",
"usb-valid",
"dc-valid"
- qcom,fast-charge-current-limit:
Usage: optional (default: 1A, or pre-configured value)
Value type: <u32>; uA; range [100mA : 3A]
Description: Maximum charge current; May be clamped to safety limits.
- qcom,fast-charge-low-threshold-voltage:
Usage: optional (default: 3.2V, or pre-configured value)
Value type: <u32>; uV; range [2.1V : 3.6V]
Description: Battery voltage limit above which fast charging may operate;
Below this value linear or switch-mode auto-trickle-charging
will operate.
- qcom,fast-charge-high-threshold-voltage:
Usage: optional (default: 4.2V, or pre-configured value)
Value type: <u32>; uV; range [3.24V : 5V]
Description: Battery voltage limit below which fast charging may operate;
The fast charger will attempt to charge the battery to this
voltage. May be clamped to safety limits.
- qcom,fast-charge-safe-voltage:
Usage: optional (default: 4.2V, or pre-configured value)
Value type: <u32>; uV; range [3.24V : 5V]
Description: Maximum safe battery voltage; May be pre-set by bootloader, in
which case, setting this will harmlessly fail. The property
'fast-charge-high-watermark' will be clamped by this value.
- qcom,fast-charge-safe-current:
Usage: optional (default: 1A, or pre-configured value)
Value type: <u32>; uA; range [100mA : 3A]
Description: Maximum safe battery charge current; May pre-set by bootloader,
in which case, setting this will harmlessly fail. The property
'qcom,fast-charge-current-limit' will be clamped by this value.
- qcom,auto-recharge-threshold-voltage:
Usage: optional (default: 4.1V, or pre-configured value)
Value type: <u32>; uV; range [3.24V : 5V]
Description: Battery voltage limit below which auto-recharge functionality
will restart charging after end-of-charge; The high cutoff
limit for auto-recharge is 5% above this value.
- qcom,minimum-input-voltage:
Usage: optional (default: 4.3V, or pre-configured value)
Value type: <u32>; uV; range [4.2V : 9.6V]
Description: Input voltage level above which charging may operate
- qcom,dc-current-limit:
Usage: optional (default: 100mA, or pre-configured value)
Value type: <u32>; uA; range [100mA : 2.5A]
Description: Default DC charge current limit
- qcom,disable-dc:
Usage: optional (default: false)
Value type: boolean: <u32> or <empty>
Description: Disable DC charger
- qcom,jeita-extended-temp-range:
Usage: optional (default: false)
Value type: boolean: <u32> or <empty>
Description: Enable JEITA extended temperature range; This does *not*
adjust the maximum charge voltage or current in the extended
temperature range. It only allows charging when the battery
is in the extended temperature range. Voltage/current
regulation must be done externally to fully comply with
the JEITA safety guidelines if this flag is set.
EXAMPLE
charger@1000 {
compatible = "qcom,pm8941-charger";
reg = <0x1000 0x700>;
interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>,
<0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>,
<0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>,
<0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>,
<0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>,
<0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>,
<0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>,
<0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "chg-done",
"chg-fast",
"chg-trkl",
"bat-temp-ok",
"bat-present",
"chg-gone",
"usb-valid",
"dc-valid";
qcom,fast-charge-current-limit = <1000000>;
qcom,dc-charge-current-limit = <1000000>;
};

View file

@ -0,0 +1,12 @@
TPS65217 Charger
Required Properties:
-compatible: "ti,tps65217-charger"
This node is a subnode of the tps65217 PMIC.
Example:
tps65217-charger {
compatible = "ti,tps65090-charger";
};

View file

@ -7505,10 +7505,10 @@ NOKIA N900 POWER SUPPLY DRIVERS
M: Pali Rohár <pali.rohar@gmail.com>
S: Maintained
F: include/linux/power/bq2415x_charger.h
F: include/linux/power/bq27x00_battery.h
F: include/linux/power/bq27xxx_battery.h
F: include/linux/power/isp1704_charger.h
F: drivers/power/bq2415x_charger.c
F: drivers/power/bq27x00_battery.c
F: drivers/power/bq27xxx_battery.c
F: drivers/power/isp1704_charger.c
F: drivers/power/rx51_battery.c

View file

@ -22,6 +22,8 @@
charger: bci {
compatible = "ti,twl4030-bci";
interrupts = <9>, <2>;
io-channels = <&twl4030_madc 11>;
io-channel-name = "vac";
bci3v1-supply = <&vusb3v1>;
};

View file

@ -246,7 +246,7 @@ CONFIG_GPIO_TWL4030=y
CONFIG_GPIO_PALMAS=y
CONFIG_W1=m
CONFIG_HDQ_MASTER_OMAP=m
CONFIG_BATTERY_BQ27x00=m
CONFIG_BATTERY_BQ27XXX=m
CONFIG_CHARGER_ISP1704=m
CONFIG_CHARGER_TWL4030=m
CONFIG_CHARGER_BQ2415X=m

View file

@ -222,7 +222,7 @@ config I2C_BATTERY_BQ27200
tristate "I2C Battery BQ27200 Support"
select I2C_PUV3
select POWER_SUPPLY
select BATTERY_BQ27x00
select BATTERY_BQ27XXX
config I2C_EEPROM_AT24
tristate "I2C EEPROMs AT24 support"

View file

@ -954,46 +954,32 @@ static int pm860x_battery_probe(struct platform_device *pdev)
else
info->resistor = 300; /* set default internal resistor */
info->battery = power_supply_register(&pdev->dev, &pm860x_battery_desc,
NULL);
info->battery = devm_power_supply_register(&pdev->dev,
&pm860x_battery_desc,
NULL);
if (IS_ERR(info->battery))
return PTR_ERR(info->battery);
info->battery->dev.parent = &pdev->dev;
ret = request_threaded_irq(info->irq_cc, NULL,
pm860x_coulomb_handler, IRQF_ONESHOT,
"coulomb", info);
ret = devm_request_threaded_irq(chip->dev, info->irq_cc, NULL,
pm860x_coulomb_handler, IRQF_ONESHOT,
"coulomb", info);
if (ret < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
info->irq_cc, ret);
goto out_reg;
return ret;
}
ret = request_threaded_irq(info->irq_batt, NULL, pm860x_batt_handler,
IRQF_ONESHOT, "battery", info);
ret = devm_request_threaded_irq(chip->dev, info->irq_batt, NULL,
pm860x_batt_handler,
IRQF_ONESHOT, "battery", info);
if (ret < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
info->irq_batt, ret);
goto out_coulomb;
return ret;
}
return 0;
out_coulomb:
free_irq(info->irq_cc, info);
out_reg:
power_supply_unregister(info->battery);
return ret;
}
static int pm860x_battery_remove(struct platform_device *pdev)
{
struct pm860x_battery_info *info = platform_get_drvdata(pdev);
free_irq(info->irq_batt, info);
free_irq(info->irq_cc, info);
power_supply_unregister(info->battery);
return 0;
}
@ -1028,7 +1014,6 @@ static struct platform_driver pm860x_battery_driver = {
.pm = &pm860x_battery_pm_ops,
},
.probe = pm860x_battery_probe,
.remove = pm860x_battery_remove,
};
module_platform_driver(pm860x_battery_driver);

View file

@ -157,26 +157,25 @@ config BATTERY_SBS
Say Y to include support for SBS battery driver for SBS-compliant
gas gauges.
config BATTERY_BQ27x00
tristate "BQ27x00 battery driver"
depends on I2C || I2C=n
config BATTERY_BQ27XXX
tristate "BQ27xxx battery driver"
help
Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips.
Say Y here to enable support for batteries with BQ27xxx (I2C/HDQ) chips.
config BATTERY_BQ27X00_I2C
bool "BQ27200/BQ27500 support"
depends on BATTERY_BQ27x00
config BATTERY_BQ27XXX_I2C
bool "BQ27xxx I2C support"
depends on BATTERY_BQ27XXX
depends on I2C
default y
help
Say Y here to enable support for batteries with BQ27x00 (I2C) chips.
Say Y here to enable support for batteries with BQ27xxx (I2C) chips.
config BATTERY_BQ27X00_PLATFORM
bool "BQ27000 support"
depends on BATTERY_BQ27x00
config BATTERY_BQ27XXX_PLATFORM
bool "BQ27xxx HDQ support"
depends on BATTERY_BQ27XXX
default y
help
Say Y here to enable support for batteries with BQ27000 (HDQ) chips.
Say Y here to enable support for batteries with BQ27xxx (HDQ) chips.
config BATTERY_DA9030
tristate "DA9030 battery driver"
@ -313,7 +312,7 @@ config CHARGER_MAX8903
config CHARGER_TWL4030
tristate "OMAP TWL4030 BCI charger driver"
depends on TWL4030_CORE
depends on IIO && TWL4030_CORE
help
Say Y here to enable support for TWL4030 Battery Charge Interface.
@ -379,6 +378,18 @@ config CHARGER_MAX8998
Say Y to enable support for the battery charger control sysfs and
platform data of MAX8998/LP3974 PMICs.
config CHARGER_QCOM_SMBB
tristate "Qualcomm Switch-Mode Battery Charger and Boost"
depends on MFD_SPMI_PMIC || COMPILE_TEST
depends on OF
help
Say Y to include support for the Switch-Mode Battery Charger and
Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger
is an integrated, single-cell lithium-ion battery charger. DT
configuration is required for loading, see the devicetree
documentation for more detail. The base name for this driver is
'pm8941_charger'.
config CHARGER_BQ2415X
tristate "TI BQ2415x battery charger driver"
depends on I2C
@ -397,12 +408,13 @@ config CHARGER_BQ24190
Say Y to enable support for the TI BQ24190 battery charger.
config CHARGER_BQ24257
tristate "TI BQ24257 battery charger driver"
tristate "TI BQ24250/24251/24257 battery charger driver"
depends on I2C
depends on GPIOLIB || COMPILE_TEST
depends on REGMAP_I2C
help
Say Y to enable support for the TI BQ24257 battery charger.
Say Y to enable support for the TI BQ24250, BQ24251, and BQ24257 battery
chargers.
config CHARGER_BQ24735
tristate "TI BQ24735 battery charger support"
@ -434,6 +446,13 @@ config CHARGER_TPS65090
Say Y here to enable support for battery charging with TPS65090
PMIC chips.
config CHARGER_TPS65217
tristate "TPS65217 battery charger driver"
depends on MFD_TPS65217
help
Say Y here to enable support for battery charging with TPS65217
PMIC chips.
config BATTERY_GAUGE_LTC2941
tristate "LTC2941/LTC2943 Battery Gauge Driver"
depends on I2C
@ -472,6 +491,13 @@ 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.
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY

View file

@ -9,6 +9,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_MAX8925_POWER) += max8925_power.o
obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
@ -29,7 +30,7 @@ obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o
obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o
@ -57,6 +58,7 @@ obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o
@ -65,6 +67,7 @@ obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
obj-$(CONFIG_POWER_RESET) += reset/
obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o

View file

@ -0,0 +1,248 @@
/*
* AXP20x PMIC USB power supply status driver
*
* Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
* Copyright (C) 2014 Bruno Prémont <bonbons@linux-vserver.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define DRVNAME "axp20x-usb-power-supply"
#define AXP20X_PWR_STATUS_VBUS_PRESENT BIT(5)
#define AXP20X_PWR_STATUS_VBUS_USED BIT(4)
#define AXP20X_USB_STATUS_VBUS_VALID BIT(2)
#define AXP20X_VBUS_VHOLD_uV(b) (4000000 + (((b) >> 3) & 7) * 100000)
#define AXP20X_VBUS_CLIMIT_MASK 3
#define AXP20X_VBUC_CLIMIT_900mA 0
#define AXP20X_VBUC_CLIMIT_500mA 1
#define AXP20X_VBUC_CLIMIT_100mA 2
#define AXP20X_VBUC_CLIMIT_NONE 3
#define AXP20X_ADC_EN1_VBUS_CURR BIT(2)
#define AXP20X_ADC_EN1_VBUS_VOLT BIT(3)
#define AXP20X_VBUS_MON_VBUS_VALID BIT(3)
struct axp20x_usb_power {
struct regmap *regmap;
struct power_supply *supply;
};
static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
{
struct axp20x_usb_power *power = devid;
power_supply_changed(power->supply);
return IRQ_HANDLED;
}
static int axp20x_usb_power_get_property(struct power_supply *psy,
enum power_supply_property psp, union power_supply_propval *val)
{
struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
unsigned int input, v;
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
if (ret)
return ret;
val->intval = AXP20X_VBUS_VHOLD_uV(v);
return 0;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = axp20x_read_variable_width(power->regmap,
AXP20X_VBUS_V_ADC_H, 12);
if (ret < 0)
return ret;
val->intval = ret * 1700; /* 1 step = 1.7 mV */
return 0;
case POWER_SUPPLY_PROP_CURRENT_MAX:
ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
if (ret)
return ret;
switch (v & AXP20X_VBUS_CLIMIT_MASK) {
case AXP20X_VBUC_CLIMIT_100mA:
val->intval = 100000;
break;
case AXP20X_VBUC_CLIMIT_500mA:
val->intval = 500000;
break;
case AXP20X_VBUC_CLIMIT_900mA:
val->intval = 900000;
break;
case AXP20X_VBUC_CLIMIT_NONE:
val->intval = -1;
break;
}
return 0;
case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = axp20x_read_variable_width(power->regmap,
AXP20X_VBUS_I_ADC_H, 12);
if (ret < 0)
return ret;
val->intval = ret * 375; /* 1 step = 0.375 mA */
return 0;
default:
break;
}
/* All the properties below need the input-status reg value */
ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &input);
if (ret)
return ret;
switch (psp) {
case POWER_SUPPLY_PROP_HEALTH:
if (!(input & AXP20X_PWR_STATUS_VBUS_PRESENT)) {
val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
break;
}
ret = regmap_read(power->regmap, AXP20X_USB_OTG_STATUS, &v);
if (ret)
return ret;
if (!(v & AXP20X_USB_STATUS_VBUS_VALID)) {
val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
break;
}
val->intval = POWER_SUPPLY_HEALTH_GOOD;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_PRESENT);
break;
case POWER_SUPPLY_PROP_ONLINE:
val->intval = !!(input & AXP20X_PWR_STATUS_VBUS_USED);
break;
default:
return -EINVAL;
}
return 0;
}
static enum power_supply_property axp20x_usb_power_properties[] = {
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
};
static const struct power_supply_desc axp20x_usb_power_desc = {
.name = "axp20x-usb",
.type = POWER_SUPPLY_TYPE_USB,
.properties = axp20x_usb_power_properties,
.num_properties = ARRAY_SIZE(axp20x_usb_power_properties),
.get_property = axp20x_usb_power_get_property,
};
static int axp20x_usb_power_probe(struct platform_device *pdev)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
struct power_supply_config psy_cfg = {};
struct axp20x_usb_power *power;
static const char * const irq_names[] = { "VBUS_PLUGIN",
"VBUS_REMOVAL", "VBUS_VALID", "VBUS_NOT_VALID" };
int i, irq, ret;
if (!of_device_is_available(pdev->dev.of_node))
return -ENODEV;
if (!axp20x) {
dev_err(&pdev->dev, "Parent drvdata not set\n");
return -EINVAL;
}
power = devm_kzalloc(&pdev->dev, sizeof(*power), GFP_KERNEL);
if (!power)
return -ENOMEM;
power->regmap = axp20x->regmap;
/* Enable vbus valid checking */
ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON,
AXP20X_VBUS_MON_VBUS_VALID, AXP20X_VBUS_MON_VBUS_VALID);
if (ret)
return ret;
/* Enable vbus voltage and current measurement */
ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1,
AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT,
AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT);
if (ret)
return ret;
psy_cfg.of_node = pdev->dev.of_node;
psy_cfg.drv_data = power;
power->supply = devm_power_supply_register(&pdev->dev,
&axp20x_usb_power_desc, &psy_cfg);
if (IS_ERR(power->supply))
return PTR_ERR(power->supply);
/* Request irqs after registering, as irqs may trigger immediately */
for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
irq = platform_get_irq_byname(pdev, irq_names[i]);
if (irq < 0) {
dev_warn(&pdev->dev, "No IRQ for %s: %d\n",
irq_names[i], irq);
continue;
}
irq = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
ret = devm_request_any_context_irq(&pdev->dev, irq,
axp20x_usb_power_irq, 0, DRVNAME, power);
if (ret < 0)
dev_warn(&pdev->dev, "Error requesting %s IRQ: %d\n",
irq_names[i], ret);
}
return 0;
}
static const struct of_device_id axp20x_usb_power_match[] = {
{ .compatible = "x-powers,axp202-usb-power-supply" },
{ }
};
MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
static struct platform_driver axp20x_usb_power_driver = {
.probe = axp20x_usb_power_probe,
.driver = {
.name = DRVNAME,
.of_match_table = axp20x_usb_power_match,
},
};
module_platform_driver(axp20x_usb_power_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("AXP20x PMIC USB power supply status driver");
MODULE_LICENSE("GPL");

View file

@ -1704,7 +1704,7 @@ error_4:
error_3:
bq2415x_power_supply_exit(bq);
error_2:
if (bq->notify_node)
if (bq && bq->notify_node)
of_node_put(bq->notify_node);
kfree(name);
error_1:

View file

@ -1543,5 +1543,4 @@ module_i2c_driver(bq24190_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
MODULE_ALIAS("i2c:bq24190-charger");
MODULE_DESCRIPTION("TI BQ24190 Charger Driver");

View file

@ -13,6 +13,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Datasheets:
* http://www.ti.com/product/bq24250
* http://www.ti.com/product/bq24251
* http://www.ti.com/product/bq24257
*/
#include <linux/module.h>
@ -36,18 +40,33 @@
#define BQ24257_REG_7 0x06
#define BQ24257_MANUFACTURER "Texas Instruments"
#define BQ24257_STAT_IRQ "stat"
#define BQ24257_PG_GPIO "pg"
#define BQ24257_ILIM_SET_DELAY 1000 /* msec */
/*
* When adding support for new devices make sure that enum bq2425x_chip and
* bq2425x_chip_name[] always stay in sync!
*/
enum bq2425x_chip {
BQ24250,
BQ24251,
BQ24257,
};
static const char *const bq2425x_chip_name[] = {
"bq24250",
"bq24251",
"bq24257",
};
enum bq24257_fields {
F_WD_FAULT, F_WD_EN, F_STAT, F_FAULT, /* REG 1 */
F_RESET, F_IILIMIT, F_EN_STAT, F_EN_TERM, F_CE, F_HZ_MODE, /* REG 2 */
F_VBAT, F_USB_DET, /* REG 3 */
F_ICHG, F_ITERM, /* REG 4 */
F_LOOP_STATUS, F_LOW_CHG, F_DPDM_EN, F_CE_STATUS, F_VINDPM, /* REG 5 */
F_X2_TMR_EN, F_TMR, F_SYSOFF, F_TS_STAT, /* REG 6 */
F_X2_TMR_EN, F_TMR, F_SYSOFF, F_TS_EN, F_TS_STAT, /* REG 6 */
F_VOVP, F_CLR_VDP, F_FORCE_BATDET, F_FORCE_PTM, /* REG 7 */
F_MAX_FIELDS
@ -58,6 +77,9 @@ struct bq24257_init_data {
u8 ichg; /* charge current */
u8 vbat; /* regulation voltage */
u8 iterm; /* termination current */
u8 iilimit; /* input current limit */
u8 vovp; /* over voltage protection voltage */
u8 vindpm; /* VDMP input threshold voltage */
};
struct bq24257_state {
@ -71,6 +93,8 @@ struct bq24257_device {
struct device *dev;
struct power_supply *charger;
enum bq2425x_chip chip;
struct regmap *rmap;
struct regmap_field *rmap_fields[F_MAX_FIELDS];
@ -82,6 +106,8 @@ struct bq24257_device {
struct bq24257_state state;
struct mutex lock; /* protect state data */
bool iilimit_autoset_enable;
};
static bool bq24257_is_volatile_reg(struct device *dev, unsigned int reg)
@ -135,6 +161,7 @@ static const struct reg_field bq24257_reg_fields[] = {
[F_X2_TMR_EN] = REG_FIELD(BQ24257_REG_6, 7, 7),
[F_TMR] = REG_FIELD(BQ24257_REG_6, 5, 6),
[F_SYSOFF] = REG_FIELD(BQ24257_REG_6, 4, 4),
[F_TS_EN] = REG_FIELD(BQ24257_REG_6, 3, 3),
[F_TS_STAT] = REG_FIELD(BQ24257_REG_6, 0, 2),
/* REG 7 */
[F_VOVP] = REG_FIELD(BQ24257_REG_7, 5, 7),
@ -169,6 +196,26 @@ static const u32 bq24257_iterm_map[] = {
#define BQ24257_ITERM_MAP_SIZE ARRAY_SIZE(bq24257_iterm_map)
static const u32 bq24257_iilimit_map[] = {
100000, 150000, 500000, 900000, 1500000, 2000000
};
#define BQ24257_IILIMIT_MAP_SIZE ARRAY_SIZE(bq24257_iilimit_map)
static const u32 bq24257_vovp_map[] = {
6000000, 6500000, 7000000, 8000000, 9000000, 9500000, 10000000,
10500000
};
#define BQ24257_VOVP_MAP_SIZE ARRAY_SIZE(bq24257_vovp_map)
static const u32 bq24257_vindpm_map[] = {
4200000, 4280000, 4360000, 4440000, 4520000, 4600000, 4680000,
4760000
};
#define BQ24257_VINDPM_MAP_SIZE ARRAY_SIZE(bq24257_vindpm_map)
static int bq24257_field_read(struct bq24257_device *bq,
enum bq24257_fields field_id)
{
@ -220,6 +267,47 @@ enum bq24257_fault {
FAULT_INPUT_LDO_LOW,
};
static int bq24257_get_input_current_limit(struct bq24257_device *bq,
union power_supply_propval *val)
{
int ret;
ret = bq24257_field_read(bq, F_IILIMIT);
if (ret < 0)
return ret;
/*
* The "External ILIM" and "Production & Test" modes are not exposed
* through this driver and not being covered by the lookup table.
* Should such a mode have become active let's return an error rather
* than exceeding the bounds of the lookup table and returning
* garbage.
*/
if (ret >= BQ24257_IILIMIT_MAP_SIZE)
return -ENODATA;
val->intval = bq24257_iilimit_map[ret];
return 0;
}
static int bq24257_set_input_current_limit(struct bq24257_device *bq,
const union power_supply_propval *val)
{
/*
* Address the case where the user manually sets an input current limit
* while the charger auto-detection mechanism is is active. In this
* case we want to abort and go straight to the user-specified value.
*/
if (bq->iilimit_autoset_enable)
cancel_delayed_work_sync(&bq->iilimit_setup_work);
return bq24257_field_write(bq, F_IILIMIT,
bq24257_find_idx(val->intval,
bq24257_iilimit_map,
BQ24257_IILIMIT_MAP_SIZE));
}
static int bq24257_power_supply_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@ -249,6 +337,10 @@ static int bq24257_power_supply_get_property(struct power_supply *psy,
val->strval = BQ24257_MANUFACTURER;
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = bq2425x_chip_name[bq->chip];
break;
case POWER_SUPPLY_PROP_ONLINE:
val->intval = state.power_good;
break;
@ -300,6 +392,9 @@ static int bq24257_power_supply_get_property(struct power_supply *psy,
val->intval = bq24257_iterm_map[bq->init_data.iterm];
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return bq24257_get_input_current_limit(bq, val);
default:
return -EINVAL;
}
@ -307,6 +402,31 @@ static int bq24257_power_supply_get_property(struct power_supply *psy,
return 0;
}
static int bq24257_power_supply_set_property(struct power_supply *psy,
enum power_supply_property prop,
const union power_supply_propval *val)
{
struct bq24257_device *bq = power_supply_get_drvdata(psy);
switch (prop) {
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return bq24257_set_input_current_limit(bq, val);
default:
return -EINVAL;
}
}
static int bq24257_power_supply_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 int bq24257_get_chip_state(struct bq24257_device *bq,
struct bq24257_state *state)
{
@ -324,7 +444,26 @@ static int bq24257_get_chip_state(struct bq24257_device *bq,
state->fault = ret;
state->power_good = !gpiod_get_value_cansleep(bq->pg);
if (bq->pg)
state->power_good = !gpiod_get_value_cansleep(bq->pg);
else
/*
* If we have a chip without a dedicated power-good GPIO or
* some other explicit bit that would provide this information
* assume the power is good if there is no supply related
* fault - and not good otherwise. There is a possibility for
* other errors to mask that power in fact is not good but this
* is probably the best we can do here.
*/
switch (state->fault) {
case FAULT_INPUT_OVP:
case FAULT_INPUT_UVLO:
case FAULT_INPUT_LDO_LOW:
state->power_good = false;
break;
default:
state->power_good = true;
}
return 0;
}
@ -361,6 +500,28 @@ enum bq24257_in_ilimit {
IILIMIT_NONE,
};
enum bq24257_vovp {
VOVP_6000,
VOVP_6500,
VOVP_7000,
VOVP_8000,
VOVP_9000,
VOVP_9500,
VOVP_10000,
VOVP_10500
};
enum bq24257_vindpm {
VINDPM_4200,
VINDPM_4280,
VINDPM_4360,
VINDPM_4440,
VINDPM_4520,
VINDPM_4600,
VINDPM_4680,
VINDPM_4760
};
enum bq24257_port_type {
PORT_TYPE_DCP, /* Dedicated Charging Port */
PORT_TYPE_CDP, /* Charging Downstream Port */
@ -449,41 +610,43 @@ static void bq24257_handle_state_change(struct bq24257_device *bq,
{
int ret;
struct bq24257_state old_state;
bool reset_iilimit = false;
bool config_iilimit = false;
mutex_lock(&bq->lock);
old_state = bq->state;
mutex_unlock(&bq->lock);
if (!new_state->power_good) { /* power removed */
cancel_delayed_work_sync(&bq->iilimit_setup_work);
/*
* Handle BQ2425x state changes observing whether the D+/D- based input
* current limit autoset functionality is enabled.
*/
if (!new_state->power_good) {
dev_dbg(bq->dev, "Power removed\n");
if (bq->iilimit_autoset_enable) {
cancel_delayed_work_sync(&bq->iilimit_setup_work);
/* activate D+/D- port detection algorithm */
ret = bq24257_field_write(bq, F_DPDM_EN, 1);
/* activate D+/D- port detection algorithm */
ret = bq24257_field_write(bq, F_DPDM_EN, 1);
if (ret < 0)
goto error;
}
/*
* When power is removed always return to the default input
* current limit as configured during probe.
*/
ret = bq24257_field_write(bq, F_IILIMIT, bq->init_data.iilimit);
if (ret < 0)
goto error;
} else if (!old_state.power_good) {
dev_dbg(bq->dev, "Power inserted\n");
reset_iilimit = true;
} else if (!old_state.power_good) { /* power inserted */
config_iilimit = true;
} else if (new_state->fault == FAULT_NO_BAT) { /* battery removed */
cancel_delayed_work_sync(&bq->iilimit_setup_work);
reset_iilimit = true;
} else if (old_state.fault == FAULT_NO_BAT) { /* battery connected */
config_iilimit = true;
} else if (new_state->fault == FAULT_TIMER) { /* safety timer expired */
dev_err(bq->dev, "Safety timer expired! Battery dead?\n");
}
if (reset_iilimit) {
ret = bq24257_field_write(bq, F_IILIMIT, IILIMIT_500);
if (ret < 0)
goto error;
} else if (config_iilimit) {
schedule_delayed_work(&bq->iilimit_setup_work,
if (bq->iilimit_autoset_enable)
/* configure input current limit */
schedule_delayed_work(&bq->iilimit_setup_work,
msecs_to_jiffies(BQ24257_ILIM_SET_DELAY));
} else if (new_state->fault == FAULT_NO_BAT) {
dev_warn(bq->dev, "Battery removed\n");
} else if (new_state->fault == FAULT_TIMER) {
dev_err(bq->dev, "Safety timer expired! Battery dead?\n");
}
return;
@ -531,7 +694,9 @@ static int bq24257_hw_init(struct bq24257_device *bq)
} init_data[] = {
{F_ICHG, bq->init_data.ichg},
{F_VBAT, bq->init_data.vbat},
{F_ITERM, bq->init_data.iterm}
{F_ITERM, bq->init_data.iterm},
{F_VOVP, bq->init_data.vovp},
{F_VINDPM, bq->init_data.vindpm},
};
/*
@ -558,7 +723,16 @@ static int bq24257_hw_init(struct bq24257_device *bq)
bq->state = state;
mutex_unlock(&bq->lock);
if (!state.power_good)
if (!bq->iilimit_autoset_enable) {
dev_dbg(bq->dev, "manually setting iilimit = %u\n",
bq->init_data.iilimit);
/* program fixed input current limit */
ret = bq24257_field_write(bq, F_IILIMIT,
bq->init_data.iilimit);
if (ret < 0)
return ret;
} else if (!state.power_good)
/* activate D+/D- detection algorithm */
ret = bq24257_field_write(bq, F_DPDM_EN, 1);
else if (state.fault != FAULT_NO_BAT)
@ -569,6 +743,7 @@ static int bq24257_hw_init(struct bq24257_device *bq)
static enum power_supply_property bq24257_power_supply_props[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_HEALTH,
@ -577,6 +752,7 @@ static enum power_supply_property bq24257_power_supply_props[] = {
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
};
static char *bq24257_charger_supplied_to[] = {
@ -589,6 +765,96 @@ static const struct power_supply_desc bq24257_power_supply_desc = {
.properties = bq24257_power_supply_props,
.num_properties = ARRAY_SIZE(bq24257_power_supply_props),
.get_property = bq24257_power_supply_get_property,
.set_property = bq24257_power_supply_set_property,
.property_is_writeable = bq24257_power_supply_property_is_writeable,
};
static ssize_t bq24257_show_ovp_voltage(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
return scnprintf(buf, PAGE_SIZE, "%u\n",
bq24257_vovp_map[bq->init_data.vovp]);
}
static ssize_t bq24257_show_in_dpm_voltage(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
return scnprintf(buf, PAGE_SIZE, "%u\n",
bq24257_vindpm_map[bq->init_data.vindpm]);
}
static ssize_t bq24257_sysfs_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
int ret;
if (strcmp(attr->attr.name, "high_impedance_enable") == 0)
ret = bq24257_field_read(bq, F_HZ_MODE);
else if (strcmp(attr->attr.name, "sysoff_enable") == 0)
ret = bq24257_field_read(bq, F_SYSOFF);
else
return -EINVAL;
if (ret < 0)
return ret;
return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
}
static ssize_t bq24257_sysfs_set_enable(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct power_supply *psy = dev_get_drvdata(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
long val;
int ret;
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
if (strcmp(attr->attr.name, "high_impedance_enable") == 0)
ret = bq24257_field_write(bq, F_HZ_MODE, (bool)val);
else if (strcmp(attr->attr.name, "sysoff_enable") == 0)
ret = bq24257_field_write(bq, F_SYSOFF, (bool)val);
else
return -EINVAL;
if (ret < 0)
return ret;
return count;
}
static DEVICE_ATTR(ovp_voltage, S_IRUGO, bq24257_show_ovp_voltage, NULL);
static DEVICE_ATTR(in_dpm_voltage, S_IRUGO, bq24257_show_in_dpm_voltage, NULL);
static DEVICE_ATTR(high_impedance_enable, S_IWUSR | S_IRUGO,
bq24257_sysfs_show_enable, bq24257_sysfs_set_enable);
static DEVICE_ATTR(sysoff_enable, S_IWUSR | S_IRUGO,
bq24257_sysfs_show_enable, bq24257_sysfs_set_enable);
static struct attribute *bq24257_charger_attr[] = {
&dev_attr_ovp_voltage.attr,
&dev_attr_in_dpm_voltage.attr,
&dev_attr_high_impedance_enable.attr,
&dev_attr_sysoff_enable.attr,
NULL,
};
static const struct attribute_group bq24257_attr_group = {
.attrs = bq24257_charger_attr,
};
static int bq24257_power_supply_init(struct bq24257_device *bq)
@ -598,36 +864,28 @@ static int bq24257_power_supply_init(struct bq24257_device *bq)
psy_cfg.supplied_to = bq24257_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(bq24257_charger_supplied_to);
bq->charger = power_supply_register(bq->dev, &bq24257_power_supply_desc,
&psy_cfg);
if (IS_ERR(bq->charger))
return PTR_ERR(bq->charger);
bq->charger = devm_power_supply_register(bq->dev,
&bq24257_power_supply_desc,
&psy_cfg);
return 0;
return PTR_ERR_OR_ZERO(bq->charger);
}
static int bq24257_irq_probe(struct bq24257_device *bq)
static void bq24257_pg_gpio_probe(struct bq24257_device *bq)
{
struct gpio_desc *stat_irq;
bq->pg = devm_gpiod_get_optional(bq->dev, BQ24257_PG_GPIO, GPIOD_IN);
stat_irq = devm_gpiod_get_index(bq->dev, BQ24257_STAT_IRQ, 0, GPIOD_IN);
if (IS_ERR(stat_irq)) {
dev_err(bq->dev, "could not probe stat_irq pin\n");
return PTR_ERR(stat_irq);
if (PTR_ERR(bq->pg) == -EPROBE_DEFER) {
dev_info(bq->dev, "probe retry requested for PG pin\n");
return;
} else if (IS_ERR(bq->pg)) {
dev_err(bq->dev, "error probing PG pin\n");
bq->pg = NULL;
return;
}
return gpiod_to_irq(stat_irq);
}
static int bq24257_pg_gpio_probe(struct bq24257_device *bq)
{
bq->pg = devm_gpiod_get_index(bq->dev, BQ24257_PG_GPIO, 0, GPIOD_IN);
if (IS_ERR(bq->pg)) {
dev_err(bq->dev, "could not probe PG pin\n");
return PTR_ERR(bq->pg);
}
return 0;
if (bq->pg)
dev_dbg(bq->dev, "probed PG pin = %d\n", desc_to_gpio(bq->pg));
}
static int bq24257_fw_probe(struct bq24257_device *bq)
@ -635,6 +893,7 @@ static int bq24257_fw_probe(struct bq24257_device *bq)
int ret;
u32 property;
/* Required properties */
ret = device_property_read_u32(bq->dev, "ti,charge-current", &property);
if (ret < 0)
return ret;
@ -658,6 +917,43 @@ static int bq24257_fw_probe(struct bq24257_device *bq)
bq->init_data.iterm = bq24257_find_idx(property, bq24257_iterm_map,
BQ24257_ITERM_MAP_SIZE);
/* Optional properties. If not provided use reasonable default. */
ret = device_property_read_u32(bq->dev, "ti,current-limit",
&property);
if (ret < 0) {
bq->iilimit_autoset_enable = true;
/*
* Explicitly set a default value which will be needed for
* devices that don't support the automatic setting of the input
* current limit through the charger type detection mechanism.
*/
bq->init_data.iilimit = IILIMIT_500;
} else
bq->init_data.iilimit =
bq24257_find_idx(property,
bq24257_iilimit_map,
BQ24257_IILIMIT_MAP_SIZE);
ret = device_property_read_u32(bq->dev, "ti,ovp-voltage",
&property);
if (ret < 0)
bq->init_data.vovp = VOVP_6500;
else
bq->init_data.vovp = bq24257_find_idx(property,
bq24257_vovp_map,
BQ24257_VOVP_MAP_SIZE);
ret = device_property_read_u32(bq->dev, "ti,in-dpm-voltage",
&property);
if (ret < 0)
bq->init_data.vindpm = VINDPM_4360;
else
bq->init_data.vindpm =
bq24257_find_idx(property,
bq24257_vindpm_map,
BQ24257_VINDPM_MAP_SIZE);
return 0;
}
@ -666,6 +962,7 @@ static int bq24257_probe(struct i2c_client *client,
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct device *dev = &client->dev;
const struct acpi_device_id *acpi_id;
struct bq24257_device *bq;
int ret;
int i;
@ -682,6 +979,18 @@ static int bq24257_probe(struct i2c_client *client,
bq->client = client;
bq->dev = dev;
if (ACPI_HANDLE(dev)) {
acpi_id = acpi_match_device(dev->driver->acpi_match_table,
&client->dev);
if (!acpi_id) {
dev_err(dev, "Failed to match ACPI device\n");
return -ENODEV;
}
bq->chip = (enum bq2425x_chip)acpi_id->driver_data;
} else {
bq->chip = (enum bq2425x_chip)id->driver_data;
}
mutex_init(&bq->lock);
bq->rmap = devm_regmap_init_i2c(client, &bq24257_regmap_config);
@ -703,8 +1012,6 @@ static int bq24257_probe(struct i2c_client *client,
i2c_set_clientdata(client, bq);
INIT_DELAYED_WORK(&bq->iilimit_setup_work, bq24257_iilimit_setup_work);
if (!dev->platform_data) {
ret = bq24257_fw_probe(bq);
if (ret < 0) {
@ -715,10 +1022,31 @@ static int bq24257_probe(struct i2c_client *client,
return -ENODEV;
}
/* we can only check Power Good status by probing the PG pin */
ret = bq24257_pg_gpio_probe(bq);
if (ret < 0)
return ret;
/*
* The BQ24250 doesn't support the D+/D- based charger type detection
* used for the automatic setting of the input current limit setting so
* explicitly disable that feature.
*/
if (bq->chip == BQ24250)
bq->iilimit_autoset_enable = false;
if (bq->iilimit_autoset_enable)
INIT_DELAYED_WORK(&bq->iilimit_setup_work,
bq24257_iilimit_setup_work);
/*
* The BQ24250 doesn't have a dedicated Power Good (PG) pin so let's
* not probe for it and instead use a SW-based approach to determine
* the PG state. We also use a SW-based approach for all other devices
* if the PG pin is either not defined or can't be probed.
*/
if (bq->chip != BQ24250)
bq24257_pg_gpio_probe(bq);
if (PTR_ERR(bq->pg) == -EPROBE_DEFER)
return PTR_ERR(bq->pg);
else if (!bq->pg)
dev_info(bq->dev, "using SW-based power-good detection\n");
/* reset all registers to defaults */
ret = bq24257_field_write(bq, F_RESET, 1);
@ -740,36 +1068,39 @@ static int bq24257_probe(struct i2c_client *client,
return ret;
}
if (client->irq <= 0)
client->irq = bq24257_irq_probe(bq);
if (client->irq < 0) {
dev_err(dev, "no irq resource found\n");
return client->irq;
}
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq24257_irq_handler_thread,
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
BQ24257_STAT_IRQ, bq);
if (ret)
bq2425x_chip_name[bq->chip], bq);
if (ret) {
dev_err(dev, "Failed to request IRQ #%d\n", client->irq);
return ret;
}
ret = bq24257_power_supply_init(bq);
if (ret < 0)
if (ret < 0) {
dev_err(dev, "Failed to register power supply\n");
return ret;
}
return ret;
ret = sysfs_create_group(&bq->charger->dev.kobj, &bq24257_attr_group);
if (ret < 0) {
dev_err(dev, "Can't create sysfs entries\n");
return ret;
}
return 0;
}
static int bq24257_remove(struct i2c_client *client)
{
struct bq24257_device *bq = i2c_get_clientdata(client);
cancel_delayed_work_sync(&bq->iilimit_setup_work);
if (bq->iilimit_autoset_enable)
cancel_delayed_work_sync(&bq->iilimit_setup_work);
power_supply_unregister(bq->charger);
sysfs_remove_group(&bq->charger->dev.kobj, &bq24257_attr_group);
bq24257_field_write(bq, F_RESET, 1); /* reset to defaults */
@ -782,7 +1113,8 @@ static int bq24257_suspend(struct device *dev)
struct bq24257_device *bq = dev_get_drvdata(dev);
int ret = 0;
cancel_delayed_work_sync(&bq->iilimit_setup_work);
if (bq->iilimit_autoset_enable)
cancel_delayed_work_sync(&bq->iilimit_setup_work);
/* reset all registers to default (and activate standalone mode) */
ret = bq24257_field_write(bq, F_RESET, 1);
@ -823,19 +1155,25 @@ static const struct dev_pm_ops bq24257_pm = {
};
static const struct i2c_device_id bq24257_i2c_ids[] = {
{ "bq24257", 0 },
{ "bq24250", BQ24250 },
{ "bq24251", BQ24251 },
{ "bq24257", BQ24257 },
{},
};
MODULE_DEVICE_TABLE(i2c, bq24257_i2c_ids);
static const struct of_device_id bq24257_of_match[] = {
{ .compatible = "ti,bq24250", },
{ .compatible = "ti,bq24251", },
{ .compatible = "ti,bq24257", },
{ },
};
MODULE_DEVICE_TABLE(of, bq24257_of_match);
static const struct acpi_device_id bq24257_acpi_match[] = {
{"BQ242570", 0},
{ "BQ242500", BQ24250 },
{ "BQ242510", BQ24251 },
{ "BQ242570", BQ24257 },
{},
};
MODULE_DEVICE_TABLE(acpi, bq24257_acpi_match);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1581,8 +1581,10 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
cables = devm_kzalloc(dev, sizeof(*cables)
* chg_regs->num_cables,
GFP_KERNEL);
if (!cables)
if (!cables) {
of_node_put(child);
return ERR_PTR(-ENOMEM);
}
chg_regs->cables = cables;

View file

@ -508,23 +508,23 @@ out:
return param;
}
static int lp8727_parse_dt(struct device *dev)
static struct lp8727_platform_data *lp8727_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
struct device_node *child;
struct lp8727_platform_data *pdata;
const char *type;
/* If charging parameter is not defined, just skip parsing the dt */
if (of_get_child_count(np) == 0)
goto out;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
of_property_read_u32(np, "debounce-ms", &pdata->debounce_msec);
/* If charging parameter is not defined, just skip parsing the dt */
if (of_get_child_count(np) == 0)
return pdata;
for_each_child_of_node(np, child) {
of_property_read_string(child, "charger-type", &type);
@ -535,29 +535,30 @@ static int lp8727_parse_dt(struct device *dev)
pdata->usb = lp8727_parse_charge_pdata(dev, child);
}
dev->platform_data = pdata;
out:
return 0;
return pdata;
}
#else
static int lp8727_parse_dt(struct device *dev)
static struct lp8727_platform_data *lp8727_parse_dt(struct device *dev)
{
return 0;
return NULL;
}
#endif
static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
struct lp8727_chg *pchg;
struct lp8727_platform_data *pdata;
int ret;
if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
if (cl->dev.of_node) {
ret = lp8727_parse_dt(&cl->dev);
if (ret)
return ret;
pdata = lp8727_parse_dt(&cl->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
} else {
pdata = dev_get_platdata(&cl->dev);
}
pchg = devm_kzalloc(&cl->dev, sizeof(*pchg), GFP_KERNEL);
@ -566,7 +567,7 @@ static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id)
pchg->client = cl;
pchg->dev = &cl->dev;
pchg->pdata = cl->dev.platform_data;
pchg->pdata = pdata;
i2c_set_clientdata(cl, pchg);
mutex_init(&pchg->xfer_lock);

Some files were not shown because too many files have changed in this diff Show more