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:
commit
400c5bd5a5
39 changed files with 3822 additions and 1478 deletions
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
};
|
131
Documentation/devicetree/bindings/power_supply/qcom_smbb.txt
Normal file
131
Documentation/devicetree/bindings/power_supply/qcom_smbb.txt
Normal 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>;
|
||||
};
|
|
@ -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";
|
||||
};
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
248
drivers/power/axp20x_usb_power.c
Normal file
248
drivers/power/axp20x_usb_power.c
Normal 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");
|
|
@ -1704,7 +1704,7 @@ static int bq2415x_probe(struct i2c_client *client,
|
|||
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:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
1375
drivers/power/bq27xxx_battery.c
Normal file
1375
drivers/power/bq27xxx_battery.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
||||
|
|
|
@ -508,23 +508,23 @@ static struct lp8727_chg_param
|
|||
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);
|
||||
|
|
|
@ -909,18 +909,21 @@ static int max17042_probe(struct i2c_client *client,
|
|||
regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007);
|
||||
}
|
||||
|
||||
chip->battery = power_supply_register(&client->dev, max17042_desc,
|
||||
&psy_cfg);
|
||||
chip->battery = devm_power_supply_register(&client->dev, max17042_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(chip->battery)) {
|
||||
dev_err(&client->dev, "failed: power supply register\n");
|
||||
return PTR_ERR(chip->battery);
|
||||
}
|
||||
|
||||
if (client->irq) {
|
||||
ret = request_threaded_irq(client->irq, NULL,
|
||||
max17042_thread_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
chip->battery->desc->name, chip);
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL,
|
||||
max17042_thread_handler,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT,
|
||||
chip->battery->desc->name,
|
||||
chip);
|
||||
if (!ret) {
|
||||
regmap_update_bits(chip->regmap, MAX17042_CONFIG,
|
||||
CONFIG_ALRT_BIT_ENBL,
|
||||
|
@ -944,16 +947,6 @@ static int max17042_probe(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int max17042_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max17042_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (client->irq)
|
||||
free_irq(client->irq, chip);
|
||||
power_supply_unregister(chip->battery);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int max17042_suspend(struct device *dev)
|
||||
{
|
||||
|
@ -1014,7 +1007,6 @@ static struct i2c_driver max17042_i2c_driver = {
|
|||
.pm = &max17042_pm_ops,
|
||||
},
|
||||
.probe = max17042_probe,
|
||||
.remove = max17042_remove,
|
||||
.id_table = max17042_id,
|
||||
};
|
||||
module_i2c_driver(max17042_i2c_driver);
|
||||
|
|
|
@ -201,8 +201,7 @@ static int max8903_probe(struct platform_device *pdev)
|
|||
|
||||
if (pdata->dc_valid == false && pdata->usb_valid == false) {
|
||||
dev_err(dev, "No valid power sources.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->dc_valid) {
|
||||
|
@ -216,8 +215,7 @@ static int max8903_probe(struct platform_device *pdev)
|
|||
} else {
|
||||
dev_err(dev, "When DC is wired, DOK and DCM should"
|
||||
" be wired as well.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (pdata->dcm) {
|
||||
|
@ -225,8 +223,7 @@ static int max8903_probe(struct platform_device *pdev)
|
|||
gpio_set_value(pdata->dcm, 0);
|
||||
else {
|
||||
dev_err(dev, "Invalid pin: dcm.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,8 +235,7 @@ static int max8903_probe(struct platform_device *pdev)
|
|||
} else {
|
||||
dev_err(dev, "When USB is wired, UOK should be wired."
|
||||
"as well.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,32 +244,28 @@ static int max8903_probe(struct platform_device *pdev)
|
|||
gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1);
|
||||
} else {
|
||||
dev_err(dev, "Invalid pin: cen.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->chg) {
|
||||
if (!gpio_is_valid(pdata->chg)) {
|
||||
dev_err(dev, "Invalid pin: chg.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->flt) {
|
||||
if (!gpio_is_valid(pdata->flt)) {
|
||||
dev_err(dev, "Invalid pin: flt.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->usus) {
|
||||
if (!gpio_is_valid(pdata->usus)) {
|
||||
dev_err(dev, "Invalid pin: usus.\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,85 +283,56 @@ static int max8903_probe(struct platform_device *pdev)
|
|||
|
||||
psy_cfg.drv_data = data;
|
||||
|
||||
data->psy = power_supply_register(dev, &data->psy_desc, &psy_cfg);
|
||||
data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg);
|
||||
if (IS_ERR(data->psy)) {
|
||||
dev_err(dev, "failed: power supply register.\n");
|
||||
ret = PTR_ERR(data->psy);
|
||||
goto err;
|
||||
return PTR_ERR(data->psy);
|
||||
}
|
||||
|
||||
if (pdata->dc_valid) {
|
||||
ret = request_threaded_irq(gpio_to_irq(pdata->dok),
|
||||
NULL, max8903_dcin,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
"MAX8903 DC IN", data);
|
||||
ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->dok),
|
||||
NULL, max8903_dcin,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_TRIGGER_RISING,
|
||||
"MAX8903 DC IN", data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot request irq %d for DC (%d)\n",
|
||||
gpio_to_irq(pdata->dok), ret);
|
||||
goto err_psy;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->usb_valid) {
|
||||
ret = request_threaded_irq(gpio_to_irq(pdata->uok),
|
||||
NULL, max8903_usbin,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
"MAX8903 USB IN", data);
|
||||
ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->uok),
|
||||
NULL, max8903_usbin,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_TRIGGER_RISING,
|
||||
"MAX8903 USB IN", data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot request irq %d for USB (%d)\n",
|
||||
gpio_to_irq(pdata->uok), ret);
|
||||
goto err_dc_irq;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->flt) {
|
||||
ret = request_threaded_irq(gpio_to_irq(pdata->flt),
|
||||
NULL, max8903_fault,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
"MAX8903 Fault", data);
|
||||
ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt),
|
||||
NULL, max8903_fault,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_TRIGGER_RISING,
|
||||
"MAX8903 Fault", data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
|
||||
gpio_to_irq(pdata->flt), ret);
|
||||
goto err_usb_irq;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_usb_irq:
|
||||
if (pdata->usb_valid)
|
||||
free_irq(gpio_to_irq(pdata->uok), data);
|
||||
err_dc_irq:
|
||||
if (pdata->dc_valid)
|
||||
free_irq(gpio_to_irq(pdata->dok), data);
|
||||
err_psy:
|
||||
power_supply_unregister(data->psy);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8903_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max8903_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
if (data) {
|
||||
struct max8903_pdata *pdata = &data->pdata;
|
||||
|
||||
if (pdata->flt)
|
||||
free_irq(gpio_to_irq(pdata->flt), data);
|
||||
if (pdata->usb_valid)
|
||||
free_irq(gpio_to_irq(pdata->uok), data);
|
||||
if (pdata->dc_valid)
|
||||
free_irq(gpio_to_irq(pdata->dok), data);
|
||||
power_supply_unregister(data->psy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver max8903_driver = {
|
||||
.probe = max8903_probe,
|
||||
.remove = max8903_remove,
|
||||
.driver = {
|
||||
.name = "max8903-charger",
|
||||
},
|
||||
|
|
|
@ -117,8 +117,7 @@ static int max8998_battery_probe(struct platform_device *pdev)
|
|||
"EOC value not set: leave it unchanged.\n");
|
||||
} else {
|
||||
dev_err(max8998->dev, "Invalid EOC value\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Setup Charge Restart Level */
|
||||
|
@ -141,8 +140,7 @@ static int max8998_battery_probe(struct platform_device *pdev)
|
|||
break;
|
||||
default:
|
||||
dev_err(max8998->dev, "Invalid Restart Level\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Setup Charge Full Timeout */
|
||||
|
@ -165,33 +163,21 @@ static int max8998_battery_probe(struct platform_device *pdev)
|
|||
break;
|
||||
default:
|
||||
dev_err(max8998->dev, "Invalid Full Timeout value\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
psy_cfg.drv_data = max8998;
|
||||
|
||||
max8998->battery = power_supply_register(max8998->dev,
|
||||
&max8998_battery_desc,
|
||||
&psy_cfg);
|
||||
max8998->battery = devm_power_supply_register(max8998->dev,
|
||||
&max8998_battery_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(max8998->battery)) {
|
||||
ret = PTR_ERR(max8998->battery);
|
||||
dev_err(max8998->dev, "failed: power supply register: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max8998_battery_data *max8998 = platform_get_drvdata(pdev);
|
||||
|
||||
power_supply_unregister(max8998->battery);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -205,7 +191,6 @@ static struct platform_driver max8998_battery_driver = {
|
|||
.name = "max8998-battery",
|
||||
},
|
||||
.probe = max8998_battery_probe,
|
||||
.remove = max8998_battery_remove,
|
||||
.id_table = max8998_battery_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -1264,5 +1264,4 @@ module_exit(pm2xxx_charger_exit);
|
|||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
|
||||
MODULE_ALIAS("i2c:pm2xxx-charger");
|
||||
MODULE_DESCRIPTION("PM2xxx charger management driver");
|
||||
|
|
951
drivers/power/qcom_smbb.c
Normal file
951
drivers/power/qcom_smbb.c
Normal file
|
@ -0,0 +1,951 @@
|
|||
/* Copyright (c) 2014, Sony Mobile Communications Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver is for the multi-block Switch-Mode Battery Charger and Boost
|
||||
* (SMBB) hardware, found in Qualcomm PM8941 PMICs. The charger is an
|
||||
* integrated, single-cell lithium-ion battery charger.
|
||||
*
|
||||
* Sub-components:
|
||||
* - Charger core
|
||||
* - Buck
|
||||
* - DC charge-path
|
||||
* - USB charge-path
|
||||
* - Battery interface
|
||||
* - Boost (not implemented)
|
||||
* - Misc
|
||||
* - HF-Buck
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define SMBB_CHG_VMAX 0x040
|
||||
#define SMBB_CHG_VSAFE 0x041
|
||||
#define SMBB_CHG_CFG 0x043
|
||||
#define SMBB_CHG_IMAX 0x044
|
||||
#define SMBB_CHG_ISAFE 0x045
|
||||
#define SMBB_CHG_VIN_MIN 0x047
|
||||
#define SMBB_CHG_CTRL 0x049
|
||||
#define CTRL_EN BIT(7)
|
||||
#define SMBB_CHG_VBAT_WEAK 0x052
|
||||
#define SMBB_CHG_IBAT_TERM_CHG 0x05b
|
||||
#define IBAT_TERM_CHG_IEOC BIT(7)
|
||||
#define IBAT_TERM_CHG_IEOC_BMS BIT(7)
|
||||
#define IBAT_TERM_CHG_IEOC_CHG 0
|
||||
#define SMBB_CHG_VBAT_DET 0x05d
|
||||
#define SMBB_CHG_TCHG_MAX_EN 0x060
|
||||
#define TCHG_MAX_EN BIT(7)
|
||||
#define SMBB_CHG_WDOG_TIME 0x062
|
||||
#define SMBB_CHG_WDOG_EN 0x065
|
||||
#define WDOG_EN BIT(7)
|
||||
|
||||
#define SMBB_BUCK_REG_MODE 0x174
|
||||
#define BUCK_REG_MODE BIT(0)
|
||||
#define BUCK_REG_MODE_VBAT BIT(0)
|
||||
#define BUCK_REG_MODE_VSYS 0
|
||||
|
||||
#define SMBB_BAT_PRES_STATUS 0x208
|
||||
#define PRES_STATUS_BAT_PRES BIT(7)
|
||||
#define SMBB_BAT_TEMP_STATUS 0x209
|
||||
#define TEMP_STATUS_OK BIT(7)
|
||||
#define TEMP_STATUS_HOT BIT(6)
|
||||
#define SMBB_BAT_BTC_CTRL 0x249
|
||||
#define BTC_CTRL_COMP_EN BIT(7)
|
||||
#define BTC_CTRL_COLD_EXT BIT(1)
|
||||
#define BTC_CTRL_HOT_EXT_N BIT(0)
|
||||
|
||||
#define SMBB_USB_IMAX 0x344
|
||||
#define SMBB_USB_ENUM_TIMER_STOP 0x34e
|
||||
#define ENUM_TIMER_STOP BIT(0)
|
||||
#define SMBB_USB_SEC_ACCESS 0x3d0
|
||||
#define SEC_ACCESS_MAGIC 0xa5
|
||||
#define SMBB_USB_REV_BST 0x3ed
|
||||
#define REV_BST_CHG_GONE BIT(7)
|
||||
|
||||
#define SMBB_DC_IMAX 0x444
|
||||
|
||||
#define SMBB_MISC_REV2 0x601
|
||||
#define SMBB_MISC_BOOT_DONE 0x642
|
||||
#define BOOT_DONE BIT(7)
|
||||
|
||||
#define STATUS_USBIN_VALID BIT(0) /* USB connection is valid */
|
||||
#define STATUS_DCIN_VALID BIT(1) /* DC connection is valid */
|
||||
#define STATUS_BAT_HOT BIT(2) /* Battery temp 1=Hot, 0=Cold */
|
||||
#define STATUS_BAT_OK BIT(3) /* Battery temp OK */
|
||||
#define STATUS_BAT_PRESENT BIT(4) /* Battery is present */
|
||||
#define STATUS_CHG_DONE BIT(5) /* Charge cycle is complete */
|
||||
#define STATUS_CHG_TRKL BIT(6) /* Trickle charging */
|
||||
#define STATUS_CHG_FAST BIT(7) /* Fast charging */
|
||||
#define STATUS_CHG_GONE BIT(8) /* No charger is connected */
|
||||
|
||||
enum smbb_attr {
|
||||
ATTR_BAT_ISAFE,
|
||||
ATTR_BAT_IMAX,
|
||||
ATTR_USBIN_IMAX,
|
||||
ATTR_DCIN_IMAX,
|
||||
ATTR_BAT_VSAFE,
|
||||
ATTR_BAT_VMAX,
|
||||
ATTR_BAT_VMIN,
|
||||
ATTR_CHG_VDET,
|
||||
ATTR_VIN_MIN,
|
||||
_ATTR_CNT,
|
||||
};
|
||||
|
||||
struct smbb_charger {
|
||||
unsigned int revision;
|
||||
unsigned int addr;
|
||||
struct device *dev;
|
||||
|
||||
bool dc_disabled;
|
||||
bool jeita_ext_temp;
|
||||
unsigned long status;
|
||||
struct mutex statlock;
|
||||
|
||||
unsigned int attr[_ATTR_CNT];
|
||||
|
||||
struct power_supply *usb_psy;
|
||||
struct power_supply *dc_psy;
|
||||
struct power_supply *bat_psy;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int smbb_vbat_weak_fn(unsigned int index)
|
||||
{
|
||||
return 2100000 + index * 100000;
|
||||
}
|
||||
|
||||
static int smbb_vin_fn(unsigned int index)
|
||||
{
|
||||
if (index > 42)
|
||||
return 5600000 + (index - 43) * 200000;
|
||||
return 3400000 + index * 50000;
|
||||
}
|
||||
|
||||
static int smbb_vmax_fn(unsigned int index)
|
||||
{
|
||||
return 3240000 + index * 10000;
|
||||
}
|
||||
|
||||
static int smbb_vbat_det_fn(unsigned int index)
|
||||
{
|
||||
return 3240000 + index * 20000;
|
||||
}
|
||||
|
||||
static int smbb_imax_fn(unsigned int index)
|
||||
{
|
||||
if (index < 2)
|
||||
return 100000 + index * 50000;
|
||||
return index * 100000;
|
||||
}
|
||||
|
||||
static int smbb_bat_imax_fn(unsigned int index)
|
||||
{
|
||||
return index * 50000;
|
||||
}
|
||||
|
||||
static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int))
|
||||
{
|
||||
unsigned int widx;
|
||||
unsigned int sel;
|
||||
|
||||
for (widx = sel = 0; (*fn)(widx) <= val; ++widx)
|
||||
sel = widx;
|
||||
|
||||
return sel;
|
||||
}
|
||||
|
||||
static const struct smbb_charger_attr {
|
||||
const char *name;
|
||||
unsigned int reg;
|
||||
unsigned int safe_reg;
|
||||
unsigned int max;
|
||||
unsigned int min;
|
||||
unsigned int fail_ok;
|
||||
int (*hw_fn)(unsigned int);
|
||||
} smbb_charger_attrs[] = {
|
||||
[ATTR_BAT_ISAFE] = {
|
||||
.name = "qcom,fast-charge-safe-current",
|
||||
.reg = SMBB_CHG_ISAFE,
|
||||
.max = 3000000,
|
||||
.min = 200000,
|
||||
.hw_fn = smbb_bat_imax_fn,
|
||||
.fail_ok = 1,
|
||||
},
|
||||
[ATTR_BAT_IMAX] = {
|
||||
.name = "qcom,fast-charge-current-limit",
|
||||
.reg = SMBB_CHG_IMAX,
|
||||
.safe_reg = SMBB_CHG_ISAFE,
|
||||
.max = 3000000,
|
||||
.min = 200000,
|
||||
.hw_fn = smbb_bat_imax_fn,
|
||||
},
|
||||
[ATTR_DCIN_IMAX] = {
|
||||
.name = "qcom,dc-current-limit",
|
||||
.reg = SMBB_DC_IMAX,
|
||||
.max = 2500000,
|
||||
.min = 100000,
|
||||
.hw_fn = smbb_imax_fn,
|
||||
},
|
||||
[ATTR_BAT_VSAFE] = {
|
||||
.name = "qcom,fast-charge-safe-voltage",
|
||||
.reg = SMBB_CHG_VSAFE,
|
||||
.max = 5000000,
|
||||
.min = 3240000,
|
||||
.hw_fn = smbb_vmax_fn,
|
||||
.fail_ok = 1,
|
||||
},
|
||||
[ATTR_BAT_VMAX] = {
|
||||
.name = "qcom,fast-charge-high-threshold-voltage",
|
||||
.reg = SMBB_CHG_VMAX,
|
||||
.safe_reg = SMBB_CHG_VSAFE,
|
||||
.max = 5000000,
|
||||
.min = 3240000,
|
||||
.hw_fn = smbb_vmax_fn,
|
||||
},
|
||||
[ATTR_BAT_VMIN] = {
|
||||
.name = "qcom,fast-charge-low-threshold-voltage",
|
||||
.reg = SMBB_CHG_VBAT_WEAK,
|
||||
.max = 3600000,
|
||||
.min = 2100000,
|
||||
.hw_fn = smbb_vbat_weak_fn,
|
||||
},
|
||||
[ATTR_CHG_VDET] = {
|
||||
.name = "qcom,auto-recharge-threshold-voltage",
|
||||
.reg = SMBB_CHG_VBAT_DET,
|
||||
.max = 5000000,
|
||||
.min = 3240000,
|
||||
.hw_fn = smbb_vbat_det_fn,
|
||||
},
|
||||
[ATTR_VIN_MIN] = {
|
||||
.name = "qcom,minimum-input-voltage",
|
||||
.reg = SMBB_CHG_VIN_MIN,
|
||||
.max = 9600000,
|
||||
.min = 4200000,
|
||||
.hw_fn = smbb_vin_fn,
|
||||
},
|
||||
[ATTR_USBIN_IMAX] = {
|
||||
.name = "usb-charge-current-limit",
|
||||
.reg = SMBB_USB_IMAX,
|
||||
.max = 2500000,
|
||||
.min = 100000,
|
||||
.hw_fn = smbb_imax_fn,
|
||||
},
|
||||
};
|
||||
|
||||
static int smbb_charger_attr_write(struct smbb_charger *chg,
|
||||
enum smbb_attr which, unsigned int val)
|
||||
{
|
||||
const struct smbb_charger_attr *prop;
|
||||
unsigned int wval;
|
||||
unsigned int out;
|
||||
int rc;
|
||||
|
||||
prop = &smbb_charger_attrs[which];
|
||||
|
||||
if (val > prop->max || val < prop->min) {
|
||||
dev_err(chg->dev, "value out of range for %s [%u:%u]\n",
|
||||
prop->name, prop->min, prop->max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prop->safe_reg) {
|
||||
rc = regmap_read(chg->regmap,
|
||||
chg->addr + prop->safe_reg, &wval);
|
||||
if (rc) {
|
||||
dev_err(chg->dev,
|
||||
"unable to read safe value for '%s'\n",
|
||||
prop->name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wval = prop->hw_fn(wval);
|
||||
|
||||
if (val > wval) {
|
||||
dev_warn(chg->dev,
|
||||
"%s above safe value, clamping at %u\n",
|
||||
prop->name, wval);
|
||||
val = wval;
|
||||
}
|
||||
}
|
||||
|
||||
wval = smbb_hw_lookup(val, prop->hw_fn);
|
||||
|
||||
rc = regmap_write(chg->regmap, chg->addr + prop->reg, wval);
|
||||
if (rc) {
|
||||
dev_err(chg->dev, "unable to update %s", prop->name);
|
||||
return rc;
|
||||
}
|
||||
out = prop->hw_fn(wval);
|
||||
if (out != val) {
|
||||
dev_warn(chg->dev,
|
||||
"%s inaccurate, rounded to %u\n",
|
||||
prop->name, out);
|
||||
}
|
||||
|
||||
dev_dbg(chg->dev, "%s <= %d\n", prop->name, out);
|
||||
|
||||
chg->attr[which] = out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbb_charger_attr_read(struct smbb_charger *chg,
|
||||
enum smbb_attr which)
|
||||
{
|
||||
const struct smbb_charger_attr *prop;
|
||||
unsigned int val;
|
||||
int rc;
|
||||
|
||||
prop = &smbb_charger_attrs[which];
|
||||
|
||||
rc = regmap_read(chg->regmap, chg->addr + prop->reg, &val);
|
||||
if (rc) {
|
||||
dev_err(chg->dev, "failed to read %s\n", prop->name);
|
||||
return rc;
|
||||
}
|
||||
val = prop->hw_fn(val);
|
||||
dev_dbg(chg->dev, "%s => %d\n", prop->name, val);
|
||||
|
||||
chg->attr[which] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbb_charger_attr_parse(struct smbb_charger *chg,
|
||||
enum smbb_attr which)
|
||||
{
|
||||
const struct smbb_charger_attr *prop;
|
||||
unsigned int val;
|
||||
int rc;
|
||||
|
||||
prop = &smbb_charger_attrs[which];
|
||||
|
||||
rc = of_property_read_u32(chg->dev->of_node, prop->name, &val);
|
||||
if (rc == 0) {
|
||||
rc = smbb_charger_attr_write(chg, which, val);
|
||||
if (!rc || !prop->fail_ok)
|
||||
return rc;
|
||||
}
|
||||
return smbb_charger_attr_read(chg, which);
|
||||
}
|
||||
|
||||
static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag)
|
||||
{
|
||||
bool state;
|
||||
int ret;
|
||||
|
||||
ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, &state);
|
||||
if (ret < 0) {
|
||||
dev_err(chg->dev, "failed to read irq line\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&chg->statlock);
|
||||
if (state)
|
||||
chg->status |= flag;
|
||||
else
|
||||
chg->status &= ~flag;
|
||||
mutex_unlock(&chg->statlock);
|
||||
|
||||
dev_dbg(chg->dev, "status = %03lx\n", chg->status);
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_usb_valid_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
|
||||
smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID);
|
||||
power_supply_changed(chg->usb_psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_dc_valid_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
|
||||
smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID);
|
||||
if (!chg->dc_disabled)
|
||||
power_supply_changed(chg->dc_psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_bat_temp_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
unsigned int val;
|
||||
int rc;
|
||||
|
||||
rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val);
|
||||
if (rc)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
mutex_lock(&chg->statlock);
|
||||
if (val & TEMP_STATUS_OK) {
|
||||
chg->status |= STATUS_BAT_OK;
|
||||
} else {
|
||||
chg->status &= ~STATUS_BAT_OK;
|
||||
if (val & TEMP_STATUS_HOT)
|
||||
chg->status |= STATUS_BAT_HOT;
|
||||
}
|
||||
mutex_unlock(&chg->statlock);
|
||||
|
||||
power_supply_changed(chg->bat_psy);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_bat_present_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
|
||||
smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT);
|
||||
power_supply_changed(chg->bat_psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_chg_done_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
|
||||
smbb_set_line_flag(chg, irq, STATUS_CHG_DONE);
|
||||
power_supply_changed(chg->bat_psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_chg_gone_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
|
||||
smbb_set_line_flag(chg, irq, STATUS_CHG_GONE);
|
||||
power_supply_changed(chg->bat_psy);
|
||||
power_supply_changed(chg->usb_psy);
|
||||
if (!chg->dc_disabled)
|
||||
power_supply_changed(chg->dc_psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_chg_fast_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
|
||||
smbb_set_line_flag(chg, irq, STATUS_CHG_FAST);
|
||||
power_supply_changed(chg->bat_psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data)
|
||||
{
|
||||
struct smbb_charger *chg = _data;
|
||||
|
||||
smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL);
|
||||
power_supply_changed(chg->bat_psy);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct smbb_irq {
|
||||
const char *name;
|
||||
irqreturn_t (*handler)(int, void *);
|
||||
} smbb_charger_irqs[] = {
|
||||
{ "chg-done", smbb_chg_done_handler },
|
||||
{ "chg-fast", smbb_chg_fast_handler },
|
||||
{ "chg-trkl", smbb_chg_trkl_handler },
|
||||
{ "bat-temp-ok", smbb_bat_temp_handler },
|
||||
{ "bat-present", smbb_bat_present_handler },
|
||||
{ "chg-gone", smbb_chg_gone_handler },
|
||||
{ "usb-valid", smbb_usb_valid_handler },
|
||||
{ "dc-valid", smbb_dc_valid_handler },
|
||||
};
|
||||
|
||||
static int smbb_usbin_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct smbb_charger *chg = power_supply_get_drvdata(psy);
|
||||
int rc = 0;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
mutex_lock(&chg->statlock);
|
||||
val->intval = !(chg->status & STATUS_CHG_GONE) &&
|
||||
(chg->status & STATUS_USBIN_VALID);
|
||||
mutex_unlock(&chg->statlock);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
||||
val->intval = chg->attr[ATTR_USBIN_IMAX];
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
|
||||
val->intval = 2500000;
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smbb_usbin_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct smbb_charger *chg = power_supply_get_drvdata(psy);
|
||||
int rc;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
||||
rc = smbb_charger_attr_write(chg, ATTR_USBIN_IMAX,
|
||||
val->intval);
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smbb_dcin_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct smbb_charger *chg = power_supply_get_drvdata(psy);
|
||||
int rc = 0;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
mutex_lock(&chg->statlock);
|
||||
val->intval = !(chg->status & STATUS_CHG_GONE) &&
|
||||
(chg->status & STATUS_DCIN_VALID);
|
||||
mutex_unlock(&chg->statlock);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
||||
val->intval = chg->attr[ATTR_DCIN_IMAX];
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
|
||||
val->intval = 2500000;
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smbb_dcin_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct smbb_charger *chg = power_supply_get_drvdata(psy);
|
||||
int rc;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
||||
rc = smbb_charger_attr_write(chg, ATTR_DCIN_IMAX,
|
||||
val->intval);
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smbb_charger_writable_property(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT;
|
||||
}
|
||||
|
||||
static int smbb_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct smbb_charger *chg = power_supply_get_drvdata(psy);
|
||||
unsigned long status;
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&chg->statlock);
|
||||
status = chg->status;
|
||||
mutex_unlock(&chg->statlock);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (status & STATUS_CHG_GONE)
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else if (!(status & (STATUS_DCIN_VALID | STATUS_USBIN_VALID)))
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else if (status & STATUS_CHG_DONE)
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else if (!(status & STATUS_BAT_OK))
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else if (status & (STATUS_CHG_FAST | STATUS_CHG_TRKL))
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else /* everything is ok for charging, but we are not... */
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
if (status & STATUS_BAT_OK)
|
||||
val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
||||
else if (status & STATUS_BAT_HOT)
|
||||
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_HEALTH_COLD;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
if (status & STATUS_CHG_FAST)
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
|
||||
else if (status & STATUS_CHG_TRKL)
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = !!(status & STATUS_BAT_PRESENT);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
val->intval = chg->attr[ATTR_BAT_IMAX];
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
|
||||
val->intval = chg->attr[ATTR_BAT_VMAX];
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
/* this charger is a single-cell lithium-ion battery charger
|
||||
* only. If you hook up some other technology, there will be
|
||||
* fireworks.
|
||||
*/
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
|
||||
val->intval = 3000000; /* single-cell li-ion low end */
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smbb_battery_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct smbb_charger *chg = power_supply_get_drvdata(psy);
|
||||
int rc;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
rc = smbb_charger_attr_write(chg, ATTR_BAT_IMAX, val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
|
||||
rc = smbb_charger_attr_write(chg, ATTR_BAT_VMAX, val->intval);
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smbb_battery_writable_property(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static enum power_supply_property smbb_charger_properties[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
|
||||
};
|
||||
|
||||
static enum power_supply_property smbb_battery_properties[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_CHARGE_TYPE,
|
||||
POWER_SUPPLY_PROP_CURRENT_MAX,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MAX,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
};
|
||||
|
||||
static const struct reg_off_mask_default {
|
||||
unsigned int offset;
|
||||
unsigned int mask;
|
||||
unsigned int value;
|
||||
unsigned int rev_mask;
|
||||
} smbb_charger_setup[] = {
|
||||
/* The bootloader is supposed to set this... make sure anyway. */
|
||||
{ SMBB_MISC_BOOT_DONE, BOOT_DONE, BOOT_DONE },
|
||||
|
||||
/* Disable software timer */
|
||||
{ SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 },
|
||||
|
||||
/* Clear and disable watchdog */
|
||||
{ SMBB_CHG_WDOG_TIME, 0xff, 160 },
|
||||
{ SMBB_CHG_WDOG_EN, WDOG_EN, 0 },
|
||||
|
||||
/* Use charger based EoC detection */
|
||||
{ SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG },
|
||||
|
||||
/* Disable GSM PA load adjustment.
|
||||
* The PA signal is incorrectly connected on v2.
|
||||
*/
|
||||
{ SMBB_CHG_CFG, 0xff, 0x00, BIT(3) },
|
||||
|
||||
/* Use VBAT (not VSYS) to compensate for IR drop during fast charging */
|
||||
{ SMBB_BUCK_REG_MODE, BUCK_REG_MODE, BUCK_REG_MODE_VBAT },
|
||||
|
||||
/* Enable battery temperature comparators */
|
||||
{ SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN },
|
||||
|
||||
/* Stop USB enumeration timer */
|
||||
{ SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
|
||||
|
||||
#if 0 /* FIXME supposedly only to disable hardware ARB termination */
|
||||
{ SMBB_USB_SEC_ACCESS, SEC_ACCESS_MAGIC },
|
||||
{ SMBB_USB_REV_BST, 0xff, REV_BST_CHG_GONE },
|
||||
#endif
|
||||
|
||||
/* Stop USB enumeration timer, again */
|
||||
{ SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP },
|
||||
|
||||
/* Enable charging */
|
||||
{ SMBB_CHG_CTRL, CTRL_EN, CTRL_EN },
|
||||
};
|
||||
|
||||
static char *smbb_bif[] = { "smbb-bif" };
|
||||
|
||||
static const struct power_supply_desc bat_psy_desc = {
|
||||
.name = "smbb-bif",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = smbb_battery_properties,
|
||||
.num_properties = ARRAY_SIZE(smbb_battery_properties),
|
||||
.get_property = smbb_battery_get_property,
|
||||
.set_property = smbb_battery_set_property,
|
||||
.property_is_writeable = smbb_battery_writable_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc usb_psy_desc = {
|
||||
.name = "smbb-usbin",
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.properties = smbb_charger_properties,
|
||||
.num_properties = ARRAY_SIZE(smbb_charger_properties),
|
||||
.get_property = smbb_usbin_get_property,
|
||||
.set_property = smbb_usbin_set_property,
|
||||
.property_is_writeable = smbb_charger_writable_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc dc_psy_desc = {
|
||||
.name = "smbb-dcin",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.properties = smbb_charger_properties,
|
||||
.num_properties = ARRAY_SIZE(smbb_charger_properties),
|
||||
.get_property = smbb_dcin_get_property,
|
||||
.set_property = smbb_dcin_set_property,
|
||||
.property_is_writeable = smbb_charger_writable_property,
|
||||
};
|
||||
|
||||
static int smbb_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct power_supply_config bat_cfg = {};
|
||||
struct power_supply_config usb_cfg = {};
|
||||
struct power_supply_config dc_cfg = {};
|
||||
struct smbb_charger *chg;
|
||||
int rc, i;
|
||||
|
||||
chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
|
||||
if (!chg)
|
||||
return -ENOMEM;
|
||||
|
||||
chg->dev = &pdev->dev;
|
||||
mutex_init(&chg->statlock);
|
||||
|
||||
chg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!chg->regmap) {
|
||||
dev_err(&pdev->dev, "failed to locate regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "reg", &chg->addr);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "missing or invalid 'reg' property\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = regmap_read(chg->regmap, chg->addr + SMBB_MISC_REV2, &chg->revision);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "unable to read revision\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
chg->revision += 1;
|
||||
if (chg->revision != 2 && chg->revision != 3) {
|
||||
dev_err(&pdev->dev, "v1 hardware not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
|
||||
|
||||
chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc");
|
||||
|
||||
for (i = 0; i < _ATTR_CNT; ++i) {
|
||||
rc = smbb_charger_attr_parse(chg, i);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "failed to parse/apply settings\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
bat_cfg.drv_data = chg;
|
||||
bat_cfg.of_node = pdev->dev.of_node;
|
||||
chg->bat_psy = devm_power_supply_register(&pdev->dev,
|
||||
&bat_psy_desc,
|
||||
&bat_cfg);
|
||||
if (IS_ERR(chg->bat_psy)) {
|
||||
dev_err(&pdev->dev, "failed to register battery\n");
|
||||
return PTR_ERR(chg->bat_psy);
|
||||
}
|
||||
|
||||
usb_cfg.drv_data = chg;
|
||||
usb_cfg.supplied_to = smbb_bif;
|
||||
usb_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
|
||||
chg->usb_psy = devm_power_supply_register(&pdev->dev,
|
||||
&usb_psy_desc,
|
||||
&usb_cfg);
|
||||
if (IS_ERR(chg->usb_psy)) {
|
||||
dev_err(&pdev->dev, "failed to register USB power supply\n");
|
||||
return PTR_ERR(chg->usb_psy);
|
||||
}
|
||||
|
||||
if (!chg->dc_disabled) {
|
||||
dc_cfg.drv_data = chg;
|
||||
dc_cfg.supplied_to = smbb_bif;
|
||||
dc_cfg.num_supplicants = ARRAY_SIZE(smbb_bif);
|
||||
chg->dc_psy = devm_power_supply_register(&pdev->dev,
|
||||
&dc_psy_desc,
|
||||
&dc_cfg);
|
||||
if (IS_ERR(chg->dc_psy)) {
|
||||
dev_err(&pdev->dev, "failed to register DC power supply\n");
|
||||
return PTR_ERR(chg->dc_psy);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) {
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get irq '%s'\n",
|
||||
smbb_charger_irqs[i].name);
|
||||
return irq;
|
||||
}
|
||||
|
||||
smbb_charger_irqs[i].handler(irq, chg);
|
||||
|
||||
rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
smbb_charger_irqs[i].handler, IRQF_ONESHOT,
|
||||
smbb_charger_irqs[i].name, chg);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "failed to request irq '%s'\n",
|
||||
smbb_charger_irqs[i].name);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,jeita-extended-temp-range");
|
||||
|
||||
/* Set temperature range to [35%:70%] or [25%:80%] accordingly */
|
||||
rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_BAT_BTC_CTRL,
|
||||
BTC_CTRL_COLD_EXT | BTC_CTRL_HOT_EXT_N,
|
||||
chg->jeita_ext_temp ?
|
||||
BTC_CTRL_COLD_EXT :
|
||||
BTC_CTRL_HOT_EXT_N);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to set %s temperature range\n",
|
||||
chg->jeita_ext_temp ? "JEITA extended" : "normal");
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) {
|
||||
const struct reg_off_mask_default *r = &smbb_charger_setup[i];
|
||||
|
||||
if (r->rev_mask & BIT(chg->revision))
|
||||
continue;
|
||||
|
||||
rc = regmap_update_bits(chg->regmap, chg->addr + r->offset,
|
||||
r->mask, r->value);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to initializing charging, bailing\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, chg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbb_charger_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct smbb_charger *chg;
|
||||
|
||||
chg = platform_get_drvdata(pdev);
|
||||
|
||||
regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id smbb_charger_id_table[] = {
|
||||
{ .compatible = "qcom,pm8941-charger" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, smbb_charger_id_table);
|
||||
|
||||
static struct platform_driver smbb_charger_driver = {
|
||||
.probe = smbb_charger_probe,
|
||||
.remove = smbb_charger_remove,
|
||||
.driver = {
|
||||
.name = "qcom-smbb",
|
||||
.of_match_table = smbb_charger_id_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(smbb_charger_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -15,7 +15,7 @@ config POWER_RESET_AS3722
|
|||
This driver supports turning off board via a ams AS3722 power-off.
|
||||
|
||||
config POWER_RESET_AT91_POWEROFF
|
||||
bool "Atmel AT91 poweroff driver"
|
||||
tristate "Atmel AT91 poweroff driver"
|
||||
depends on ARCH_AT91
|
||||
default SOC_AT91SAM9 || SOC_SAMA5
|
||||
help
|
||||
|
@ -23,7 +23,7 @@ config POWER_RESET_AT91_POWEROFF
|
|||
SoCs
|
||||
|
||||
config POWER_RESET_AT91_RESET
|
||||
bool "Atmel AT91 reset driver"
|
||||
tristate "Atmel AT91 reset driver"
|
||||
depends on ARCH_AT91
|
||||
default SOC_AT91SAM9 || SOC_SAMA5
|
||||
help
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -48,6 +49,7 @@ static const char *shdwc_wakeup_modes[] = {
|
|||
};
|
||||
|
||||
static void __iomem *at91_shdwc_base;
|
||||
static struct clk *sclk;
|
||||
|
||||
static void __init at91_wakeup_status(void)
|
||||
{
|
||||
|
@ -119,9 +121,10 @@ static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
|
|||
writel(wakeup_mode | mode, at91_shdwc_base + AT91_SHDW_MR);
|
||||
}
|
||||
|
||||
static int at91_poweroff_probe(struct platform_device *pdev)
|
||||
static int __init at91_poweroff_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
@ -130,6 +133,16 @@ static int at91_poweroff_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(at91_shdwc_base);
|
||||
}
|
||||
|
||||
sclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sclk))
|
||||
return PTR_ERR(sclk);
|
||||
|
||||
ret = clk_prepare_enable(sclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not enable slow clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
at91_wakeup_status();
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
|
@ -140,6 +153,16 @@ static int at91_poweroff_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __exit at91_poweroff_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (pm_power_off == at91_poweroff)
|
||||
pm_power_off = NULL;
|
||||
|
||||
clk_disable_unprepare(sclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id at91_poweroff_of_match[] = {
|
||||
{ .compatible = "atmel,at91sam9260-shdwc", },
|
||||
{ .compatible = "atmel,at91sam9rl-shdwc", },
|
||||
|
@ -148,10 +171,14 @@ static const struct of_device_id at91_poweroff_of_match[] = {
|
|||
};
|
||||
|
||||
static struct platform_driver at91_poweroff_driver = {
|
||||
.probe = at91_poweroff_probe,
|
||||
.remove = __exit_p(at91_poweroff_remove),
|
||||
.driver = {
|
||||
.name = "at91-poweroff",
|
||||
.of_match_table = at91_poweroff_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(at91_poweroff_driver);
|
||||
module_platform_driver_probe(at91_poweroff_driver, at91_poweroff_probe);
|
||||
|
||||
MODULE_AUTHOR("Atmel Corporation");
|
||||
MODULE_DESCRIPTION("Shutdown driver for Atmel SoCs");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Atmel AT91 SAM9 SoCs reset code
|
||||
* Atmel AT91 SAM9 & SAMA5 SoCs reset code
|
||||
*
|
||||
* Copyright (C) 2007 Atmel Corporation.
|
||||
* Copyright (C) BitBox Ltd 2010
|
||||
|
@ -11,6 +11,7 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -46,6 +47,7 @@ enum reset_type {
|
|||
};
|
||||
|
||||
static void __iomem *at91_ramc_base[2], *at91_rstc_base;
|
||||
static struct clk *sclk;
|
||||
|
||||
/*
|
||||
* unless the SDRAM is cleanly shutdown before we hit the
|
||||
|
@ -178,11 +180,11 @@ static struct notifier_block at91_restart_nb = {
|
|||
.priority = 192,
|
||||
};
|
||||
|
||||
static int at91_reset_of_probe(struct platform_device *pdev)
|
||||
static int __init at91_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device_node *np;
|
||||
int idx = 0;
|
||||
int ret, idx = 0;
|
||||
|
||||
at91_rstc_base = of_iomap(pdev->dev.of_node, 0);
|
||||
if (!at91_rstc_base) {
|
||||
|
@ -204,57 +206,36 @@ static int at91_reset_of_probe(struct platform_device *pdev)
|
|||
|
||||
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
|
||||
at91_restart_nb.notifier_call = match->data;
|
||||
return register_restart_handler(&at91_restart_nb);
|
||||
}
|
||||
|
||||
static int at91_reset_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *match;
|
||||
struct resource *res;
|
||||
int idx = 0;
|
||||
sclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sclk))
|
||||
return PTR_ERR(sclk);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
at91_rstc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(at91_rstc_base)) {
|
||||
dev_err(&pdev->dev, "Could not map reset controller address\n");
|
||||
return PTR_ERR(at91_rstc_base);
|
||||
}
|
||||
|
||||
for (idx = 0; idx < 2; idx++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1 );
|
||||
at91_ramc_base[idx] = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!at91_ramc_base[idx]) {
|
||||
dev_err(&pdev->dev, "Could not map ram controller address\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
match = platform_get_device_id(pdev);
|
||||
at91_restart_nb.notifier_call =
|
||||
(int (*)(struct notifier_block *,
|
||||
unsigned long, void *)) match->driver_data;
|
||||
|
||||
return register_restart_handler(&at91_restart_nb);
|
||||
}
|
||||
|
||||
static int at91_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
ret = at91_reset_of_probe(pdev);
|
||||
else
|
||||
ret = at91_reset_platform_probe(pdev);
|
||||
|
||||
if (ret)
|
||||
ret = clk_prepare_enable(sclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not enable slow clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = register_restart_handler(&at91_restart_nb);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(sclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
at91_reset_status(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit at91_reset_remove(struct platform_device *pdev)
|
||||
{
|
||||
unregister_restart_handler(&at91_restart_nb);
|
||||
clk_disable_unprepare(sclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id at91_reset_plat_match[] = {
|
||||
{ "at91-sam9260-reset", (unsigned long)at91sam9260_restart },
|
||||
{ "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart },
|
||||
|
@ -262,11 +243,15 @@ static const struct platform_device_id at91_reset_plat_match[] = {
|
|||
};
|
||||
|
||||
static struct platform_driver at91_reset_driver = {
|
||||
.probe = at91_reset_probe,
|
||||
.remove = __exit_p(at91_reset_remove),
|
||||
.driver = {
|
||||
.name = "at91-reset",
|
||||
.of_match_table = at91_reset_of_match,
|
||||
},
|
||||
.id_table = at91_reset_plat_match,
|
||||
};
|
||||
module_platform_driver(at91_reset_driver);
|
||||
module_platform_driver_probe(at91_reset_driver, at91_reset_probe);
|
||||
|
||||
MODULE_AUTHOR("Atmel Corporation");
|
||||
MODULE_DESCRIPTION("Reset driver for Atmel SoCs");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -1760,5 +1760,4 @@ module_i2c_driver(rt9455_driver);
|
|||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Anda-Maria Nicolae <anda-maria.nicolae@intel.com>");
|
||||
MODULE_ALIAS("i2c:rt9455-charger");
|
||||
MODULE_DESCRIPTION("Richtek RT9455 Charger Driver");
|
||||
|
|
|
@ -1332,4 +1332,3 @@ MODULE_AUTHOR("Bruce E. Robertson <bruce.e.robertson@intel.com>");
|
|||
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("SMB347 battery charger driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("i2c:smb347");
|
||||
|
|
|
@ -353,6 +353,7 @@ static const struct of_device_id of_tps65090_charger_match[] = {
|
|||
{ .compatible = "ti,tps65090-charger", },
|
||||
{ /* end */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_tps65090_charger_match);
|
||||
|
||||
static struct platform_driver tps65090_charger_driver = {
|
||||
.driver = {
|
||||
|
|
264
drivers/power/tps65217_charger.c
Normal file
264
drivers/power/tps65217_charger.c
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Battery charger driver for TI's tps65217
|
||||
*
|
||||
* Copyright (c) 2015, Collabora Ltd.
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Battery charger driver for TI's tps65217
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps65217.h>
|
||||
|
||||
#define POLL_INTERVAL (HZ * 2)
|
||||
|
||||
struct tps65217_charger {
|
||||
struct tps65217 *tps;
|
||||
struct device *dev;
|
||||
struct power_supply *ac;
|
||||
|
||||
int ac_online;
|
||||
int prev_ac_online;
|
||||
|
||||
struct task_struct *poll_task;
|
||||
};
|
||||
|
||||
static enum power_supply_property tps65217_ac_props[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static int tps65217_config_charger(struct tps65217_charger *charger)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(charger->dev, "%s\n", __func__);
|
||||
|
||||
/*
|
||||
* tps65217 rev. G, p. 31 (see p. 32 for NTC schematic)
|
||||
*
|
||||
* The device can be configured to support a 100k NTC (B = 3960) by
|
||||
* setting the the NTC_TYPE bit in register CHGCONFIG1 to 1. However it
|
||||
* is not recommended to do so. In sleep mode, the charger continues
|
||||
* charging the battery, but all register values are reset to default
|
||||
* values. Therefore, the charger would get the wrong temperature
|
||||
* information. If 100k NTC setting is required, please contact the
|
||||
* factory.
|
||||
*
|
||||
* ATTENTION, conflicting information, from p. 46
|
||||
*
|
||||
* NTC TYPE (for battery temperature measurement)
|
||||
* 0 – 100k (curve 1, B = 3960)
|
||||
* 1 – 10k (curve 2, B = 3480) (default on reset)
|
||||
*
|
||||
*/
|
||||
ret = tps65217_clear_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
|
||||
TPS65217_CHGCONFIG1_NTC_TYPE,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (ret) {
|
||||
dev_err(charger->dev,
|
||||
"failed to set 100k NTC setting: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65217_enable_charging(struct tps65217_charger *charger)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* charger already enabled */
|
||||
if (charger->ac_online)
|
||||
return 0;
|
||||
|
||||
dev_dbg(charger->dev, "%s: enable charging\n", __func__);
|
||||
ret = tps65217_set_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
|
||||
TPS65217_CHGCONFIG1_CHG_EN,
|
||||
TPS65217_CHGCONFIG1_CHG_EN,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (ret) {
|
||||
dev_err(charger->dev,
|
||||
"%s: Error in writing CHG_EN in reg 0x%x: %d\n",
|
||||
__func__, TPS65217_REG_CHGCONFIG1, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
charger->ac_online = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65217_ac_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct tps65217_charger *charger = power_supply_get_drvdata(psy);
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_ONLINE) {
|
||||
val->intval = charger->ac_online;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static irqreturn_t tps65217_charger_irq(int irq, void *dev)
|
||||
{
|
||||
int ret, val;
|
||||
struct tps65217_charger *charger = dev;
|
||||
|
||||
charger->prev_ac_online = charger->ac_online;
|
||||
|
||||
ret = tps65217_reg_read(charger->tps, TPS65217_REG_STATUS, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(charger->dev, "%s: Error in reading reg 0x%x\n",
|
||||
__func__, TPS65217_REG_STATUS);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
dev_dbg(charger->dev, "%s: 0x%x\n", __func__, val);
|
||||
|
||||
/* check for AC status bit */
|
||||
if (val & TPS65217_STATUS_ACPWR) {
|
||||
ret = tps65217_enable_charging(charger);
|
||||
if (ret) {
|
||||
dev_err(charger->dev,
|
||||
"failed to enable charger: %d\n", ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
} else {
|
||||
charger->ac_online = 0;
|
||||
}
|
||||
|
||||
if (charger->prev_ac_online != charger->ac_online)
|
||||
power_supply_changed(charger->ac);
|
||||
|
||||
ret = tps65217_reg_read(charger->tps, TPS65217_REG_CHGCONFIG0, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(charger->dev, "%s: Error in reading reg 0x%x\n",
|
||||
__func__, TPS65217_REG_CHGCONFIG0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (val & TPS65217_CHGCONFIG0_ACTIVE)
|
||||
dev_dbg(charger->dev, "%s: charger is charging\n", __func__);
|
||||
else
|
||||
dev_dbg(charger->dev,
|
||||
"%s: charger is NOT charging\n", __func__);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tps65217_charger_poll_task(void *data)
|
||||
{
|
||||
set_freezable();
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
schedule_timeout_interruptible(POLL_INTERVAL);
|
||||
try_to_freeze();
|
||||
tps65217_charger_irq(-1, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct power_supply_desc tps65217_charger_desc = {
|
||||
.name = "tps65217-ac",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.get_property = tps65217_ac_get_property,
|
||||
.properties = tps65217_ac_props,
|
||||
.num_properties = ARRAY_SIZE(tps65217_ac_props),
|
||||
};
|
||||
|
||||
static int tps65217_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
|
||||
struct tps65217_charger *charger;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s\n", __func__);
|
||||
|
||||
charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
|
||||
if (!charger)
|
||||
return -ENOMEM;
|
||||
|
||||
charger->tps = tps;
|
||||
charger->dev = &pdev->dev;
|
||||
|
||||
charger->ac = devm_power_supply_register(&pdev->dev,
|
||||
&tps65217_charger_desc,
|
||||
NULL);
|
||||
if (IS_ERR(charger->ac)) {
|
||||
dev_err(&pdev->dev, "failed: power supply register\n");
|
||||
return PTR_ERR(charger->ac);
|
||||
}
|
||||
|
||||
ret = tps65217_config_charger(charger);
|
||||
if (ret < 0) {
|
||||
dev_err(charger->dev, "charger config failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
charger->poll_task = kthread_run(tps65217_charger_poll_task,
|
||||
charger, "ktps65217charger");
|
||||
if (IS_ERR(charger->poll_task)) {
|
||||
ret = PTR_ERR(charger->poll_task);
|
||||
dev_err(charger->dev, "Unable to run kthread err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65217_charger_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65217_charger *charger = platform_get_drvdata(pdev);
|
||||
|
||||
kthread_stop(charger->poll_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id tps65217_charger_match_table[] = {
|
||||
{ .compatible = "ti,tps65217-charger", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps65217_charger_match_table);
|
||||
|
||||
static struct platform_driver tps65217_charger_driver = {
|
||||
.probe = tps65217_charger_probe,
|
||||
.remove = tps65217_charger_remove,
|
||||
.driver = {
|
||||
.name = "tps65217-charger",
|
||||
.of_match_table = of_match_ptr(tps65217_charger_match_table),
|
||||
},
|
||||
|
||||
};
|
||||
module_platform_driver(tps65217_charger_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>");
|
||||
MODULE_DESCRIPTION("TPS65217 battery charger driver");
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/i2c/twl4030-madc.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
|
||||
#define TWL4030_BCIMDEN 0x00
|
||||
#define TWL4030_BCIMDKEY 0x01
|
||||
|
@ -91,21 +91,23 @@
|
|||
#define TWL4030_MSTATEC_COMPLETE1 0x0b
|
||||
#define TWL4030_MSTATEC_COMPLETE4 0x0e
|
||||
|
||||
#if IS_REACHABLE(CONFIG_TWL4030_MADC)
|
||||
/*
|
||||
* If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
|
||||
* then AC is available.
|
||||
*/
|
||||
static inline int ac_available(void)
|
||||
static inline int ac_available(struct iio_channel *channel_vac)
|
||||
{
|
||||
return twl4030_get_madc_conversion(11) > 4500;
|
||||
int val, err;
|
||||
|
||||
if (!channel_vac)
|
||||
return 0;
|
||||
|
||||
err = iio_read_channel_processed(channel_vac, &val);
|
||||
if (err < 0)
|
||||
return 0;
|
||||
return val > 4500;
|
||||
}
|
||||
#else
|
||||
static inline int ac_available(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool allow_usb;
|
||||
module_param(allow_usb, bool, 0644);
|
||||
MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
|
||||
|
@ -128,6 +130,7 @@ struct twl4030_bci {
|
|||
*/
|
||||
unsigned int ichg_eoc, ichg_lo, ichg_hi;
|
||||
unsigned int usb_cur, ac_cur;
|
||||
struct iio_channel *channel_vac;
|
||||
bool ac_is_active;
|
||||
int usb_mode, ac_mode; /* charging mode requested */
|
||||
#define CHARGE_OFF 0
|
||||
|
@ -278,7 +281,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci)
|
|||
* If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11)
|
||||
* and AC is enabled, set current for 'ac'
|
||||
*/
|
||||
if (ac_available()) {
|
||||
if (ac_available(bci->channel_vac)) {
|
||||
cur = bci->ac_cur;
|
||||
bci->ac_is_active = true;
|
||||
} else {
|
||||
|
@ -1048,6 +1051,12 @@ static int twl4030_bci_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bci->channel_vac = iio_channel_get(&pdev->dev, "vac");
|
||||
if (IS_ERR(bci->channel_vac)) {
|
||||
bci->channel_vac = NULL;
|
||||
dev_warn(&pdev->dev, "could not request vac iio channel");
|
||||
}
|
||||
|
||||
INIT_WORK(&bci->work, twl4030_bci_usb_work);
|
||||
INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker);
|
||||
|
||||
|
@ -1069,7 +1078,7 @@ static int twl4030_bci_probe(struct platform_device *pdev)
|
|||
TWL4030_INTERRUPTS_BCIIMR1A);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret);
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
|
||||
|
@ -1102,6 +1111,10 @@ static int twl4030_bci_probe(struct platform_device *pdev)
|
|||
twl4030_charger_enable_backup(0, 0);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
iio_channel_release(bci->channel_vac);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit twl4030_bci_remove(struct platform_device *pdev)
|
||||
|
@ -1112,6 +1125,8 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
|
|||
twl4030_charger_enable_usb(bci, false);
|
||||
twl4030_charger_enable_backup(0, 0);
|
||||
|
||||
iio_channel_release(bci->channel_vac);
|
||||
|
||||
device_remove_file(&bci->usb->dev, &dev_attr_max_current);
|
||||
device_remove_file(&bci->usb->dev, &dev_attr_mode);
|
||||
device_remove_file(&bci->ac->dev, &dev_attr_max_current);
|
||||
|
|
|
@ -499,7 +499,8 @@ static int wm831x_power_probe(struct platform_device *pdev)
|
|||
struct wm831x_power *power;
|
||||
int ret, irq, i;
|
||||
|
||||
power = kzalloc(sizeof(struct wm831x_power), GFP_KERNEL);
|
||||
power = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_power),
|
||||
GFP_KERNEL);
|
||||
if (power == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -536,7 +537,7 @@ static int wm831x_power_probe(struct platform_device *pdev)
|
|||
NULL);
|
||||
if (IS_ERR(power->wall)) {
|
||||
ret = PTR_ERR(power->wall);
|
||||
goto err_kmalloc;
|
||||
goto err;
|
||||
}
|
||||
|
||||
power->usb_desc.name = power->usb_name,
|
||||
|
@ -572,7 +573,7 @@ static int wm831x_power_probe(struct platform_device *pdev)
|
|||
|
||||
irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO"));
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
|
||||
IRQF_TRIGGER_RISING, "System power low",
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "System power low",
|
||||
power);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
|
||||
|
@ -582,7 +583,7 @@ static int wm831x_power_probe(struct platform_device *pdev)
|
|||
|
||||
irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC"));
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq,
|
||||
IRQF_TRIGGER_RISING, "Power source",
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "Power source",
|
||||
power);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n",
|
||||
|
@ -595,7 +596,7 @@ static int wm831x_power_probe(struct platform_device *pdev)
|
|||
platform_get_irq_byname(pdev,
|
||||
wm831x_bat_irqs[i]));
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_bat_irq,
|
||||
IRQF_TRIGGER_RISING,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
wm831x_bat_irqs[i],
|
||||
power);
|
||||
if (ret != 0) {
|
||||
|
@ -626,8 +627,7 @@ static int wm831x_power_probe(struct platform_device *pdev)
|
|||
power_supply_unregister(power->usb);
|
||||
err_wall:
|
||||
power_supply_unregister(power->wall);
|
||||
err_kmalloc:
|
||||
kfree(power);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -654,7 +654,6 @@ static int wm831x_power_remove(struct platform_device *pdev)
|
|||
power_supply_unregister(wm831x_power->battery);
|
||||
power_supply_unregister(wm831x_power->wall);
|
||||
power_supply_unregister(wm831x_power->usb);
|
||||
kfree(wm831x_power);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/power/bq27x00_battery.h>
|
||||
#include <linux/power/bq27xxx_battery.h>
|
||||
|
||||
#include "../w1.h"
|
||||
#include "../w1_int.h"
|
||||
|
@ -39,9 +39,10 @@ static int w1_bq27000_read(struct device *dev, unsigned int reg)
|
|||
return val;
|
||||
}
|
||||
|
||||
static struct bq27000_platform_data bq27000_battery_info = {
|
||||
static struct bq27xxx_platform_data bq27000_battery_info = {
|
||||
.read = w1_bq27000_read,
|
||||
.name = "bq27000-battery",
|
||||
.chip = BQ27000,
|
||||
};
|
||||
|
||||
static int w1_bq27000_add_slave(struct w1_slave *sl)
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef __LINUX_MFD_AXP20X_H
|
||||
#define __LINUX_MFD_AXP20X_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
enum {
|
||||
AXP152_ID = 0,
|
||||
AXP202_ID,
|
||||
|
@ -438,4 +440,26 @@ struct axp288_extcon_pdata {
|
|||
struct gpio_desc *gpio_mux_cntl;
|
||||
};
|
||||
|
||||
/* generic helper function for reading 9-16 bit wide regs */
|
||||
static inline int axp20x_read_variable_width(struct regmap *regmap,
|
||||
unsigned int reg, unsigned int width)
|
||||
{
|
||||
unsigned int reg_val, result;
|
||||
int err;
|
||||
|
||||
err = regmap_read(regmap, reg, ®_val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
result = reg_val << (width - 8);
|
||||
|
||||
err = regmap_read(regmap, reg + 1, ®_val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
result |= reg_val;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* __LINUX_MFD_AXP20X_H */
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef __LINUX_BQ27X00_BATTERY_H__
|
||||
#define __LINUX_BQ27X00_BATTERY_H__
|
||||
|
||||
/**
|
||||
* struct bq27000_plaform_data - Platform data for bq27000 devices
|
||||
* @name: Name of the battery. If NULL the driver will fallback to "bq27000".
|
||||
* @read: HDQ read callback.
|
||||
* This function should provide access to the HDQ bus the battery is
|
||||
* connected to.
|
||||
* The first parameter is a pointer to the battery device, the second the
|
||||
* register to be read. The return value should either be the content of
|
||||
* the passed register or an error value.
|
||||
*/
|
||||
struct bq27000_platform_data {
|
||||
const char *name;
|
||||
int (*read)(struct device *dev, unsigned int);
|
||||
};
|
||||
|
||||
#endif
|
31
include/linux/power/bq27xxx_battery.h
Normal file
31
include/linux/power/bq27xxx_battery.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef __LINUX_BQ27X00_BATTERY_H__
|
||||
#define __LINUX_BQ27X00_BATTERY_H__
|
||||
|
||||
/**
|
||||
* struct bq27xxx_plaform_data - Platform data for bq27xxx devices
|
||||
* @name: Name of the battery.
|
||||
* @chip: Chip class number of this device.
|
||||
* @read: HDQ read callback.
|
||||
* This function should provide access to the HDQ bus the battery is
|
||||
* connected to.
|
||||
* The first parameter is a pointer to the battery device, the second the
|
||||
* register to be read. The return value should either be the content of
|
||||
* the passed register or an error value.
|
||||
*/
|
||||
enum bq27xxx_chip {
|
||||
BQ27000 = 1, /* bq27000, bq27200 */
|
||||
BQ27010, /* bq27010, bq27210 */
|
||||
BQ27500, /* bq27500, bq27510, bq27520 */
|
||||
BQ27530, /* bq27530, bq27531 */
|
||||
BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
|
||||
BQ27545, /* bq27545 */
|
||||
BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
|
||||
};
|
||||
|
||||
struct bq27xxx_platform_data {
|
||||
const char *name;
|
||||
enum bq27xxx_chip chip;
|
||||
int (*read)(struct device *dev, unsigned int);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -65,7 +65,7 @@ struct charger_cable {
|
|||
const char *extcon_name;
|
||||
const char *name;
|
||||
|
||||
/* The charger-manager use Exton framework*/
|
||||
/* The charger-manager use Extcon framework */
|
||||
struct extcon_specific_cable_nb extcon_dev;
|
||||
struct work_struct wq;
|
||||
struct notifier_block nb;
|
||||
|
@ -94,7 +94,7 @@ struct charger_cable {
|
|||
* the charger will be maintained with disabled state.
|
||||
* @cables:
|
||||
* the array of charger cables to enable/disable charger
|
||||
* and set current limit according to constratint data of
|
||||
* and set current limit according to constraint data of
|
||||
* struct charger_cable if only charger cable included
|
||||
* in the array of charger cables is attached/detached.
|
||||
* @num_cables: the number of charger cables.
|
||||
|
@ -148,7 +148,7 @@ struct charger_regulator {
|
|||
* @polling_interval_ms: interval in millisecond at which
|
||||
* charger manager will monitor battery health
|
||||
* @battery_present:
|
||||
* Specify where information for existance of battery can be obtained
|
||||
* Specify where information for existence of battery can be obtained
|
||||
* @psy_charger_stat: the names of power-supply for chargers
|
||||
* @num_charger_regulator: the number of entries in charger_regulators
|
||||
* @charger_regulators: array of charger regulators
|
||||
|
@ -156,7 +156,7 @@ struct charger_regulator {
|
|||
* @thermal_zone : the name of thermal zone for battery
|
||||
* @temp_min : Minimum battery temperature for charging.
|
||||
* @temp_max : Maximum battery temperature for charging.
|
||||
* @temp_diff : Temperature diffential to restart charging.
|
||||
* @temp_diff : Temperature difference to restart charging.
|
||||
* @measure_battery_temp:
|
||||
* true: measure battery temperature
|
||||
* false: measure ambient temperature
|
||||
|
|
Loading…
Reference in a new issue