power supply and reset changes for the v5.10 series
power-supply core: * Add wireless type * Properly document current direction battery/charger driver changes: * New fuel-gauge/charger driver for RN5T618/RN5T619 * New charger driver for BQ25980, BQ25975 and BQ25960 * bq27xxx-battery: add support for TI bq34z100 * gpio-charger: convert to GPIO descriptors * gpio-charger: add optional support for charge current limiting * max17040: add support for max17041, max17043, max17044 * max17040: add support for max17048, max17049, max17058, max17059 * smb347-charger: add DT support * smb247-charger: add SMB345 and SMB358 support * simple-battery: add temperature properties * lots of minor fixes, cleanups and DT binding YAML conversions reset drivers: * ocelot: Add support for Sparx5 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAl+IsXoACgkQ2O7X88g7 +prL8RAAprDcwF5irflM2bWwzKnfuNgTjk6P/o9gIWiSJsNA1R3XKJEm6l38givV EhnceGaZXgWg8blh3htd5Z6DNEEFX5ucB9KtQESW5ehM/KGvcEwD7CJilSJejqt4 3AQiFQLa41s4tnBBao/9gp+juSsvwg2NoeCaOa1H2K5oVi7WDmnmQyexa6CAty7b D4Uz8EOfpVi9FvYalffGP7QkA5ZsNWSLRRLJshHCw6QH54+h51F5efhu5S5qxXEA L/yjfFFhiB99df7y4LzvCItfaTGLcLNFfCas4+0yOWnViXosIr9rQk51FihXaDot DBCyF6hHWFDCnymnjMjWclYeatPFw+jnPrjmn+b0mQ/RaTgz30tgvuZurepcCwN/ ZKZftnvN16VAnUYgrE397F706sBZHjE6NonWvpXExawNUznA4h2uTu1bwWhtp5Um gcIjhL0ePEMf1yAYW3iI/l70NfIgPoEep6w+8oyLgV4vvffkKxkHkndoV7ZcS79M OdKbgGq4ZBNTS8ABsjHDO0o+/vBuKa3KE3/2J+916G3mc8FM6WJBfo1mIuwD51GA ASwG4UlE1Kyu91z4rP15GGMwSho7UKvWORB5ECsmfZ8xjiJSRHJAiDhmiaSaZZi0 dc5JKVDdM056IWOuP8THEVG6r3BiG/B1i8eY4YJ6GPv82JP/iks= =QtfI -----END PGP SIGNATURE----- Merge tag 'for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset updates from Sebastian Reichel: "Power-supply core: - add wireless type - properly document current direction Battery/charger driver changes: - new fuel-gauge/charger driver for RN5T618/RN5T619 - new charger driver for BQ25980, BQ25975 and BQ25960 - bq27xxx-battery: add support for TI bq34z100 - gpio-charger: convert to GPIO descriptors - gpio-charger: add optional support for charge current limiting - max17040: add support for max17041, max17043, max17044 - max17040: add support for max17048, max17049, max17058, max17059 - smb347-charger: add DT support - smb247-charger: add SMB345 and SMB358 support - simple-battery: add temperature properties - lots of minor fixes, cleanups and DT binding YAML conversions Reset drivers: - ocelot: Add support for Sparx5" * tag 'for-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (81 commits) power: reset: POWER_RESET_OCELOT_RESET should depend on Ocelot or Sparx5 power: supply: bq25980: Fix uninitialized wd_reg_val and overrun power: supply: ltc2941: Fix ptr to enum cast power: supply: test-power: revise parameter printing to use sprintf power: supply: charger-manager: fix incorrect check on charging_duration_ms power: supply: max17040: Fix ptr to enum cast power: supply: bq25980: Fix uninitialized wd_reg_val power: supply: bq25980: remove redundant zero check on ret power: reset: ocelot: Add support for Sparx5 dt-bindings: reset: ocelot: Add Sparx5 support power: supply: sbs-battery: keep error code when get_property() fails power: supply: bq25980: Add support for the BQ259xx family dt-binding: bq25980: Add the bq25980 flash charger power: supply: fix spelling mistake "unprecise" -> "imprecise" power: supply: test_power: add missing newlines when printing parameters by sysfs power: supply: pm2301: drop duplicated i2c_device_id power: supply: charger-manager: drop unused charger assignment power: supply: rt9455: skip 'struct acpi_device_id' when !CONFIG_ACPI power: supply: goldfish: skip 'struct acpi_device_id' when !CONFIG_ACPI power: supply: bq25890: skip 'struct acpi_device_id' when !CONFIG_ACPI ...
This commit is contained in:
Коммит
38525c6919
|
@ -34,7 +34,7 @@ Description:
|
|||
Describes the main type of the supply.
|
||||
|
||||
Access: Read
|
||||
Valid values: "Battery", "UPS", "Mains", "USB"
|
||||
Valid values: "Battery", "UPS", "Mains", "USB", "Wireless"
|
||||
|
||||
===== Battery Properties =====
|
||||
|
||||
|
@ -108,7 +108,8 @@ Description:
|
|||
which they average readings to smooth out the reported value.
|
||||
|
||||
Access: Read
|
||||
Valid values: Represented in microamps
|
||||
Valid values: Represented in microamps. Negative values are used
|
||||
for discharging batteries, positive values for charging batteries.
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/current_max
|
||||
Date: October 2010
|
||||
|
@ -127,7 +128,8 @@ Description:
|
|||
This value is not averaged/smoothed.
|
||||
|
||||
Access: Read
|
||||
Valid values: Represented in microamps
|
||||
Valid values: Represented in microamps. Negative values are used
|
||||
for discharging batteries, positive values for charging batteries.
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/charge_control_limit
|
||||
Date: Oct 2012
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
Microsemi Ocelot reset controller
|
||||
|
||||
The DEVCPU_GCB:CHIP_REGS have a SOFT_RST register that can be used to reset the
|
||||
SoC MIPS core.
|
||||
SoC core.
|
||||
|
||||
The reset registers are both present in the MSCC vcoreiii MIPS and
|
||||
microchip Sparx5 armv8 SoC's.
|
||||
|
||||
Required Properties:
|
||||
- compatible: "mscc,ocelot-chip-reset"
|
||||
- compatible: "mscc,ocelot-chip-reset" or "microchip,sparx5-chip-reset"
|
||||
|
||||
Example:
|
||||
reset@1070008 {
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
Generic reboot mode core map driver
|
||||
|
||||
This driver get reboot mode arguments and call the write
|
||||
interface to store the magic value in special register
|
||||
or ram. Then the bootloader can read it and take different
|
||||
action according to the argument stored.
|
||||
|
||||
All mode properties are vendor specific, it is a indication to tell
|
||||
the bootloader what to do when the system reboots, and should be named
|
||||
as mode-xxx = <magic> (xxx is mode name, magic should be a none-zero value).
|
||||
|
||||
For example modes common on Android platform:
|
||||
- mode-normal: Normal reboot mode, system reboot with command "reboot".
|
||||
- mode-recovery: Android Recovery mode, it is a mode to format the device or update a new image.
|
||||
- mode-bootloader: Android fastboot mode, it's a mode to re-flash partitions on the Android based device.
|
||||
- mode-loader: A bootloader mode, it's a mode used to download image on Rockchip platform,
|
||||
usually used in development.
|
||||
|
||||
Example:
|
||||
reboot-mode {
|
||||
mode-normal = <BOOT_NORMAL>;
|
||||
mode-recovery = <BOOT_RECOVERY>;
|
||||
mode-bootloader = <BOOT_FASTBOOT>;
|
||||
mode-loader = <BOOT_BL_DOWNLOAD>;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/reset/reboot-mode.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Generic reboot mode core map
|
||||
|
||||
maintainers:
|
||||
- Andy Yan <andy.yan@rock-chips.com>
|
||||
|
||||
description: |
|
||||
This driver get reboot mode arguments and call the write
|
||||
interface to store the magic value in special register
|
||||
or ram. Then the bootloader can read it and take different
|
||||
action according to the argument stored.
|
||||
|
||||
All mode properties are vendor specific, it is a indication to tell
|
||||
the bootloader what to do when the system reboots, and should be named
|
||||
as mode-xxx = <magic> (xxx is mode name, magic should be a non-zero value).
|
||||
|
||||
For example, modes common Android platform are:
|
||||
- normal: Normal reboot mode, system reboot with command "reboot".
|
||||
- recovery: Android Recovery mode, it is a mode to format the device or update a new image.
|
||||
- bootloader: Android fastboot mode, it's a mode to re-flash partitions on the Android based device.
|
||||
- loader: A bootloader mode, it's a mode used to download image on Rockchip platform,
|
||||
usually used in development.
|
||||
|
||||
properties:
|
||||
mode-normal:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Default value to set on a reboot if no command was provided.
|
||||
|
||||
patternProperties:
|
||||
"^mode-.*$":
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
examples:
|
||||
- |
|
||||
reboot-mode {
|
||||
mode-normal = <0>;
|
||||
mode-recovery = <1>;
|
||||
mode-bootloader = <2>;
|
||||
mode-loader = <3>;
|
||||
};
|
||||
...
|
|
@ -82,6 +82,27 @@ properties:
|
|||
An array containing the temperature in degree Celsius,
|
||||
for each of the battery capacity lookup table.
|
||||
|
||||
operating-range-celsius:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: operating temperature range of a battery
|
||||
items:
|
||||
- description: minimum temperature at which battery can operate
|
||||
- description: maximum temperature at which battery can operate
|
||||
|
||||
ambient-celsius:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: safe range of ambient temperature
|
||||
items:
|
||||
- description: alert when ambient temperature is lower than this value
|
||||
- description: alert when ambient temperature is higher than this value
|
||||
|
||||
alert-celsius:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: safe range of battery temperature
|
||||
items:
|
||||
- description: alert when battery temperature is lower than this value
|
||||
- description: alert when battery temperature is higher than this value
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
|
@ -130,6 +151,9 @@ examples:
|
|||
/* table for 10 degree Celsius */
|
||||
ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>;
|
||||
resistance-temp-table = <20 100>, <10 90>, <0 80>, <(-10) 60>;
|
||||
operating-range-celsius = <(-30) 50>;
|
||||
ambient-celsius = <(-5) 50>;
|
||||
alert-celsius = <0 40>;
|
||||
};
|
||||
|
||||
charger@11 {
|
||||
|
|
|
@ -33,6 +33,10 @@ Optional properties:
|
|||
- ti,thermal-regulation-threshold: integer, temperature above which the charge
|
||||
current is lowered, to avoid overheating (in degrees Celsius). If omitted,
|
||||
the default setting will be used (120 degrees);
|
||||
- ti,ibatcomp-micro-ohms: integer, value of a resistor in series with
|
||||
the battery;
|
||||
- ti,ibatcomp-clamp-microvolt: integer, maximum charging voltage adjustment due
|
||||
to expected voltage drop on in-series resistor;
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2020 Texas Instruments Incorporated
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/power/supply/bq25980.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: TI BQ25980 Flash Charger
|
||||
|
||||
maintainers:
|
||||
- Dan Murphy <dmurphy@ti.com>
|
||||
- Ricardo Rivera-Matos <r-rivera-matos@ti.com>
|
||||
|
||||
description: |
|
||||
The BQ25980, BQ25975, and BQ25960 are a series of flash chargers intended
|
||||
for use in high-power density portable electronics. These inductorless
|
||||
switching chargers can provide over 97% efficiency by making use of the
|
||||
switched capacitor architecture.
|
||||
|
||||
allOf:
|
||||
- $ref: power-supply.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,bq25980
|
||||
- ti,bq25975
|
||||
- ti,bq25960
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,watchdog-timeout-ms:
|
||||
description: |
|
||||
Watchdog timer in milli seconds. 0 disables the watchdog.
|
||||
default: 0
|
||||
minimum: 0
|
||||
maximum: 300000
|
||||
enum: [ 0, 5000, 10000, 50000, 300000]
|
||||
|
||||
ti,sc-ovp-limit-microvolt:
|
||||
description: |
|
||||
Minimum input voltage limit in micro volts with a when the charger is in
|
||||
switch cap mode. 100000 micro volt step.
|
||||
default: 17800000
|
||||
minimum: 14000000
|
||||
maximum: 22000000
|
||||
|
||||
ti,sc-ocp-limit-microamp:
|
||||
description: |
|
||||
Maximum input current limit in micro amps with a 100000 micro amp step.
|
||||
minimum: 100000
|
||||
maximum: 3300000
|
||||
|
||||
ti,bypass-ovp-limit-microvolt:
|
||||
description: |
|
||||
Minimum input voltage limit in micro volts with a when the charger is in
|
||||
switch cap mode. 50000 micro volt step.
|
||||
minimum: 7000000
|
||||
maximum: 12750000
|
||||
|
||||
ti,bypass-ocp-limit-microamp:
|
||||
description: |
|
||||
Maximum input current limit in micro amps with a 100000 micro amp step.
|
||||
minimum: 100000
|
||||
maximum: 3300000
|
||||
|
||||
ti,bypass-enable:
|
||||
type: boolean
|
||||
description: Enables bypass mode at boot time
|
||||
|
||||
interrupts:
|
||||
description: |
|
||||
Indicates that the device state has changed.
|
||||
|
||||
monitored-battery:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle to the battery node being monitored
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- monitored-battery
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bat: battery {
|
||||
compatible = "simple-battery";
|
||||
constant-charge-current-max-microamp = <4000000>;
|
||||
constant-charge-voltage-max-microvolt = <8400000>;
|
||||
precharge-current-microamp = <160000>;
|
||||
charge-term-current-microamp = <160000>;
|
||||
};
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
bq25980: charger@65 {
|
||||
compatible = "ti,bq25980";
|
||||
reg = <0x65>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
|
||||
ti,watchdog-timer = <0>;
|
||||
ti,sc-ocp-limit-microamp = <2000000>;
|
||||
ti,sc-ovp-limit-microvolt = <17800000>;
|
||||
monitored-battery = <&bat>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -51,6 +51,7 @@ properties:
|
|||
- ti,bq27621
|
||||
- ti,bq27z561
|
||||
- ti,bq28z610
|
||||
- ti,bq34z100
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -3,24 +3,32 @@ charger-manager bindings
|
|||
|
||||
Required properties :
|
||||
- compatible : "charger-manager"
|
||||
- <>-supply : for regulator consumer
|
||||
- cm-num-chargers : number of chargers
|
||||
- <>-supply : for regulator consumer, named according to cm-regulator-name
|
||||
- cm-chargers : name of chargers
|
||||
- cm-fuel-gauge : name of battery fuel gauge
|
||||
- subnode <regulator> :
|
||||
- cm-regulator-name : name of charger regulator
|
||||
- subnode <cable> :
|
||||
- cm-cable-name : name of charger cable
|
||||
- cm-cable-name : name of charger cable - one of USB, USB-HOST,
|
||||
SDP, DCP, CDP, ACA, FAST-CHARGER, SLOW-CHARGER, WPT,
|
||||
PD, DOCK, JIG, or MECHANICAL
|
||||
- cm-cable-extcon : name of extcon dev
|
||||
(optional) - cm-cable-min : minimum current of cable
|
||||
(optional) - cm-cable-max : maximum current of cable
|
||||
|
||||
Optional properties :
|
||||
- cm-name : charger manager's name (default : "battery")
|
||||
- cm-poll-mode : polling mode (enum polling_modes)
|
||||
- cm-poll-interval : polling interval
|
||||
- cm-battery-stat : battery status (enum data_source)
|
||||
- cm-fullbatt-* : data for full battery checking
|
||||
- cm-poll-mode : polling mode - 0 for disabled, 1 for always, 2 for when
|
||||
external power is connected, or 3 for when charging. If not present,
|
||||
then polling is disabled
|
||||
- cm-poll-interval : polling interval (in ms)
|
||||
- cm-battery-stat : battery status - 0 for battery always present, 1 for no
|
||||
battery, 2 to check presence via fuel gauge, or 3 to check presence
|
||||
via charger
|
||||
- cm-fullbatt-vchkdrop-volt : voltage drop (in uV) before restarting charging
|
||||
- cm-fullbatt-voltage : voltage (in uV) of full battery
|
||||
- cm-fullbatt-soc : state of charge to consider as full battery
|
||||
- cm-fullbatt-capacity : capcity (in uAh) to consider as full battery
|
||||
- cm-thermal-zone : name of external thermometer's thermal zone
|
||||
- cm-battery-* : threshold battery temperature for charging
|
||||
-cold : critical cold temperature of battery for charging
|
||||
|
@ -29,6 +37,10 @@ Optional properties :
|
|||
-temp-diff : temperature difference to allow recharging
|
||||
- cm-dis/charging-max = limits of charging duration
|
||||
|
||||
Deprecated properties:
|
||||
- cm-num-chargers
|
||||
- cm-fullbatt-vchkdrop-ms
|
||||
|
||||
Example :
|
||||
charger-manager@0 {
|
||||
compatible = "charger-manager";
|
||||
|
@ -39,13 +51,11 @@ Example :
|
|||
cm-poll-mode = <1>;
|
||||
cm-poll-interval = <30000>;
|
||||
|
||||
cm-fullbatt-vchkdrop-ms = <30000>;
|
||||
cm-fullbatt-vchkdrop-volt = <150000>;
|
||||
cm-fullbatt-soc = <100>;
|
||||
|
||||
cm-battery-stat = <3>;
|
||||
|
||||
cm-num-chargers = <3>;
|
||||
cm-chargers = "charger0", "charger1", "charger2";
|
||||
|
||||
cm-fuel-gauge = "fuelgauge0";
|
||||
|
@ -71,7 +81,7 @@ Example :
|
|||
cm-cable-max = <500000>;
|
||||
};
|
||||
cable@1 {
|
||||
cm-cable-name = "TA";
|
||||
cm-cable-name = "SDP";
|
||||
cm-cable-extcon = "extcon-dev.0";
|
||||
cm-cable-min = <650000>;
|
||||
cm-cable-max = <675000>;
|
||||
|
|
|
@ -39,6 +39,25 @@ properties:
|
|||
maxItems: 1
|
||||
description: GPIO indicating the charging status
|
||||
|
||||
charge-current-limit-gpios:
|
||||
minItems: 1
|
||||
maxItems: 32
|
||||
description: GPIOs used for current limiting
|
||||
|
||||
charge-current-limit-mapping:
|
||||
description: List of tuples with current in uA and a GPIO bitmap (in
|
||||
this order). The tuples must be provided in descending order of the
|
||||
current limit.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
items:
|
||||
items:
|
||||
- description:
|
||||
Current limit in uA
|
||||
- description:
|
||||
Encoded GPIO setting. Bit 0 represents last GPIO from the
|
||||
charge-current-limit-gpios property. Bit 1 second to last
|
||||
GPIO and so on.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
|
@ -47,6 +66,12 @@ anyOf:
|
|||
- gpios
|
||||
- required:
|
||||
- charge-status-gpios
|
||||
- required:
|
||||
- charge-current-limit-gpios
|
||||
|
||||
dependencies:
|
||||
charge-current-limit-gpios: [ charge-current-limit-mapping ]
|
||||
charge-current-limit-mapping: [ charge-current-limit-gpios ]
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
@ -60,4 +85,10 @@ examples:
|
|||
|
||||
gpios = <&gpd 28 GPIO_ACTIVE_LOW>;
|
||||
charge-status-gpios = <&gpc 27 GPIO_ACTIVE_LOW>;
|
||||
|
||||
charge-current-limit-gpios = <&gpioA 11 GPIO_ACTIVE_HIGH>,
|
||||
<&gpioA 12 GPIO_ACTIVE_HIGH>;
|
||||
charge-current-limit-mapping = <2500000 0x00>, // 2.5 A => both GPIOs low
|
||||
<700000 0x01>, // 700 mA => GPIO A.12 high
|
||||
<0 0x02>; // 0 mA => GPIO A.11 high
|
||||
};
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
* Ingenic JZ47xx battery bindings
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "ingenic,jz4740-battery".
|
||||
- io-channels: phandle and IIO specifier pair to the IIO device.
|
||||
Format described in iio-bindings.txt.
|
||||
- monitored-battery: phandle to a "simple-battery" compatible node.
|
||||
|
||||
The "monitored-battery" property must be a phandle to a node using the format
|
||||
described in battery.txt, with the following properties being required:
|
||||
|
||||
- voltage-min-design-microvolt: Drained battery voltage.
|
||||
- voltage-max-design-microvolt: Fully charged battery voltage.
|
||||
|
||||
Example:
|
||||
|
||||
#include <dt-bindings/iio/adc/ingenic,adc.h>
|
||||
|
||||
simple_battery: battery {
|
||||
compatible = "simple-battery";
|
||||
voltage-min-design-microvolt = <3600000>;
|
||||
voltage-max-design-microvolt = <4200000>;
|
||||
};
|
||||
|
||||
ingenic_battery {
|
||||
compatible = "ingenic,jz4740-battery";
|
||||
io-channels = <&adc INGENIC_ADC_BATTERY>;
|
||||
io-channel-names = "battery";
|
||||
monitored-battery = <&simple_battery>;
|
||||
};
|
|
@ -0,0 +1,61 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2019-2020 Artur Rojek
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/power/supply/ingenic,battery.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Ingenic JZ47xx battery bindings
|
||||
|
||||
maintainers:
|
||||
- Artur Rojek <contact@artur-rojek.eu>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: ingenic,jz4740-battery
|
||||
- items:
|
||||
- enum:
|
||||
- ingenic,jz4725b-battery
|
||||
- ingenic,jz4770-battery
|
||||
- const: ingenic,jz4740-battery
|
||||
|
||||
io-channels:
|
||||
maxItems: 1
|
||||
|
||||
io-channel-names:
|
||||
const: battery
|
||||
|
||||
monitored-battery:
|
||||
description: >
|
||||
phandle to a "simple-battery" compatible node.
|
||||
|
||||
This property must be a phandle to a node using the format described
|
||||
in battery.yaml, with the following properties being required:
|
||||
- voltage-min-design-microvolt: drained battery voltage,
|
||||
- voltage-max-design-microvolt: fully charged battery voltage.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- io-channels
|
||||
- io-channel-names
|
||||
- monitored-battery
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/iio/adc/ingenic,adc.h>
|
||||
|
||||
simple_battery: battery {
|
||||
compatible = "simple-battery";
|
||||
voltage-min-design-microvolt = <3600000>;
|
||||
voltage-max-design-microvolt = <4200000>;
|
||||
};
|
||||
|
||||
ingenic-battery {
|
||||
compatible = "ingenic,jz4740-battery";
|
||||
io-channels = <&adc INGENIC_ADC_BATTERY>;
|
||||
io-channel-names = "battery";
|
||||
monitored-battery = <&simple_battery>;
|
||||
};
|
|
@ -2,7 +2,9 @@ max17040_battery
|
|||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Required properties :
|
||||
- compatible : "maxim,max17040" or "maxim,max77836-battery"
|
||||
- compatible : "maxim,max17040", "maxim,max17041", "maxim,max17043",
|
||||
"maxim,max17044", "maxim,max17048", "maxim,max17049",
|
||||
"maxim,max17058", "maxim,max17059" or "maxim,max77836-battery"
|
||||
- reg: i2c slave address
|
||||
|
||||
Optional properties :
|
||||
|
@ -11,6 +13,15 @@ Optional properties :
|
|||
generated. Can be configured from 1 up to 32
|
||||
(%). If skipped the power up default value of
|
||||
4 (%) will be used.
|
||||
- maxim,double-soc : Certain devices return double the capacity.
|
||||
Specify this boolean property to divide the
|
||||
reported value in 2 and thus normalize it.
|
||||
SOC == State of Charge == Capacity.
|
||||
- maxim,rcomp : A value to compensate readings for various
|
||||
battery chemistries and operating temperatures.
|
||||
max17040,41 have 2 byte rcomp, default to
|
||||
0x97 0x00. All other devices have one byte
|
||||
rcomp, default to 0x97.
|
||||
- interrupts : Interrupt line see Documentation/devicetree/
|
||||
bindings/interrupt-controller/interrupts.txt
|
||||
- wakeup-source : This device has wakeup capabilities. Use this
|
||||
|
@ -31,3 +42,11 @@ Example:
|
|||
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
|
||||
wakeup-source;
|
||||
};
|
||||
|
||||
battery-fuel-gauge@36 {
|
||||
compatible = "maxim,max17048";
|
||||
reg = <0x36>;
|
||||
maxim,rcomp = /bits/ 8 <0x56>;
|
||||
maxim,alert-low-soc-level = <10>;
|
||||
maxim,double-soc;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/power/supply/summit,smb347-charger.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Battery charger driver for SMB345, SMB347 and SMB358
|
||||
|
||||
maintainers:
|
||||
- David Heidelberg <david@ixit.cz>
|
||||
- Dmitry Osipenko <digetx@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- summit,smb345
|
||||
- summit,smb347
|
||||
- summit,smb358
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
monitored-battery:
|
||||
description: phandle to the battery node
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
summit,enable-usb-charging:
|
||||
type: boolean
|
||||
description: Enable charging through USB.
|
||||
|
||||
summit,enable-otg-charging:
|
||||
type: boolean
|
||||
description: Provide power for USB OTG
|
||||
|
||||
summit,enable-mains-charging:
|
||||
type: boolean
|
||||
description: Enable charging through mains
|
||||
|
||||
summit,enable-charge-control:
|
||||
description: Enable charging control
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 0 # SMB3XX_CHG_ENABLE_SW SW (I2C interface)
|
||||
- 1 # SMB3XX_CHG_ENABLE_PIN_ACTIVE_LOW Pin control (Active Low)
|
||||
- 2 # SMB3XX_CHG_ENABLE_PIN_ACTIVE_HIGH Pin control (Active High)
|
||||
|
||||
summit,fast-voltage-threshold-microvolt:
|
||||
description: Voltage threshold to transit to fast charge mode (in uV)
|
||||
minimum: 2400000
|
||||
maximum: 3000000
|
||||
|
||||
summit,mains-current-limit-microamp:
|
||||
description: Maximum input current from AC/DC input (in uA)
|
||||
|
||||
summit,usb-current-limit-microamp:
|
||||
description: Maximum input current from USB input (in uA)
|
||||
|
||||
summit,charge-current-compensation-microamp:
|
||||
description: Charge current compensation (in uA)
|
||||
|
||||
summit,chip-temperature-threshold-celsius:
|
||||
description: Chip temperature for thermal regulation in °C.
|
||||
enum: [100, 110, 120, 130]
|
||||
|
||||
summit,soft-compensation-method:
|
||||
description: Soft temperature limit compensation method
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 0 # SMB3XX_SOFT_TEMP_COMPENSATE_NONE Compensation none
|
||||
- 1 # SMB3XX_SOFT_TEMP_COMPENSATE_CURRENT Current compensation
|
||||
- 2 # SMB3XX_SOFT_TEMP_COMPENSATE_VOLTAGE Voltage compensation
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- summit,smb345
|
||||
- summit,smb358
|
||||
|
||||
then:
|
||||
properties:
|
||||
summit,mains-current-limit-microamp:
|
||||
enum: [ 300000, 500000, 700000, 1000000,
|
||||
1500000, 1800000, 2000000]
|
||||
|
||||
summit,usb-current-limit-microamp:
|
||||
enum: [ 300000, 500000, 700000, 1000000,
|
||||
1500000, 1800000, 2000000]
|
||||
|
||||
summit,charge-current-compensation-microamp:
|
||||
enum: [200000, 450000, 600000, 900000]
|
||||
|
||||
else:
|
||||
properties:
|
||||
summit,mains-current-limit-microamp:
|
||||
enum: [ 300000, 500000, 700000, 900000, 1200000,
|
||||
1500000, 1800000, 2000000, 2200000, 2500000]
|
||||
|
||||
summit,usb-current-limit-microamp:
|
||||
enum: [ 300000, 500000, 700000, 900000, 1200000,
|
||||
1500000, 1800000, 2000000, 2200000, 2500000]
|
||||
|
||||
summit,charge-current-compensation-microamp:
|
||||
enum: [250000, 700000, 900000, 1200000]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
anyOf:
|
||||
- required:
|
||||
- summit,enable-usb-charging
|
||||
- required:
|
||||
- summit,enable-otg-charging
|
||||
- required:
|
||||
- summit,enable-mains-charging
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/power/summit,smb347-charger.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
charger@7f {
|
||||
compatible = "summit,smb347";
|
||||
reg = <0x7f>;
|
||||
|
||||
summit,enable-charge-control = <SMB3XX_CHG_ENABLE_PIN_ACTIVE_HIGH>;
|
||||
summit,chip-temperature-threshold-celsius = <110>;
|
||||
summit,mains-current-limit-microamp = <2000000>;
|
||||
summit,usb-current-limit-microamp = <500000>;
|
||||
summit,enable-usb-charging;
|
||||
summit,enable-mains-charging;
|
||||
|
||||
monitored-battery = <&battery>;
|
||||
};
|
||||
};
|
||||
|
||||
battery: battery-cell {
|
||||
compatible = "simple-battery";
|
||||
constant-charge-current-max-microamp = <1800000>;
|
||||
operating-range-celsius = <0 45>;
|
||||
alert-celsius = <3 42>;
|
||||
};
|
|
@ -5231,7 +5231,6 @@ F: kernel/dma/
|
|||
|
||||
DMA-BUF HEAPS FRAMEWORK
|
||||
M: Sumit Semwal <sumit.semwal@linaro.org>
|
||||
R: Andrew F. Davis <afd@ti.com>
|
||||
R: Benjamin Gaignard <benjamin.gaignard@linaro.org>
|
||||
R: Liam Mark <lmark@codeaurora.org>
|
||||
R: Laura Abbott <labbott@redhat.com>
|
||||
|
@ -11605,6 +11604,7 @@ M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
|
|||
L: linux-mips@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/mips/mscc.txt
|
||||
F: Documentation/devicetree/bindings/power/reset/ocelot-reset.txt
|
||||
F: arch/mips/boot/dts/mscc/
|
||||
F: arch/mips/configs/generic/board-ocelot.config
|
||||
F: arch/mips/generic/board-ocelot.c
|
||||
|
@ -17391,7 +17391,7 @@ S: Maintained
|
|||
F: drivers/thermal/ti-soc-thermal/
|
||||
|
||||
TI BQ27XXX POWER SUPPLY DRIVER
|
||||
R: Andrew F. Davis <afd@ti.com>
|
||||
R: Dan Murphy <dmurphy@ti.com>
|
||||
F: drivers/power/supply/bq27xxx_battery.c
|
||||
F: drivers/power/supply/bq27xxx_battery_i2c.c
|
||||
F: include/linux/power/bq27xxx_battery.h
|
||||
|
|
|
@ -369,6 +369,15 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = {
|
|||
/*
|
||||
* Tosa AC IN
|
||||
*/
|
||||
static struct gpiod_lookup_table tosa_power_gpiod_table = {
|
||||
.dev_id = "gpio-charger",
|
||||
.table = {
|
||||
GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_AC_IN,
|
||||
NULL, GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static char *tosa_ac_supplied_to[] = {
|
||||
"main-battery",
|
||||
"backup-battery",
|
||||
|
@ -378,8 +387,6 @@ static char *tosa_ac_supplied_to[] = {
|
|||
static struct gpio_charger_platform_data tosa_power_data = {
|
||||
.name = "charger",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.gpio = TOSA_GPIO_AC_IN,
|
||||
.gpio_active_low = 1,
|
||||
.supplied_to = tosa_ac_supplied_to,
|
||||
.num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to),
|
||||
};
|
||||
|
@ -951,6 +958,7 @@ static void __init tosa_init(void)
|
|||
clk_add_alias("CLK_CK3P6MI", tc6393xb_device.name, "GPIO11_CLK", NULL);
|
||||
|
||||
gpiod_add_lookup_table(&tosa_udc_gpiod_table);
|
||||
gpiod_add_lookup_table(&tosa_power_gpiod_table);
|
||||
platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/gpio_keys.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/power/gpio-charger.h>
|
||||
|
||||
#include <video/sa1100fb.h>
|
||||
|
@ -131,16 +132,23 @@ static struct irda_platform_data collie_ir_data = {
|
|||
/*
|
||||
* Collie AC IN
|
||||
*/
|
||||
static struct gpiod_lookup_table collie_power_gpiod_table = {
|
||||
.dev_id = "gpio-charger",
|
||||
.table = {
|
||||
GPIO_LOOKUP("gpio", COLLIE_GPIO_AC_IN,
|
||||
NULL, GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static char *collie_ac_supplied_to[] = {
|
||||
"main-battery",
|
||||
"backup-battery",
|
||||
};
|
||||
|
||||
|
||||
static struct gpio_charger_platform_data collie_power_data = {
|
||||
.name = "charger",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.gpio = COLLIE_GPIO_AC_IN,
|
||||
.supplied_to = collie_ac_supplied_to,
|
||||
.num_supplicants = ARRAY_SIZE(collie_ac_supplied_to),
|
||||
};
|
||||
|
@ -386,6 +394,8 @@ static void __init collie_init(void)
|
|||
|
||||
platform_scoop_config = &collie_pcmcia_config;
|
||||
|
||||
gpiod_add_lookup_table(&collie_power_gpiod_table);
|
||||
|
||||
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
|
||||
|
|
|
@ -129,10 +129,10 @@ config POWER_RESET_QCOM_PON
|
|||
|
||||
config POWER_RESET_OCELOT_RESET
|
||||
bool "Microsemi Ocelot reset driver"
|
||||
depends on MSCC_OCELOT || COMPILE_TEST
|
||||
depends on MSCC_OCELOT || ARCH_SPARX5 || COMPILE_TEST
|
||||
select MFD_SYSCON
|
||||
help
|
||||
This driver supports restart for Microsemi Ocelot SoC.
|
||||
This driver supports restart for Microsemi Ocelot SoC and similar.
|
||||
|
||||
config POWER_RESET_OXNAS
|
||||
bool "OXNAS SoC restart driver"
|
||||
|
|
|
@ -15,15 +15,20 @@
|
|||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct reset_props {
|
||||
const char *syscon;
|
||||
u32 protect_reg;
|
||||
u32 vcore_protect;
|
||||
u32 if_si_owner_bit;
|
||||
};
|
||||
|
||||
struct ocelot_reset_context {
|
||||
void __iomem *base;
|
||||
struct regmap *cpu_ctrl;
|
||||
const struct reset_props *props;
|
||||
struct notifier_block restart_handler;
|
||||
};
|
||||
|
||||
#define ICPU_CFG_CPU_SYSTEM_CTRL_RESET 0x20
|
||||
#define CORE_RST_PROTECT BIT(2)
|
||||
|
||||
#define SOFT_CHIP_RST BIT(0)
|
||||
|
||||
#define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
|
||||
|
@ -31,7 +36,6 @@ struct ocelot_reset_context {
|
|||
#define IF_SI_OWNER_SISL 0
|
||||
#define IF_SI_OWNER_SIBM 1
|
||||
#define IF_SI_OWNER_SIMC 2
|
||||
#define IF_SI_OWNER_OFFSET 4
|
||||
|
||||
static int ocelot_restart_handle(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
|
@ -39,15 +43,18 @@ static int ocelot_restart_handle(struct notifier_block *this,
|
|||
struct ocelot_reset_context *ctx = container_of(this, struct
|
||||
ocelot_reset_context,
|
||||
restart_handler);
|
||||
u32 if_si_owner_bit = ctx->props->if_si_owner_bit;
|
||||
|
||||
/* Make sure the core is not protected from reset */
|
||||
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_RESET,
|
||||
CORE_RST_PROTECT, 0);
|
||||
regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
|
||||
ctx->props->vcore_protect, 0);
|
||||
|
||||
/* Make the SI back to boot mode */
|
||||
regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
|
||||
IF_SI_OWNER_MASK << IF_SI_OWNER_OFFSET,
|
||||
IF_SI_OWNER_SIBM << IF_SI_OWNER_OFFSET);
|
||||
IF_SI_OWNER_MASK << if_si_owner_bit,
|
||||
IF_SI_OWNER_SIBM << if_si_owner_bit);
|
||||
|
||||
pr_emerg("Resetting SoC\n");
|
||||
|
||||
writel(SOFT_CHIP_RST, ctx->base);
|
||||
|
||||
|
@ -72,9 +79,13 @@ static int ocelot_reset_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(ctx->base))
|
||||
return PTR_ERR(ctx->base);
|
||||
|
||||
ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon");
|
||||
if (IS_ERR(ctx->cpu_ctrl))
|
||||
ctx->props = device_get_match_data(dev);
|
||||
|
||||
ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible(ctx->props->syscon);
|
||||
if (IS_ERR(ctx->cpu_ctrl)) {
|
||||
dev_err(dev, "No syscon map: %s\n", ctx->props->syscon);
|
||||
return PTR_ERR(ctx->cpu_ctrl);
|
||||
}
|
||||
|
||||
ctx->restart_handler.notifier_call = ocelot_restart_handle;
|
||||
ctx->restart_handler.priority = 192;
|
||||
|
@ -85,9 +96,29 @@ static int ocelot_reset_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static const struct reset_props reset_props_ocelot = {
|
||||
.syscon = "mscc,ocelot-cpu-syscon",
|
||||
.protect_reg = 0x20,
|
||||
.vcore_protect = BIT(2),
|
||||
.if_si_owner_bit = 4,
|
||||
};
|
||||
|
||||
static const struct reset_props reset_props_sparx5 = {
|
||||
.syscon = "microchip,sparx5-cpu-syscon",
|
||||
.protect_reg = 0x84,
|
||||
.vcore_protect = BIT(10),
|
||||
.if_si_owner_bit = 6,
|
||||
};
|
||||
|
||||
static const struct of_device_id ocelot_reset_of_match[] = {
|
||||
{ .compatible = "mscc,ocelot-chip-reset" },
|
||||
{}
|
||||
{
|
||||
.compatible = "mscc,ocelot-chip-reset",
|
||||
.data = &reset_props_ocelot
|
||||
}, {
|
||||
.compatible = "microchip,sparx5-chip-reset",
|
||||
.data = &reset_props_sparx5
|
||||
},
|
||||
{ /*sentinel*/ }
|
||||
};
|
||||
|
||||
static struct platform_driver ocelot_reset_driver = {
|
||||
|
|
|
@ -164,7 +164,7 @@ config BATTERY_DS2782
|
|||
|
||||
config BATTERY_LEGO_EV3
|
||||
tristate "LEGO MINDSTORMS EV3 battery"
|
||||
depends on OF && IIO && GPIOLIB
|
||||
depends on OF && IIO && GPIOLIB && (ARCH_DAVINCI_DA850 || COMPILE_TEST)
|
||||
help
|
||||
Say Y here to enable support for the LEGO MINDSTORMS EV3 battery.
|
||||
|
||||
|
@ -367,10 +367,15 @@ config AXP288_FUEL_GAUGE
|
|||
config BATTERY_MAX17040
|
||||
tristate "Maxim MAX17040 Fuel Gauge"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
|
||||
in handheld and portable equipment. The MAX17040 is configured
|
||||
to operate with a single lithium cell
|
||||
Maxim models with ModelGauge are fuel-gauge systems for lithium-ion
|
||||
(Li+) batteries in handheld and portable equipment, including
|
||||
max17040, max17041, max17043, max17044, max17048, max17049, max17058,
|
||||
max17059. It is also included in some batteries like max77836.
|
||||
|
||||
Driver supports reporting SOC (State of Charge, i.e capacity),
|
||||
voltage and configurable low-SOC wakeup interrupt.
|
||||
|
||||
config BATTERY_MAX17042
|
||||
tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
|
||||
|
@ -631,13 +636,22 @@ config CHARGER_BQ25890
|
|||
help
|
||||
Say Y to enable support for the TI BQ25890 battery charger.
|
||||
|
||||
config CHARGER_BQ25980
|
||||
tristate "TI BQ25980 battery charger driver"
|
||||
depends on I2C
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y to enable support for the TI BQ25980, BQ25975 and BQ25960
|
||||
series of fast battery chargers.
|
||||
|
||||
config CHARGER_SMB347
|
||||
tristate "Summit Microelectronics SMB347 Battery Charger"
|
||||
tristate "Summit Microelectronics SMB3XX Battery Charger"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y to include support for Summit Microelectronics SMB347
|
||||
Battery Charger.
|
||||
Say Y to include support for Summit Microelectronics SMB345,
|
||||
SMB347 or SMB358 Battery Charger.
|
||||
|
||||
config CHARGER_TPS65090
|
||||
tristate "TPS65090 battery charger driver"
|
||||
|
@ -752,4 +766,12 @@ config CHARGER_WILCO
|
|||
information can be found in
|
||||
Documentation/ABI/testing/sysfs-class-power-wilco
|
||||
|
||||
config RN5T618_POWER
|
||||
tristate "RN5T618 charger/fuel gauge support"
|
||||
depends on MFD_RN5T618
|
||||
help
|
||||
Say Y here to have support for RN5T618 PMIC family fuel gauge and charger.
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called rn5t618_power.
|
||||
|
||||
endif # POWER_SUPPLY
|
||||
|
|
|
@ -84,6 +84,7 @@ obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o
|
|||
obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o
|
||||
obj-$(CONFIG_CHARGER_BQ2515X) += bq2515x_charger.o
|
||||
obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
|
||||
obj-$(CONFIG_CHARGER_BQ25980) += bq25980_charger.o
|
||||
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
|
||||
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
|
||||
obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
|
||||
|
@ -96,3 +97,4 @@ obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
|
|||
obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
|
||||
obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
|
||||
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
|
||||
obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
|
||||
|
|
|
@ -653,7 +653,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
|
|||
|
||||
/*
|
||||
* negative value for Discharging
|
||||
* convert 2's compliment into decimal
|
||||
* convert 2's complement into decimal
|
||||
*/
|
||||
if (high & 0x10)
|
||||
val = (low | (high << 8) | 0xFFFFE000);
|
||||
|
@ -781,7 +781,7 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work)
|
|||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
/* Check for sign bit in case of negative value, 2's compliment */
|
||||
/* Check for sign bit in case of negative value, 2's complement */
|
||||
if (high & 0x10)
|
||||
val = (low | (med << 8) | (high << 16) | 0xFFE00000);
|
||||
else
|
||||
|
|
|
@ -1152,6 +1152,7 @@ static const struct of_device_id bq24257_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, bq24257_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id bq24257_acpi_match[] = {
|
||||
{ "BQ242500", BQ24250 },
|
||||
{ "BQ242510", BQ24251 },
|
||||
|
@ -1159,6 +1160,7 @@ static const struct acpi_device_id bq24257_acpi_match[] = {
|
|||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bq24257_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver bq24257_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -168,7 +168,7 @@ enum bq2515x_id {
|
|||
* @device_id: value of device_id
|
||||
* @mains_online: boolean value indicating power supply online
|
||||
*
|
||||
* @bq2515x_init_data init_data: charger initialization data structure
|
||||
* @init_data: charger initialization data structure
|
||||
*/
|
||||
struct bq2515x_device {
|
||||
struct power_supply *mains;
|
||||
|
@ -188,7 +188,7 @@ struct bq2515x_device {
|
|||
struct bq2515x_init_data init_data;
|
||||
};
|
||||
|
||||
static struct reg_default bq25150_reg_defaults[] = {
|
||||
static const struct reg_default bq25150_reg_defaults[] = {
|
||||
{BQ2515X_FLAG0, 0x0},
|
||||
{BQ2515X_FLAG1, 0x0},
|
||||
{BQ2515X_FLAG2, 0x0},
|
||||
|
@ -227,7 +227,7 @@ static struct reg_default bq25150_reg_defaults[] = {
|
|||
{BQ2515X_DEVICE_ID, 0x20},
|
||||
};
|
||||
|
||||
static struct reg_default bq25155_reg_defaults[] = {
|
||||
static const struct reg_default bq25155_reg_defaults[] = {
|
||||
{BQ2515X_FLAG0, 0x0},
|
||||
{BQ2515X_FLAG1, 0x0},
|
||||
{BQ2515X_FLAG2, 0x0},
|
||||
|
@ -886,14 +886,14 @@ static int bq2515x_battery_get_property(struct power_supply *psy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static enum power_supply_property bq2515x_battery_properties[] = {
|
||||
static const enum power_supply_property bq2515x_battery_properties[] = {
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq2515x_mains_properties[] = {
|
||||
static const enum power_supply_property bq2515x_mains_properties[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
|
@ -905,7 +905,7 @@ static enum power_supply_property bq2515x_mains_properties[] = {
|
|||
POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
|
||||
};
|
||||
|
||||
static struct power_supply_desc bq2515x_mains_desc = {
|
||||
static const struct power_supply_desc bq2515x_mains_desc = {
|
||||
.name = "bq2515x-mains",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.get_property = bq2515x_mains_get_property,
|
||||
|
@ -915,7 +915,7 @@ static struct power_supply_desc bq2515x_mains_desc = {
|
|||
.property_is_writeable = bq2515x_power_supply_property_is_writeable,
|
||||
};
|
||||
|
||||
static struct power_supply_desc bq2515x_battery_desc = {
|
||||
static const struct power_supply_desc bq2515x_battery_desc = {
|
||||
.name = "bq2515x-battery",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.get_property = bq2515x_battery_get_property,
|
||||
|
|
|
@ -83,6 +83,8 @@ struct bq25890_init_data {
|
|||
u8 boostf; /* boost frequency */
|
||||
u8 ilim_en; /* enable ILIM pin */
|
||||
u8 treg; /* thermal regulation threshold */
|
||||
u8 rbatcomp; /* IBAT sense resistor value */
|
||||
u8 vclamp; /* IBAT compensation voltage limit */
|
||||
};
|
||||
|
||||
struct bq25890_state {
|
||||
|
@ -258,6 +260,8 @@ enum bq25890_table_ids {
|
|||
TBL_VREG,
|
||||
TBL_BOOSTV,
|
||||
TBL_SYSVMIN,
|
||||
TBL_VBATCOMP,
|
||||
TBL_RBATCOMP,
|
||||
|
||||
/* lookup tables */
|
||||
TBL_TREG,
|
||||
|
@ -299,6 +303,8 @@ static const union {
|
|||
[TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */
|
||||
[TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */
|
||||
[TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */
|
||||
[TBL_VBATCOMP] ={ .rt = {0, 224000, 32000} }, /* uV */
|
||||
[TBL_RBATCOMP] ={ .rt = {0, 140000, 20000} }, /* uOhm */
|
||||
|
||||
/* lookup tables */
|
||||
[TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
|
||||
|
@ -648,7 +654,9 @@ static int bq25890_hw_init(struct bq25890_device *bq)
|
|||
{F_BOOSTI, bq->init_data.boosti},
|
||||
{F_BOOSTF, bq->init_data.boostf},
|
||||
{F_EN_ILIM, bq->init_data.ilim_en},
|
||||
{F_TREG, bq->init_data.treg}
|
||||
{F_TREG, bq->init_data.treg},
|
||||
{F_BATCMP, bq->init_data.rbatcomp},
|
||||
{F_VCLAMP, bq->init_data.vclamp},
|
||||
};
|
||||
|
||||
ret = bq25890_chip_reset(bq);
|
||||
|
@ -859,11 +867,14 @@ static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
|
|||
{"ti,boost-max-current", false, TBL_BOOSTI, &init->boosti},
|
||||
|
||||
/* optional properties */
|
||||
{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg}
|
||||
{"ti,thermal-regulation-threshold", true, TBL_TREG, &init->treg},
|
||||
{"ti,ibatcomp-micro-ohms", true, TBL_RBATCOMP, &init->rbatcomp},
|
||||
{"ti,ibatcomp-clamp-microvolt", true, TBL_VBATCOMP, &init->vclamp},
|
||||
};
|
||||
|
||||
/* initialize data for optional properties */
|
||||
init->treg = 3; /* 120 degrees Celsius */
|
||||
init->rbatcomp = init->vclamp = 0; /* IBAT compensation disabled */
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(props); i++) {
|
||||
ret = device_property_read_u32(bq->dev, props[i].name,
|
||||
|
@ -1073,11 +1084,13 @@ static const struct of_device_id bq25890_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, bq25890_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id bq25890_acpi_match[] = {
|
||||
{"BQ258900", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bq25890_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver bq25890_driver = {
|
||||
.driver = {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,178 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ */
|
||||
|
||||
#ifndef BQ25980_CHARGER_H
|
||||
#define BQ25980_CHARGER_H
|
||||
|
||||
#define BQ25980_MANUFACTURER "Texas Instruments"
|
||||
|
||||
#define BQ25980_BATOVP 0x0
|
||||
#define BQ25980_BATOVP_ALM 0x1
|
||||
#define BQ25980_BATOCP 0x2
|
||||
#define BQ25980_BATOCP_ALM 0x3
|
||||
#define BQ25980_BATUCP_ALM 0x4
|
||||
#define BQ25980_CHRGR_CTRL_1 0x5
|
||||
#define BQ25980_BUSOVP 0x6
|
||||
#define BQ25980_BUSOVP_ALM 0x7
|
||||
#define BQ25980_BUSOCP 0x8
|
||||
#define BQ25980_BUSOCP_ALM 0x9
|
||||
#define BQ25980_TEMP_CONTROL 0xA
|
||||
#define BQ25980_TDIE_ALM 0xB
|
||||
#define BQ25980_TSBUS_FLT 0xC
|
||||
#define BQ25980_TSBAT_FLG 0xD
|
||||
#define BQ25980_VAC_CONTROL 0xE
|
||||
#define BQ25980_CHRGR_CTRL_2 0xF
|
||||
#define BQ25980_CHRGR_CTRL_3 0x10
|
||||
#define BQ25980_CHRGR_CTRL_4 0x11
|
||||
#define BQ25980_CHRGR_CTRL_5 0x12
|
||||
#define BQ25980_STAT1 0x13
|
||||
#define BQ25980_STAT2 0x14
|
||||
#define BQ25980_STAT3 0x15
|
||||
#define BQ25980_STAT4 0x16
|
||||
#define BQ25980_STAT5 0x17
|
||||
#define BQ25980_FLAG1 0x18
|
||||
#define BQ25980_FLAG2 0x19
|
||||
#define BQ25980_FLAG3 0x1A
|
||||
#define BQ25980_FLAG4 0x1B
|
||||
#define BQ25980_FLAG5 0x1C
|
||||
#define BQ25980_MASK1 0x1D
|
||||
#define BQ25980_MASK2 0x1E
|
||||
#define BQ25980_MASK3 0x1F
|
||||
#define BQ25980_MASK4 0x20
|
||||
#define BQ25980_MASK5 0x21
|
||||
#define BQ25980_DEVICE_INFO 0x22
|
||||
#define BQ25980_ADC_CONTROL1 0x23
|
||||
#define BQ25980_ADC_CONTROL2 0x24
|
||||
#define BQ25980_IBUS_ADC_MSB 0x25
|
||||
#define BQ25980_IBUS_ADC_LSB 0x26
|
||||
#define BQ25980_VBUS_ADC_MSB 0x27
|
||||
#define BQ25980_VBUS_ADC_LSB 0x28
|
||||
#define BQ25980_VAC1_ADC_MSB 0x29
|
||||
#define BQ25980_VAC1_ADC_LSB 0x2A
|
||||
#define BQ25980_VAC2_ADC_MSB 0x2B
|
||||
#define BQ25980_VAC2_ADC_LSB 0x2C
|
||||
#define BQ25980_VOUT_ADC_MSB 0x2D
|
||||
#define BQ25980_VOUT_ADC_LSB 0x2E
|
||||
#define BQ25980_VBAT_ADC_MSB 0x2F
|
||||
#define BQ25980_VBAT_ADC_LSB 0x30
|
||||
#define BQ25980_IBAT_ADC_MSB 0x31
|
||||
#define BQ25980_IBAT_ADC_LSB 0x32
|
||||
#define BQ25980_TSBUS_ADC_MSB 0x33
|
||||
#define BQ25980_TSBUS_ADC_LSB 0x34
|
||||
#define BQ25980_TSBAT_ADC_MSB 0x35
|
||||
#define BQ25980_TSBAT_ADC_LSB 0x36
|
||||
#define BQ25980_TDIE_ADC_MSB 0x37
|
||||
#define BQ25980_TDIE_ADC_LSB 0x38
|
||||
#define BQ25980_DEGLITCH_TIME 0x39
|
||||
#define BQ25980_CHRGR_CTRL_6 0x3A
|
||||
|
||||
#define BQ25980_BUSOCP_STEP_uA 250000
|
||||
#define BQ25980_BUSOCP_OFFSET_uA 1000000
|
||||
|
||||
#define BQ25980_BUSOCP_DFLT_uA 4250000
|
||||
#define BQ25975_BUSOCP_DFLT_uA 4250000
|
||||
#define BQ25960_BUSOCP_DFLT_uA 3250000
|
||||
|
||||
#define BQ25980_BUSOCP_MIN_uA 1000000
|
||||
|
||||
#define BQ25980_BUSOCP_SC_MAX_uA 5750000
|
||||
#define BQ25975_BUSOCP_SC_MAX_uA 5750000
|
||||
#define BQ25960_BUSOCP_SC_MAX_uA 3750000
|
||||
|
||||
#define BQ25980_BUSOCP_BYP_MAX_uA 8500000
|
||||
#define BQ25975_BUSOCP_BYP_MAX_uA 8500000
|
||||
#define BQ25960_BUSOCP_BYP_MAX_uA 5750000
|
||||
|
||||
#define BQ25980_BUSOVP_SC_STEP_uV 100000
|
||||
#define BQ25975_BUSOVP_SC_STEP_uV 50000
|
||||
#define BQ25960_BUSOVP_SC_STEP_uV 50000
|
||||
#define BQ25980_BUSOVP_SC_OFFSET_uV 14000000
|
||||
#define BQ25975_BUSOVP_SC_OFFSET_uV 7000000
|
||||
#define BQ25960_BUSOVP_SC_OFFSET_uV 7000000
|
||||
|
||||
#define BQ25980_BUSOVP_BYP_STEP_uV 50000
|
||||
#define BQ25975_BUSOVP_BYP_STEP_uV 25000
|
||||
#define BQ25960_BUSOVP_BYP_STEP_uV 25000
|
||||
#define BQ25980_BUSOVP_BYP_OFFSET_uV 7000000
|
||||
#define BQ25975_BUSOVP_BYP_OFFSET_uV 3500000
|
||||
#define BQ25960_BUSOVP_BYP_OFFSET_uV 3500000
|
||||
|
||||
#define BQ25980_BUSOVP_DFLT_uV 17800000
|
||||
#define BQ25980_BUSOVP_BYPASS_DFLT_uV 8900000
|
||||
#define BQ25975_BUSOVP_DFLT_uV 8900000
|
||||
#define BQ25975_BUSOVP_BYPASS_DFLT_uV 4450000
|
||||
#define BQ25960_BUSOVP_DFLT_uV 8900000
|
||||
|
||||
#define BQ25980_BUSOVP_SC_MIN_uV 14000000
|
||||
#define BQ25975_BUSOVP_SC_MIN_uV 7000000
|
||||
#define BQ25960_BUSOVP_SC_MIN_uV 7000000
|
||||
#define BQ25980_BUSOVP_BYP_MIN_uV 7000000
|
||||
#define BQ25975_BUSOVP_BYP_MIN_uV 3500000
|
||||
#define BQ25960_BUSOVP_BYP_MIN_uV 3500000
|
||||
|
||||
#define BQ25980_BUSOVP_SC_MAX_uV 22000000
|
||||
#define BQ25975_BUSOVP_SC_MAX_uV 12750000
|
||||
#define BQ25960_BUSOVP_SC_MAX_uV 12750000
|
||||
|
||||
#define BQ25980_BUSOVP_BYP_MAX_uV 12750000
|
||||
#define BQ25975_BUSOVP_BYP_MAX_uV 6500000
|
||||
#define BQ25960_BUSOVP_BYP_MAX_uV 6500000
|
||||
|
||||
#define BQ25980_BATOVP_STEP_uV 20000
|
||||
#define BQ25975_BATOVP_STEP_uV 10000
|
||||
#define BQ25960_BATOVP_STEP_uV 10000
|
||||
|
||||
#define BQ25980_BATOVP_OFFSET_uV 7000000
|
||||
#define BQ25975_BATOVP_OFFSET_uV 3500000
|
||||
#define BQ25960_BATOVP_OFFSET_uV 3500000
|
||||
|
||||
#define BQ25980_BATOVP_DFLT_uV 14000000
|
||||
#define BQ25975_BATOVP_DFLT_uV 8900000
|
||||
#define BQ25960_BATOVP_DFLT_uV 8900000
|
||||
|
||||
#define BQ25980_BATOVP_MIN_uV 7000000
|
||||
#define BQ25975_BATOVP_MIN_uV 3500000
|
||||
#define BQ25960_BATOVP_MIN_uV 3500000
|
||||
|
||||
#define BQ25980_BATOVP_MAX_uV 9540000
|
||||
#define BQ25975_BATOVP_MAX_uV 4770000
|
||||
#define BQ25960_BATOVP_MAX_uV 4770000
|
||||
|
||||
#define BQ25980_BATOCP_STEP_uA 100000
|
||||
|
||||
#define BQ25980_BATOCP_MASK GENMASK(6, 0)
|
||||
|
||||
#define BQ25980_BATOCP_DFLT_uA 8100000
|
||||
#define BQ25960_BATOCP_DFLT_uA 6100000
|
||||
|
||||
#define BQ25980_BATOCP_MIN_uA 2000000
|
||||
|
||||
#define BQ25980_BATOCP_MAX_uA 11000000
|
||||
#define BQ25975_BATOCP_MAX_uA 11000000
|
||||
#define BQ25960_BATOCP_MAX_uA 7000000
|
||||
|
||||
#define BQ25980_ENABLE_HIZ 0xff
|
||||
#define BQ25980_DISABLE_HIZ 0x0
|
||||
#define BQ25980_EN_BYPASS BIT(3)
|
||||
#define BQ25980_STAT1_OVP_MASK (BIT(6) | BIT(5) | BIT(0))
|
||||
#define BQ25980_STAT3_OVP_MASK (BIT(7) | BIT(6))
|
||||
#define BQ25980_STAT1_OCP_MASK BIT(3)
|
||||
#define BQ25980_STAT2_OCP_MASK (BIT(6) | BIT(1))
|
||||
#define BQ25980_STAT4_TFLT_MASK GENMASK(5, 1)
|
||||
#define BQ25980_WD_STAT BIT(0)
|
||||
#define BQ25980_PRESENT_MASK GENMASK(4, 2)
|
||||
#define BQ25980_CHG_EN BIT(4)
|
||||
#define BQ25980_EN_HIZ BIT(6)
|
||||
#define BQ25980_ADC_EN BIT(7)
|
||||
|
||||
#define BQ25980_ADC_VOLT_STEP_uV 1000
|
||||
#define BQ25980_ADC_CURR_STEP_uA 1000
|
||||
#define BQ25980_ADC_POLARITY_BIT BIT(7)
|
||||
|
||||
#define BQ25980_WATCHDOG_MASK GENMASK(4, 3)
|
||||
#define BQ25980_WATCHDOG_DIS BIT(2)
|
||||
#define BQ25980_WATCHDOG_MAX 300000
|
||||
#define BQ25980_WATCHDOG_MIN 0
|
||||
#define BQ25980_NUM_WD_VAL 4
|
||||
|
||||
#endif /* BQ25980_CHARGER_H */
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* BQ27xxx battery driver
|
||||
*
|
||||
|
@ -9,14 +10,6 @@
|
|||
*
|
||||
* Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Datasheets:
|
||||
* https://www.ti.com/product/bq27000
|
||||
* https://www.ti.com/product/bq27200
|
||||
|
@ -45,6 +38,7 @@
|
|||
* https://www.ti.com/product/bq27621-g1
|
||||
* https://www.ti.com/product/bq27z561
|
||||
* https://www.ti.com/product/bq28z610
|
||||
* https://www.ti.com/product/bq34z100-g1
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
@ -83,7 +77,7 @@
|
|||
|
||||
/* BQ27Z561 has different layout for Flags register */
|
||||
#define BQ27Z561_FLAG_FDC BIT(4) /* Battery fully discharged */
|
||||
#define BQ27Z561_FLAG_FC BIT(5) /* Battery fully charged */
|
||||
#define BQ27Z561_FLAG_FC BIT(5) /* Battery fully charged */
|
||||
#define BQ27Z561_FLAG_DIS_CH BIT(6) /* Battery is discharging */
|
||||
|
||||
/* control register params */
|
||||
|
@ -483,6 +477,26 @@ static u8
|
|||
[BQ27XXX_REG_DCAP] = 0x3c,
|
||||
[BQ27XXX_REG_AP] = 0x22,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
bq34z100_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x0c,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x2a,
|
||||
[BQ27XXX_REG_VOLT] = 0x08,
|
||||
[BQ27XXX_REG_AI] = 0x0a,
|
||||
[BQ27XXX_REG_FLAGS] = 0x0e,
|
||||
[BQ27XXX_REG_TTE] = 0x18,
|
||||
[BQ27XXX_REG_TTF] = 0x1a,
|
||||
[BQ27XXX_REG_TTES] = 0x1e,
|
||||
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_NAC] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_FCC] = 0x06,
|
||||
[BQ27XXX_REG_CYCT] = 0x2c,
|
||||
[BQ27XXX_REG_AE] = 0x24,
|
||||
[BQ27XXX_REG_SOC] = 0x02,
|
||||
[BQ27XXX_REG_DCAP] = 0x3c,
|
||||
[BQ27XXX_REG_AP] = 0x22,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27000_props[] = {
|
||||
|
@ -757,6 +771,27 @@ static enum power_supply_property bq28z610_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq34z100_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
POWER_SUPPLY_PROP_ENERGY_NOW,
|
||||
POWER_SUPPLY_PROP_POWER_AVG,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
struct bq27xxx_dm_reg {
|
||||
u8 subclass_id;
|
||||
u8 offset;
|
||||
|
@ -854,13 +889,17 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
|
|||
|
||||
#define bq27z561_dm_regs 0
|
||||
#define bq28z610_dm_regs 0
|
||||
#define bq34z100_dm_regs 0
|
||||
|
||||
#define BQ27XXX_O_ZERO 0x00000001
|
||||
#define BQ27XXX_O_OTDC 0x00000002 /* has OTC/OTD overtemperature flags */
|
||||
#define BQ27XXX_O_UTOT 0x00000004 /* has OT overtemperature flag */
|
||||
#define BQ27XXX_O_CFGUP 0x00000008
|
||||
#define BQ27XXX_O_RAM 0x00000010
|
||||
#define BQ27Z561_O_BITS 0x00000020
|
||||
#define BQ27XXX_O_ZERO BIT(0)
|
||||
#define BQ27XXX_O_OTDC BIT(1) /* has OTC/OTD overtemperature flags */
|
||||
#define BQ27XXX_O_UTOT BIT(2) /* has OT overtemperature flag */
|
||||
#define BQ27XXX_O_CFGUP BIT(3)
|
||||
#define BQ27XXX_O_RAM BIT(4)
|
||||
#define BQ27Z561_O_BITS BIT(5)
|
||||
#define BQ27XXX_O_SOC_SI BIT(6) /* SoC is single register */
|
||||
#define BQ27XXX_O_HAS_CI BIT(7) /* has Capacity Inaccurate flag */
|
||||
#define BQ27XXX_O_MUL_CHEM BIT(8) /* multiple chemistries supported */
|
||||
|
||||
#define BQ27XXX_DATA(ref, key, opt) { \
|
||||
.opts = (opt), \
|
||||
|
@ -878,8 +917,8 @@ static struct {
|
|||
enum power_supply_property *props;
|
||||
size_t props_size;
|
||||
} bq27xxx_chip_data[] = {
|
||||
[BQ27000] = BQ27XXX_DATA(bq27000, 0 , BQ27XXX_O_ZERO),
|
||||
[BQ27010] = BQ27XXX_DATA(bq27010, 0 , BQ27XXX_O_ZERO),
|
||||
[BQ27000] = BQ27XXX_DATA(bq27000, 0 , BQ27XXX_O_ZERO | BQ27XXX_O_SOC_SI | BQ27XXX_O_HAS_CI),
|
||||
[BQ27010] = BQ27XXX_DATA(bq27010, 0 , BQ27XXX_O_ZERO | BQ27XXX_O_SOC_SI | BQ27XXX_O_HAS_CI),
|
||||
[BQ2750X] = BQ27XXX_DATA(bq2750x, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ2751X] = BQ27XXX_DATA(bq2751x, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ2752X] = BQ27XXX_DATA(bq2752x, 0 , BQ27XXX_O_OTDC),
|
||||
|
@ -907,6 +946,8 @@ static struct {
|
|||
[BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
|
||||
[BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS),
|
||||
[BQ28Z610] = BQ27XXX_DATA(bq28z610, 0 , BQ27Z561_O_BITS),
|
||||
[BQ34Z100] = BQ27XXX_DATA(bq34z100, 0 , BQ27XXX_O_OTDC | BQ27XXX_O_SOC_SI | \
|
||||
BQ27XXX_O_HAS_CI | BQ27XXX_O_MUL_CHEM),
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(bq27xxx_list_lock);
|
||||
|
@ -1426,7 +1467,7 @@ static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di)
|
|||
{
|
||||
int soc;
|
||||
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
if (di->opts & BQ27XXX_O_SOC_SI)
|
||||
soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true);
|
||||
else
|
||||
soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
|
||||
|
@ -1664,7 +1705,7 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di)
|
|||
void bq27xxx_battery_update(struct bq27xxx_device_info *di)
|
||||
{
|
||||
struct bq27xxx_reg_cache cache = {0, };
|
||||
bool has_ci_flag = di->opts & BQ27XXX_O_ZERO;
|
||||
bool has_ci_flag = di->opts & BQ27XXX_O_HAS_CI;
|
||||
bool has_singe_flag = di->opts & BQ27XXX_O_ZERO;
|
||||
|
||||
cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag);
|
||||
|
@ -1772,8 +1813,6 @@ static int bq27xxx_battery_status(struct bq27xxx_device_info *di,
|
|||
status = POWER_SUPPLY_STATUS_FULL;
|
||||
else if (di->cache.flags & BQ27000_FLAG_CHGS)
|
||||
status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else if (power_supply_am_i_supplied(di->bat) > 0)
|
||||
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
else
|
||||
status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
} else if (di->opts & BQ27Z561_O_BITS) {
|
||||
|
@ -1792,6 +1831,10 @@ static int bq27xxx_battery_status(struct bq27xxx_device_info *di,
|
|||
status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
|
||||
if ((status == POWER_SUPPLY_STATUS_DISCHARGING) &&
|
||||
(power_supply_am_i_supplied(di->bat) > 0))
|
||||
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
|
||||
val->intval = status;
|
||||
|
||||
return 0;
|
||||
|
@ -1916,7 +1959,10 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
|
|||
ret = bq27xxx_simple_value(di->cache.time_to_full, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
if (di->opts & BQ27XXX_O_MUL_CHEM)
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
||||
ret = bq27xxx_simple_value(bq27xxx_battery_read_nac(di), val);
|
||||
|
@ -1992,13 +2038,9 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
|
|||
psy_desc->external_power_changed = bq27xxx_external_power_changed;
|
||||
|
||||
di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg);
|
||||
if (IS_ERR(di->bat)) {
|
||||
if (PTR_ERR(di->bat) == -EPROBE_DEFER)
|
||||
dev_dbg(di->dev, "failed to register battery, deferring probe\n");
|
||||
else
|
||||
dev_err(di->dev, "failed to register battery\n");
|
||||
return PTR_ERR(di->bat);
|
||||
}
|
||||
if (IS_ERR(di->bat))
|
||||
return dev_err_probe(di->dev, PTR_ERR(di->bat),
|
||||
"failed to register battery\n");
|
||||
|
||||
bq27xxx_battery_settings(di);
|
||||
bq27xxx_battery_update(di);
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* BQ27xxx battery monitor HDQ/1-wire driver
|
||||
*
|
||||
* Copyright (C) 2007-2017 Texas Instruments Incorporated - https://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -1,17 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* BQ27xxx battery monitor I2C driver
|
||||
*
|
||||
* Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
|
||||
* Andrew F. Davis <afd@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
@ -255,6 +247,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
|
|||
{ "bq27621", BQ27621 },
|
||||
{ "bq27z561", BQ27Z561 },
|
||||
{ "bq28z610", BQ28Z610 },
|
||||
{ "bq34z100", BQ34Z100 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
|
||||
|
@ -290,6 +283,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
|
|||
{ .compatible = "ti,bq27621" },
|
||||
{ .compatible = "ti,bq27z561" },
|
||||
{ .compatible = "ti,bq28z610" },
|
||||
{ .compatible = "ti,bq34z100" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table);
|
||||
|
|
|
@ -26,6 +26,29 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
u64 extcon_type;
|
||||
} extcon_mapping[] = {
|
||||
/* Current textual representations */
|
||||
{ "USB", EXTCON_USB },
|
||||
{ "USB-HOST", EXTCON_USB_HOST },
|
||||
{ "SDP", EXTCON_CHG_USB_SDP },
|
||||
{ "DCP", EXTCON_CHG_USB_DCP },
|
||||
{ "CDP", EXTCON_CHG_USB_CDP },
|
||||
{ "ACA", EXTCON_CHG_USB_ACA },
|
||||
{ "FAST-CHARGER", EXTCON_CHG_USB_FAST },
|
||||
{ "SLOW-CHARGER", EXTCON_CHG_USB_SLOW },
|
||||
{ "WPT", EXTCON_CHG_WPT },
|
||||
{ "PD", EXTCON_CHG_USB_PD },
|
||||
{ "DOCK", EXTCON_DOCK },
|
||||
{ "JIG", EXTCON_JIG },
|
||||
{ "MECHANICAL", EXTCON_MECHANICAL },
|
||||
/* Deprecated textual representations */
|
||||
{ "TA", EXTCON_CHG_USB_SDP },
|
||||
{ "CHARGE-DOWNSTREAM", EXTCON_CHG_USB_CDP },
|
||||
};
|
||||
|
||||
/*
|
||||
* Default temperature threshold for charging.
|
||||
* Every temperature units are in tenth of centigrade.
|
||||
|
@ -33,18 +56,6 @@
|
|||
#define CM_DEFAULT_RECHARGE_TEMP_DIFF 50
|
||||
#define CM_DEFAULT_CHARGE_TEMP_MAX 500
|
||||
|
||||
static const char * const default_event_names[] = {
|
||||
[CM_EVENT_UNKNOWN] = "Unknown",
|
||||
[CM_EVENT_BATT_FULL] = "Battery Full",
|
||||
[CM_EVENT_BATT_IN] = "Battery Inserted",
|
||||
[CM_EVENT_BATT_OUT] = "Battery Pulled Out",
|
||||
[CM_EVENT_BATT_OVERHEAT] = "Battery Overheat",
|
||||
[CM_EVENT_BATT_COLD] = "Battery Cold",
|
||||
[CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach",
|
||||
[CM_EVENT_CHG_START_STOP] = "Charging Start/Stop",
|
||||
[CM_EVENT_OTHERS] = "Other battery events"
|
||||
};
|
||||
|
||||
/*
|
||||
* Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for
|
||||
* delayed works so that we can run delayed works with CM_JIFFIES_SMALL
|
||||
|
@ -61,8 +72,6 @@ static const char * const default_event_names[] = {
|
|||
*/
|
||||
#define CM_RTC_SMALL (2)
|
||||
|
||||
#define UEVENT_BUF_SIZE 32
|
||||
|
||||
static LIST_HEAD(cm_list);
|
||||
static DEFINE_MUTEX(cm_list_mtx);
|
||||
|
||||
|
@ -285,6 +294,19 @@ static bool is_full_charged(struct charger_manager *cm)
|
|||
if (!fuel_gauge)
|
||||
return false;
|
||||
|
||||
/* Full, if it's over the fullbatt voltage */
|
||||
if (desc->fullbatt_uV > 0) {
|
||||
ret = get_batt_uV(cm, &uV);
|
||||
if (!ret) {
|
||||
/* Battery is already full, checks voltage drop. */
|
||||
if (cm->battery_status == POWER_SUPPLY_STATUS_FULL
|
||||
&& desc->fullbatt_vchkdrop_uV)
|
||||
uV += desc->fullbatt_vchkdrop_uV;
|
||||
if (uV >= desc->fullbatt_uV)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc->fullbatt_full_capacity > 0) {
|
||||
val.intval = 0;
|
||||
|
||||
|
@ -297,15 +319,6 @@ static bool is_full_charged(struct charger_manager *cm)
|
|||
}
|
||||
}
|
||||
|
||||
/* Full, if it's over the fullbatt voltage */
|
||||
if (desc->fullbatt_uV > 0) {
|
||||
ret = get_batt_uV(cm, &uV);
|
||||
if (!ret && uV >= desc->fullbatt_uV) {
|
||||
is_full = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Full, if the capacity is more than fullbatt_soc */
|
||||
if (desc->fullbatt_soc > 0) {
|
||||
val.intval = 0;
|
||||
|
@ -426,122 +439,6 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* try_charger_restart - Restart charging.
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
*
|
||||
* Restart charging by turning off and on the charger.
|
||||
*/
|
||||
static int try_charger_restart(struct charger_manager *cm)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (cm->emergency_stop)
|
||||
return -EAGAIN;
|
||||
|
||||
err = try_charger_enable(cm, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return try_charger_enable(cm, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* uevent_notify - Let users know something has changed.
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
* @event: the event string.
|
||||
*
|
||||
* If @event is null, it implies that uevent_notify is called
|
||||
* by resume function. When called in the resume function, cm_suspended
|
||||
* should be already reset to false in order to let uevent_notify
|
||||
* notify the recent event during the suspend to users. While
|
||||
* suspended, uevent_notify does not notify users, but tracks
|
||||
* events so that uevent_notify can notify users later after resumed.
|
||||
*/
|
||||
static void uevent_notify(struct charger_manager *cm, const char *event)
|
||||
{
|
||||
static char env_str[UEVENT_BUF_SIZE + 1] = "";
|
||||
static char env_str_save[UEVENT_BUF_SIZE + 1] = "";
|
||||
|
||||
if (cm_suspended) {
|
||||
/* Nothing in suspended-event buffer */
|
||||
if (env_str_save[0] == 0) {
|
||||
if (!strncmp(env_str, event, UEVENT_BUF_SIZE))
|
||||
return; /* status not changed */
|
||||
strncpy(env_str_save, event, UEVENT_BUF_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(env_str_save, event, UEVENT_BUF_SIZE))
|
||||
return; /* Duplicated. */
|
||||
strncpy(env_str_save, event, UEVENT_BUF_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == NULL) {
|
||||
/* No messages pending */
|
||||
if (!env_str_save[0])
|
||||
return;
|
||||
|
||||
strncpy(env_str, env_str_save, UEVENT_BUF_SIZE);
|
||||
kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE);
|
||||
env_str_save[0] = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* status not changed */
|
||||
if (!strncmp(env_str, event, UEVENT_BUF_SIZE))
|
||||
return;
|
||||
|
||||
/* save the status and notify the update */
|
||||
strncpy(env_str, event, UEVENT_BUF_SIZE);
|
||||
kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE);
|
||||
|
||||
dev_info(cm->dev, "%s\n", event);
|
||||
}
|
||||
|
||||
/**
|
||||
* fullbatt_vchk - Check voltage drop some times after "FULL" event.
|
||||
* @work: the work_struct appointing the function
|
||||
*
|
||||
* If a user has designated "fullbatt_vchkdrop_ms/uV" values with
|
||||
* charger_desc, Charger Manager checks voltage drop after the battery
|
||||
* "FULL" event. It checks whether the voltage has dropped more than
|
||||
* fullbatt_vchkdrop_uV by calling this function after fullbatt_vchkrop_ms.
|
||||
*/
|
||||
static void fullbatt_vchk(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork = to_delayed_work(work);
|
||||
struct charger_manager *cm = container_of(dwork,
|
||||
struct charger_manager, fullbatt_vchk_work);
|
||||
struct charger_desc *desc = cm->desc;
|
||||
int batt_uV, err, diff;
|
||||
|
||||
/* remove the appointment for fullbatt_vchk */
|
||||
cm->fullbatt_vchk_jiffies_at = 0;
|
||||
|
||||
if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms)
|
||||
return;
|
||||
|
||||
err = get_batt_uV(cm, &batt_uV);
|
||||
if (err) {
|
||||
dev_err(cm->dev, "%s: get_batt_uV error(%d)\n", __func__, err);
|
||||
return;
|
||||
}
|
||||
|
||||
diff = desc->fullbatt_uV - batt_uV;
|
||||
if (diff < 0)
|
||||
return;
|
||||
|
||||
dev_info(cm->dev, "VBATT dropped %duV after full-batt\n", diff);
|
||||
|
||||
if (diff > desc->fullbatt_vchkdrop_uV) {
|
||||
try_charger_restart(cm);
|
||||
uevent_notify(cm, "Recharging");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check_charging_duration - Monitor charging/discharging duration
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
|
@ -569,19 +466,14 @@ static int check_charging_duration(struct charger_manager *cm)
|
|||
if (duration > desc->charging_max_duration_ms) {
|
||||
dev_info(cm->dev, "Charging duration exceed %ums\n",
|
||||
desc->charging_max_duration_ms);
|
||||
uevent_notify(cm, "Discharging");
|
||||
try_charger_enable(cm, false);
|
||||
ret = true;
|
||||
}
|
||||
} else if (is_ext_pwr_online(cm) && !cm->charger_enabled) {
|
||||
} else if (cm->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
|
||||
duration = curr - cm->charging_end_time;
|
||||
|
||||
if (duration > desc->discharging_max_duration_ms &&
|
||||
is_ext_pwr_online(cm)) {
|
||||
if (duration > desc->discharging_max_duration_ms) {
|
||||
dev_info(cm->dev, "Discharging duration exceed %ums\n",
|
||||
desc->discharging_max_duration_ms);
|
||||
uevent_notify(cm, "Recharging");
|
||||
try_charger_enable(cm, true);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
@ -657,13 +549,52 @@ static int cm_check_thermal_status(struct charger_manager *cm)
|
|||
}
|
||||
|
||||
if (temp > upper_limit)
|
||||
ret = CM_EVENT_BATT_OVERHEAT;
|
||||
ret = CM_BATT_OVERHEAT;
|
||||
else if (temp < lower_limit)
|
||||
ret = CM_EVENT_BATT_COLD;
|
||||
ret = CM_BATT_COLD;
|
||||
else
|
||||
ret = CM_BATT_OK;
|
||||
|
||||
cm->emergency_stop = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cm_get_target_status - Check current status and get next target status.
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
*/
|
||||
static int cm_get_target_status(struct charger_manager *cm)
|
||||
{
|
||||
if (!is_ext_pwr_online(cm))
|
||||
return POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
|
||||
if (cm_check_thermal_status(cm)) {
|
||||
/* Check if discharging duration exeeds limit. */
|
||||
if (check_charging_duration(cm))
|
||||
goto charging_ok;
|
||||
return POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
}
|
||||
|
||||
switch (cm->battery_status) {
|
||||
case POWER_SUPPLY_STATUS_CHARGING:
|
||||
/* Check if charging duration exeeds limit. */
|
||||
if (check_charging_duration(cm))
|
||||
return POWER_SUPPLY_STATUS_FULL;
|
||||
fallthrough;
|
||||
case POWER_SUPPLY_STATUS_FULL:
|
||||
if (is_full_charged(cm))
|
||||
return POWER_SUPPLY_STATUS_FULL;
|
||||
fallthrough;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
charging_ok:
|
||||
/* Charging is allowed. */
|
||||
return POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cm_monitor - Monitor the temperature and return true for exceptions.
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
|
@ -673,60 +604,18 @@ static int cm_check_thermal_status(struct charger_manager *cm)
|
|||
*/
|
||||
static bool _cm_monitor(struct charger_manager *cm)
|
||||
{
|
||||
int temp_alrt;
|
||||
int target;
|
||||
|
||||
temp_alrt = cm_check_thermal_status(cm);
|
||||
target = cm_get_target_status(cm);
|
||||
|
||||
/* It has been stopped already */
|
||||
if (temp_alrt && cm->emergency_stop)
|
||||
return false;
|
||||
try_charger_enable(cm, (target == POWER_SUPPLY_STATUS_CHARGING));
|
||||
|
||||
/*
|
||||
* Check temperature whether overheat or cold.
|
||||
* If temperature is out of range normal state, stop charging.
|
||||
*/
|
||||
if (temp_alrt) {
|
||||
cm->emergency_stop = temp_alrt;
|
||||
if (!try_charger_enable(cm, false))
|
||||
uevent_notify(cm, default_event_names[temp_alrt]);
|
||||
|
||||
/*
|
||||
* Check whole charging duration and discharging duration
|
||||
* after full-batt.
|
||||
*/
|
||||
} else if (!cm->emergency_stop && check_charging_duration(cm)) {
|
||||
dev_dbg(cm->dev,
|
||||
"Charging/Discharging duration is out of range\n");
|
||||
/*
|
||||
* Check dropped voltage of battery. If battery voltage is more
|
||||
* dropped than fullbatt_vchkdrop_uV after fully charged state,
|
||||
* charger-manager have to recharge battery.
|
||||
*/
|
||||
} else if (!cm->emergency_stop && is_ext_pwr_online(cm) &&
|
||||
!cm->charger_enabled) {
|
||||
fullbatt_vchk(&cm->fullbatt_vchk_work.work);
|
||||
|
||||
/*
|
||||
* Check whether fully charged state to protect overcharge
|
||||
* if charger-manager is charging for battery.
|
||||
*/
|
||||
} else if (!cm->emergency_stop && is_full_charged(cm) &&
|
||||
cm->charger_enabled) {
|
||||
dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n");
|
||||
uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]);
|
||||
|
||||
try_charger_enable(cm, false);
|
||||
|
||||
fullbatt_vchk(&cm->fullbatt_vchk_work.work);
|
||||
} else {
|
||||
cm->emergency_stop = 0;
|
||||
if (is_ext_pwr_online(cm)) {
|
||||
if (!try_charger_enable(cm, true))
|
||||
uevent_notify(cm, "CHARGING");
|
||||
}
|
||||
if (cm->battery_status != target) {
|
||||
cm->battery_status = target;
|
||||
power_supply_changed(cm->charger_psy);
|
||||
}
|
||||
|
||||
return true;
|
||||
return (cm->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -819,66 +708,6 @@ static void cm_monitor_poller(struct work_struct *work)
|
|||
schedule_work(&setup_polling);
|
||||
}
|
||||
|
||||
/**
|
||||
* fullbatt_handler - Event handler for CM_EVENT_BATT_FULL
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
*/
|
||||
static void fullbatt_handler(struct charger_manager *cm)
|
||||
{
|
||||
struct charger_desc *desc = cm->desc;
|
||||
|
||||
if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms)
|
||||
goto out;
|
||||
|
||||
if (cm_suspended)
|
||||
device_set_wakeup_capable(cm->dev, true);
|
||||
|
||||
mod_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
|
||||
msecs_to_jiffies(desc->fullbatt_vchkdrop_ms));
|
||||
cm->fullbatt_vchk_jiffies_at = jiffies + msecs_to_jiffies(
|
||||
desc->fullbatt_vchkdrop_ms);
|
||||
|
||||
if (cm->fullbatt_vchk_jiffies_at == 0)
|
||||
cm->fullbatt_vchk_jiffies_at = 1;
|
||||
|
||||
out:
|
||||
dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n");
|
||||
uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* battout_handler - Event handler for CM_EVENT_BATT_OUT
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
*/
|
||||
static void battout_handler(struct charger_manager *cm)
|
||||
{
|
||||
if (cm_suspended)
|
||||
device_set_wakeup_capable(cm->dev, true);
|
||||
|
||||
if (!is_batt_present(cm)) {
|
||||
dev_emerg(cm->dev, "Battery Pulled Out!\n");
|
||||
uevent_notify(cm, default_event_names[CM_EVENT_BATT_OUT]);
|
||||
} else {
|
||||
uevent_notify(cm, "Battery Reinserted?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* misc_event_handler - Handler for other events
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
* @type: the Charger Manager representing the battery.
|
||||
*/
|
||||
static void misc_event_handler(struct charger_manager *cm,
|
||||
enum cm_event_types type)
|
||||
{
|
||||
if (cm_suspended)
|
||||
device_set_wakeup_capable(cm->dev, true);
|
||||
|
||||
if (is_polling_required(cm) && cm->desc->polling_interval_ms)
|
||||
schedule_work(&setup_polling);
|
||||
uevent_notify(cm, default_event_names[type]);
|
||||
}
|
||||
|
||||
static int charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
|
@ -891,12 +720,7 @@ static int charger_get_property(struct power_supply *psy,
|
|||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (is_charging(cm))
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else if (is_ext_pwr_online(cm))
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
val->intval = cm->battery_status;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
if (cm->emergency_stop > 0)
|
||||
|
@ -925,7 +749,6 @@ static int charger_get_property(struct power_supply *psy,
|
|||
POWER_SUPPLY_PROP_CURRENT_NOW, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
|
||||
return cm_get_battery_temperature(cm, &val->intval);
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
if (!is_batt_present(cm)) {
|
||||
|
@ -981,35 +804,13 @@ static int charger_get_property(struct power_supply *psy,
|
|||
val->intval = 0;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
if (is_full_charged(cm))
|
||||
val->intval = 1;
|
||||
else
|
||||
val->intval = 0;
|
||||
ret = 0;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
||||
if (is_charging(cm)) {
|
||||
fuel_gauge = power_supply_get_by_name(
|
||||
cm->desc->psy_fuel_gauge);
|
||||
if (!fuel_gauge) {
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = power_supply_get_property(fuel_gauge,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
val);
|
||||
if (ret) {
|
||||
val->intval = 1;
|
||||
ret = 0;
|
||||
} else {
|
||||
/* If CHARGE_NOW is supplied, use it */
|
||||
val->intval = (val->intval > 0) ?
|
||||
val->intval : 1;
|
||||
}
|
||||
} else {
|
||||
val->intval = 0;
|
||||
fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
|
||||
if (!fuel_gauge) {
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
ret = power_supply_get_property(fuel_gauge, psp, val);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -1028,13 +829,12 @@ static enum power_supply_property default_charger_props[] = {
|
|||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
/*
|
||||
* Optional properties are:
|
||||
* POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
* POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
* POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
* POWER_SUPPLY_PROP_TEMP, and
|
||||
* POWER_SUPPLY_PROP_TEMP_AMBIENT,
|
||||
* POWER_SUPPLY_PROP_TEMP,
|
||||
*/
|
||||
};
|
||||
|
||||
|
@ -1069,21 +869,6 @@ static bool cm_setup_timer(void)
|
|||
|
||||
mutex_lock(&cm_list_mtx);
|
||||
list_for_each_entry(cm, &cm_list, entry) {
|
||||
unsigned int fbchk_ms = 0;
|
||||
|
||||
/* fullbatt_vchk is required. setup timer for that */
|
||||
if (cm->fullbatt_vchk_jiffies_at) {
|
||||
fbchk_ms = jiffies_to_msecs(cm->fullbatt_vchk_jiffies_at
|
||||
- jiffies);
|
||||
if (time_is_before_eq_jiffies(
|
||||
cm->fullbatt_vchk_jiffies_at) ||
|
||||
msecs_to_jiffies(fbchk_ms) < CM_JIFFIES_SMALL) {
|
||||
fullbatt_vchk(&cm->fullbatt_vchk_work.work);
|
||||
fbchk_ms = 0;
|
||||
}
|
||||
}
|
||||
CM_MIN_VALID(wakeup_ms, fbchk_ms);
|
||||
|
||||
/* Skip if polling is not required for this CM */
|
||||
if (!is_polling_required(cm) && !cm->emergency_stop)
|
||||
continue;
|
||||
|
@ -1145,7 +930,8 @@ static void charger_extcon_work(struct work_struct *work)
|
|||
cable->min_uA, cable->max_uA);
|
||||
}
|
||||
|
||||
try_charger_enable(cable->cm, cable->attached);
|
||||
cancel_delayed_work(&cm_monitor_work);
|
||||
queue_delayed_work(cm_wq, &cm_monitor_work, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1168,15 +954,6 @@ static int charger_extcon_notifier(struct notifier_block *self,
|
|||
*/
|
||||
cable->attached = event;
|
||||
|
||||
/*
|
||||
* Setup monitoring to check battery state
|
||||
* when charger cable is attached.
|
||||
*/
|
||||
if (cable->attached && is_polling_required(cable->cm)) {
|
||||
cancel_work_sync(&setup_polling);
|
||||
schedule_work(&setup_polling);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup work for controlling charger(regulator)
|
||||
* according to charger cable.
|
||||
|
@ -1196,7 +973,8 @@ static int charger_extcon_notifier(struct notifier_block *self,
|
|||
static int charger_extcon_init(struct charger_manager *cm,
|
||||
struct charger_cable *cable)
|
||||
{
|
||||
int ret;
|
||||
int ret, i;
|
||||
u64 extcon_type = EXTCON_NONE;
|
||||
|
||||
/*
|
||||
* Charger manager use Extcon framework to identify
|
||||
|
@ -1205,14 +983,39 @@ static int charger_extcon_init(struct charger_manager *cm,
|
|||
*/
|
||||
INIT_WORK(&cable->wq, charger_extcon_work);
|
||||
cable->nb.notifier_call = charger_extcon_notifier;
|
||||
ret = extcon_register_interest(&cable->extcon_dev,
|
||||
cable->extcon_name, cable->name, &cable->nb);
|
||||
if (ret < 0) {
|
||||
pr_info("Cannot register extcon_dev for %s(cable: %s)\n",
|
||||
|
||||
cable->extcon_dev = extcon_get_extcon_dev(cable->extcon_name);
|
||||
if (IS_ERR_OR_NULL(cable->extcon_dev)) {
|
||||
pr_err("Cannot find extcon_dev for %s (cable: %s)\n",
|
||||
cable->extcon_name, cable->name);
|
||||
if (cable->extcon_dev == NULL)
|
||||
return -EPROBE_DEFER;
|
||||
else
|
||||
return PTR_ERR(cable->extcon_dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
for (i = 0; i < ARRAY_SIZE(extcon_mapping); i++) {
|
||||
if (!strcmp(cable->name, extcon_mapping[i].name)) {
|
||||
extcon_type = extcon_mapping[i].extcon_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (extcon_type == EXTCON_NONE) {
|
||||
pr_err("Cannot find cable for type %s", cable->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cable->extcon_type = extcon_type;
|
||||
|
||||
ret = devm_extcon_register_notifier(cm->dev, cable->extcon_dev,
|
||||
cable->extcon_type, &cable->nb);
|
||||
if (ret < 0) {
|
||||
pr_err("Cannot register extcon_dev for %s (cable: %s)\n",
|
||||
cable->extcon_name, cable->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1229,6 +1032,7 @@ static int charger_manager_register_extcon(struct charger_manager *cm)
|
|||
{
|
||||
struct charger_desc *desc = cm->desc;
|
||||
struct charger_regulator *charger;
|
||||
unsigned long event;
|
||||
int ret;
|
||||
int i;
|
||||
int j;
|
||||
|
@ -1256,6 +1060,11 @@ static int charger_manager_register_extcon(struct charger_manager *cm)
|
|||
}
|
||||
cable->charger = charger;
|
||||
cable->cm = cm;
|
||||
|
||||
event = extcon_get_state(cable->extcon_dev,
|
||||
cable->extcon_type);
|
||||
charger_extcon_notifier(&cable->nb,
|
||||
event, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1447,7 +1256,7 @@ static int cm_init_thermal_data(struct charger_manager *cm,
|
|||
return PTR_ERR(cm->tzd_batt);
|
||||
|
||||
/* Use external thermometer */
|
||||
properties[*num_properties] = POWER_SUPPLY_PROP_TEMP_AMBIENT;
|
||||
properties[*num_properties] = POWER_SUPPLY_PROP_TEMP;
|
||||
(*num_properties)++;
|
||||
cm->desc->measure_battery_temp = true;
|
||||
ret = 0;
|
||||
|
@ -1491,8 +1300,6 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
|
|||
of_property_read_u32(np, "cm-poll-interval",
|
||||
&desc->polling_interval_ms);
|
||||
|
||||
of_property_read_u32(np, "cm-fullbatt-vchkdrop-ms",
|
||||
&desc->fullbatt_vchkdrop_ms);
|
||||
of_property_read_u32(np, "cm-fullbatt-vchkdrop-volt",
|
||||
&desc->fullbatt_vchkdrop_uV);
|
||||
of_property_read_u32(np, "cm-fullbatt-voltage", &desc->fullbatt_uV);
|
||||
|
@ -1504,8 +1311,8 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
|
|||
desc->battery_present = battery_stat;
|
||||
|
||||
/* chargers */
|
||||
of_property_read_u32(np, "cm-num-chargers", &num_chgs);
|
||||
if (num_chgs) {
|
||||
num_chgs = of_property_count_strings(np, "cm-chargers");
|
||||
if (num_chgs > 0) {
|
||||
int i;
|
||||
|
||||
/* Allocate empty bin at the tail of array */
|
||||
|
@ -1618,7 +1425,6 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
struct charger_desc *desc = cm_get_drv_data(pdev);
|
||||
struct charger_manager *cm;
|
||||
int ret, i = 0;
|
||||
int j = 0;
|
||||
union power_supply_propval val;
|
||||
struct power_supply *fuel_gauge;
|
||||
enum power_supply_property *properties;
|
||||
|
@ -1654,9 +1460,8 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
if (desc->fullbatt_uV == 0) {
|
||||
dev_info(&pdev->dev, "Ignoring full-battery voltage threshold as it is not supplied\n");
|
||||
}
|
||||
if (!desc->fullbatt_vchkdrop_ms || !desc->fullbatt_vchkdrop_uV) {
|
||||
if (!desc->fullbatt_vchkdrop_uV) {
|
||||
dev_info(&pdev->dev, "Disabling full-battery voltage drop checking mechanism as it is not supplied\n");
|
||||
desc->fullbatt_vchkdrop_ms = 0;
|
||||
desc->fullbatt_vchkdrop_uV = 0;
|
||||
}
|
||||
if (desc->fullbatt_soc == 0) {
|
||||
|
@ -1738,6 +1543,12 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
desc->psy_fuel_gauge);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!power_supply_get_property(fuel_gauge,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL, &val)) {
|
||||
properties[num_properties] =
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL;
|
||||
num_properties++;
|
||||
}
|
||||
if (!power_supply_get_property(fuel_gauge,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW, &val)) {
|
||||
properties[num_properties] =
|
||||
|
@ -1762,8 +1573,6 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
cm->charger_psy_desc.properties = properties;
|
||||
cm->charger_psy_desc.num_properties = num_properties;
|
||||
|
||||
INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk);
|
||||
|
||||
/* Register sysfs entry for charger(regulator) */
|
||||
ret = charger_manager_prepare_sysfs(cm);
|
||||
if (ret < 0) {
|
||||
|
@ -1813,19 +1622,8 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_reg_extcon:
|
||||
for (i = 0; i < desc->num_charger_regulators; i++) {
|
||||
struct charger_regulator *charger;
|
||||
|
||||
charger = &desc->charger_regulators[i];
|
||||
for (j = 0; j < charger->num_cables; j++) {
|
||||
struct charger_cable *cable = &charger->cables[j];
|
||||
/* Remove notifier block if only edev exists */
|
||||
if (cable->extcon_dev.edev)
|
||||
extcon_unregister_interest(&cable->extcon_dev);
|
||||
}
|
||||
|
||||
for (i = 0; i < desc->num_charger_regulators; i++)
|
||||
regulator_put(desc->charger_regulators[i].consumer);
|
||||
}
|
||||
|
||||
power_supply_unregister(cm->charger_psy);
|
||||
|
||||
|
@ -1837,7 +1635,6 @@ static int charger_manager_remove(struct platform_device *pdev)
|
|||
struct charger_manager *cm = platform_get_drvdata(pdev);
|
||||
struct charger_desc *desc = cm->desc;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
/* Remove from the list */
|
||||
mutex_lock(&cm_list_mtx);
|
||||
|
@ -1847,15 +1644,6 @@ static int charger_manager_remove(struct platform_device *pdev)
|
|||
cancel_work_sync(&setup_polling);
|
||||
cancel_delayed_work_sync(&cm_monitor_work);
|
||||
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
|
||||
struct charger_regulator *charger
|
||||
= &desc->charger_regulators[i];
|
||||
for (j = 0 ; j < charger->num_cables ; j++) {
|
||||
struct charger_cable *cable = &charger->cables[j];
|
||||
extcon_unregister_interest(&cable->extcon_dev);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++)
|
||||
regulator_put(desc->charger_regulators[i].consumer);
|
||||
|
||||
|
@ -1903,8 +1691,6 @@ static bool cm_need_to_awake(void)
|
|||
|
||||
static int cm_suspend_prepare(struct device *dev)
|
||||
{
|
||||
struct charger_manager *cm = dev_get_drvdata(dev);
|
||||
|
||||
if (cm_need_to_awake())
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -1916,7 +1702,6 @@ static int cm_suspend_prepare(struct device *dev)
|
|||
if (cm_timer_set) {
|
||||
cancel_work_sync(&setup_polling);
|
||||
cancel_delayed_work_sync(&cm_monitor_work);
|
||||
cancel_delayed_work(&cm->fullbatt_vchk_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1941,31 +1726,6 @@ static void cm_suspend_complete(struct device *dev)
|
|||
|
||||
_cm_monitor(cm);
|
||||
|
||||
/* Re-enqueue delayed work (fullbatt_vchk_work) */
|
||||
if (cm->fullbatt_vchk_jiffies_at) {
|
||||
unsigned long delay = 0;
|
||||
unsigned long now = jiffies + CM_JIFFIES_SMALL;
|
||||
|
||||
if (time_after_eq(now, cm->fullbatt_vchk_jiffies_at)) {
|
||||
delay = (unsigned long)((long)now
|
||||
- (long)(cm->fullbatt_vchk_jiffies_at));
|
||||
delay = jiffies_to_msecs(delay);
|
||||
} else {
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Account for cm_suspend_duration_ms with assuming that
|
||||
* timer stops in suspend.
|
||||
*/
|
||||
if (delay > cm_suspend_duration_ms)
|
||||
delay -= cm_suspend_duration_ms;
|
||||
else
|
||||
delay = 0;
|
||||
|
||||
queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
|
||||
msecs_to_jiffies(delay));
|
||||
}
|
||||
device_set_wakeup_capable(cm->dev, false);
|
||||
}
|
||||
|
||||
|
@ -2007,56 +1767,6 @@ static void __exit charger_manager_cleanup(void)
|
|||
}
|
||||
module_exit(charger_manager_cleanup);
|
||||
|
||||
/**
|
||||
* cm_notify_event - charger driver notify Charger Manager of charger event
|
||||
* @psy: pointer to instance of charger's power_supply
|
||||
* @type: type of charger event
|
||||
* @msg: optional message passed to uevent_notify function
|
||||
*/
|
||||
void cm_notify_event(struct power_supply *psy, enum cm_event_types type,
|
||||
char *msg)
|
||||
{
|
||||
struct charger_manager *cm;
|
||||
bool found_power_supply = false;
|
||||
|
||||
if (psy == NULL)
|
||||
return;
|
||||
|
||||
mutex_lock(&cm_list_mtx);
|
||||
list_for_each_entry(cm, &cm_list, entry) {
|
||||
if (match_string(cm->desc->psy_charger_stat, -1,
|
||||
psy->desc->name) >= 0) {
|
||||
found_power_supply = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&cm_list_mtx);
|
||||
|
||||
if (!found_power_supply)
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case CM_EVENT_BATT_FULL:
|
||||
fullbatt_handler(cm);
|
||||
break;
|
||||
case CM_EVENT_BATT_OUT:
|
||||
battout_handler(cm);
|
||||
break;
|
||||
case CM_EVENT_BATT_IN:
|
||||
case CM_EVENT_EXT_PWR_IN_OUT ... CM_EVENT_CHG_START_STOP:
|
||||
misc_event_handler(cm, type);
|
||||
break;
|
||||
case CM_EVENT_UNKNOWN:
|
||||
case CM_EVENT_OTHERS:
|
||||
uevent_notify(cm, msg ? msg : default_event_names[type]);
|
||||
break;
|
||||
default:
|
||||
dev_err(cm->dev, "%s: type not specified\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cm_notify_event);
|
||||
|
||||
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||
MODULE_DESCRIPTION("Charger Manager");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -747,11 +747,8 @@ static int cpcap_battery_init_iio(struct cpcap_battery_ddata *ddata)
|
|||
return 0;
|
||||
|
||||
out_err:
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
|
||||
error);
|
||||
|
||||
return error;
|
||||
return dev_err_probe(ddata->dev, error,
|
||||
"could not initialize VBUS or ID IIO\n");
|
||||
}
|
||||
|
||||
/* Calibrate coulomb counter */
|
||||
|
|
|
@ -160,7 +160,7 @@ static int ds2780_get_voltage(struct ds2780_device_info *dev_info,
|
|||
|
||||
/*
|
||||
* The voltage value is located in 10 bits across the voltage MSB
|
||||
* and LSB registers in two's compliment form
|
||||
* and LSB registers in two's complement form
|
||||
* Sign bit of the voltage value is in bit 7 of the voltage MSB register
|
||||
* Bits 9 - 3 of the voltage value are in bits 6 - 0 of the
|
||||
* voltage MSB register
|
||||
|
@ -188,7 +188,7 @@ static int ds2780_get_temperature(struct ds2780_device_info *dev_info,
|
|||
|
||||
/*
|
||||
* The temperature value is located in 10 bits across the temperature
|
||||
* MSB and LSB registers in two's compliment form
|
||||
* MSB and LSB registers in two's complement form
|
||||
* Sign bit of the temperature value is in bit 7 of the temperature
|
||||
* MSB register
|
||||
* Bits 9 - 3 of the temperature value are in bits 6 - 0 of the
|
||||
|
@ -241,7 +241,7 @@ static int ds2780_get_current(struct ds2780_device_info *dev_info,
|
|||
|
||||
/*
|
||||
* The current value is located in 16 bits across the current MSB
|
||||
* and LSB registers in two's compliment form
|
||||
* and LSB registers in two's complement form
|
||||
* Sign bit of the current value is in bit 7 of the current MSB register
|
||||
* Bits 14 - 8 of the current value are in bits 6 - 0 of the current
|
||||
* MSB register
|
||||
|
|
|
@ -168,7 +168,7 @@ static int ds2781_get_voltage(struct ds2781_device_info *dev_info,
|
|||
return ret;
|
||||
/*
|
||||
* The voltage value is located in 10 bits across the voltage MSB
|
||||
* and LSB registers in two's compliment form
|
||||
* and LSB registers in two's complement form
|
||||
* Sign bit of the voltage value is in bit 7 of the voltage MSB register
|
||||
* Bits 9 - 3 of the voltage value are in bits 6 - 0 of the
|
||||
* voltage MSB register
|
||||
|
@ -197,7 +197,7 @@ static int ds2781_get_temperature(struct ds2781_device_info *dev_info,
|
|||
return ret;
|
||||
/*
|
||||
* The temperature value is located in 10 bits across the temperature
|
||||
* MSB and LSB registers in two's compliment form
|
||||
* MSB and LSB registers in two's complement form
|
||||
* Sign bit of the temperature value is in bit 7 of the temperature
|
||||
* MSB register
|
||||
* Bits 9 - 3 of the temperature value are in bits 6 - 0 of the
|
||||
|
@ -242,7 +242,7 @@ static int ds2781_get_current(struct ds2781_device_info *dev_info,
|
|||
|
||||
/*
|
||||
* The current value is located in 16 bits across the current MSB
|
||||
* and LSB registers in two's compliment form
|
||||
* and LSB registers in two's complement form
|
||||
* Sign bit of the current value is in bit 7 of the current MSB register
|
||||
* Bits 14 - 8 of the current value are in bits 6 - 0 of the current
|
||||
* MSB register
|
||||
|
|
|
@ -266,11 +266,13 @@ static const struct of_device_id goldfish_battery_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, goldfish_battery_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id goldfish_battery_acpi_match[] = {
|
||||
{ "GFSH0001", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver goldfish_battery_device = {
|
||||
.probe = goldfish_battery_probe,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h> /* For legacy platform data */
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -18,7 +17,13 @@
|
|||
|
||||
#include <linux/power/gpio-charger.h>
|
||||
|
||||
struct gpio_mapping {
|
||||
u32 limit_ua;
|
||||
u32 gpiodata;
|
||||
} __packed;
|
||||
|
||||
struct gpio_charger {
|
||||
struct device *dev;
|
||||
unsigned int irq;
|
||||
unsigned int charge_status_irq;
|
||||
bool wakeup_enabled;
|
||||
|
@ -27,6 +32,11 @@ struct gpio_charger {
|
|||
struct power_supply_desc charger_desc;
|
||||
struct gpio_desc *gpiod;
|
||||
struct gpio_desc *charge_status;
|
||||
|
||||
struct gpio_descs *current_limit_gpios;
|
||||
struct gpio_mapping *current_limit_map;
|
||||
u32 current_limit_map_size;
|
||||
u32 charge_current_limit;
|
||||
};
|
||||
|
||||
static irqreturn_t gpio_charger_irq(int irq, void *devid)
|
||||
|
@ -43,6 +53,35 @@ static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
|
|||
return power_supply_get_drvdata(psy);
|
||||
}
|
||||
|
||||
static int set_charge_current_limit(struct gpio_charger *gpio_charger, int val)
|
||||
{
|
||||
struct gpio_mapping mapping;
|
||||
int ndescs = gpio_charger->current_limit_gpios->ndescs;
|
||||
struct gpio_desc **gpios = gpio_charger->current_limit_gpios->desc;
|
||||
int i;
|
||||
|
||||
if (!gpio_charger->current_limit_map_size)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < gpio_charger->current_limit_map_size; i++) {
|
||||
if (gpio_charger->current_limit_map[i].limit_ua <= val)
|
||||
break;
|
||||
}
|
||||
mapping = gpio_charger->current_limit_map[i];
|
||||
|
||||
for (i = 0; i < ndescs; i++) {
|
||||
bool val = (mapping.gpiodata >> i) & 1;
|
||||
gpiod_set_value_cansleep(gpios[ndescs-i-1], val);
|
||||
}
|
||||
|
||||
gpio_charger->charge_current_limit = mapping.limit_ua;
|
||||
|
||||
dev_dbg(gpio_charger->dev, "set charge current limit to %d (requested: %d)\n",
|
||||
gpio_charger->charge_current_limit, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp, union power_supply_propval *val)
|
||||
{
|
||||
|
@ -58,6 +97,9 @@ static int gpio_charger_get_property(struct power_supply *psy,
|
|||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
||||
val->intval = gpio_charger->charge_current_limit;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -65,6 +107,34 @@ static int gpio_charger_get_property(struct power_supply *psy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_charger_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp, const union power_supply_propval *val)
|
||||
{
|
||||
struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
||||
return set_charge_current_limit(gpio_charger, val->intval);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_charger_property_is_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum power_supply_type gpio_charger_get_type(struct device *dev)
|
||||
{
|
||||
const char *chargetype;
|
||||
|
@ -112,6 +182,61 @@ static int gpio_charger_get_irq(struct device *dev, void *dev_id,
|
|||
return irq;
|
||||
}
|
||||
|
||||
static int init_charge_current_limit(struct device *dev,
|
||||
struct gpio_charger *gpio_charger)
|
||||
{
|
||||
int i, len;
|
||||
u32 cur_limit = U32_MAX;
|
||||
|
||||
gpio_charger->current_limit_gpios = devm_gpiod_get_array_optional(dev,
|
||||
"charge-current-limit", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio_charger->current_limit_gpios)) {
|
||||
dev_err(dev, "error getting current-limit GPIOs\n");
|
||||
return PTR_ERR(gpio_charger->current_limit_gpios);
|
||||
}
|
||||
|
||||
if (!gpio_charger->current_limit_gpios)
|
||||
return 0;
|
||||
|
||||
len = device_property_read_u32_array(dev, "charge-current-limit-mapping",
|
||||
NULL, 0);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
if (len == 0 || len % 2) {
|
||||
dev_err(dev, "invalid charge-current-limit-mapping length\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_charger->current_limit_map = devm_kmalloc_array(dev,
|
||||
len / 2, sizeof(*gpio_charger->current_limit_map), GFP_KERNEL);
|
||||
if (!gpio_charger->current_limit_map)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio_charger->current_limit_map_size = len / 2;
|
||||
|
||||
len = device_property_read_u32_array(dev, "charge-current-limit-mapping",
|
||||
(u32*) gpio_charger->current_limit_map, len);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
for (i=0; i < gpio_charger->current_limit_map_size; i++) {
|
||||
if (gpio_charger->current_limit_map[i].limit_ua > cur_limit) {
|
||||
dev_err(dev, "charge-current-limit-mapping not sorted by current in descending order\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cur_limit = gpio_charger->current_limit_map[i].limit_ua;
|
||||
}
|
||||
|
||||
/* default to smallest current limitation for safety reasons */
|
||||
len = gpio_charger->current_limit_map_size - 1;
|
||||
set_charge_current_limit(gpio_charger,
|
||||
gpio_charger->current_limit_map[len].limit_ua);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The entries will be overwritten by driver's probe routine depending
|
||||
* on the available features. This list ensures, that the array is big
|
||||
|
@ -120,6 +245,7 @@ static int gpio_charger_get_irq(struct device *dev, void *dev_id,
|
|||
static enum power_supply_property gpio_charger_properties[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||
};
|
||||
|
||||
static int gpio_charger_probe(struct platform_device *pdev)
|
||||
|
@ -131,7 +257,6 @@ static int gpio_charger_probe(struct platform_device *pdev)
|
|||
struct power_supply_desc *charger_desc;
|
||||
struct gpio_desc *charge_status;
|
||||
int charge_status_irq;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
int num_props = 0;
|
||||
|
||||
|
@ -143,40 +268,17 @@ static int gpio_charger_probe(struct platform_device *pdev)
|
|||
gpio_charger = devm_kzalloc(dev, sizeof(*gpio_charger), GFP_KERNEL);
|
||||
if (!gpio_charger)
|
||||
return -ENOMEM;
|
||||
gpio_charger->dev = dev;
|
||||
|
||||
/*
|
||||
* This will fetch a GPIO descriptor from device tree, ACPI or
|
||||
* boardfile descriptor tables. It's good to try this first.
|
||||
*/
|
||||
gpio_charger->gpiod = devm_gpiod_get_optional(dev, NULL, GPIOD_IN);
|
||||
|
||||
/*
|
||||
* Fallback to legacy platform data method, if no GPIO is specified
|
||||
* using boardfile descriptor tables.
|
||||
*/
|
||||
if (!gpio_charger->gpiod && pdata) {
|
||||
/* Non-DT: use legacy GPIO numbers */
|
||||
if (!gpio_is_valid(pdata->gpio)) {
|
||||
dev_err(dev, "Invalid gpio pin in pdata\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
flags = GPIOF_IN;
|
||||
if (pdata->gpio_active_low)
|
||||
flags |= GPIOF_ACTIVE_LOW;
|
||||
ret = devm_gpio_request_one(dev, pdata->gpio, flags,
|
||||
dev_name(dev));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request gpio pin: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/* Then convert this to gpiod for now */
|
||||
gpio_charger->gpiod = gpio_to_desc(pdata->gpio);
|
||||
} else if (IS_ERR(gpio_charger->gpiod)) {
|
||||
if (IS_ERR(gpio_charger->gpiod)) {
|
||||
/* Just try again if this happens */
|
||||
if (PTR_ERR(gpio_charger->gpiod) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_err(dev, "error getting GPIO descriptor\n");
|
||||
return PTR_ERR(gpio_charger->gpiod);
|
||||
return dev_err_probe(dev, PTR_ERR(gpio_charger->gpiod),
|
||||
"error getting GPIO descriptor\n");
|
||||
}
|
||||
|
||||
if (gpio_charger->gpiod) {
|
||||
|
@ -193,10 +295,22 @@ static int gpio_charger_probe(struct platform_device *pdev)
|
|||
num_props++;
|
||||
}
|
||||
|
||||
ret = init_charge_current_limit(dev, gpio_charger);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (gpio_charger->current_limit_map) {
|
||||
gpio_charger_properties[num_props] =
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
|
||||
num_props++;
|
||||
}
|
||||
|
||||
charger_desc = &gpio_charger->charger_desc;
|
||||
charger_desc->properties = gpio_charger_properties;
|
||||
charger_desc->num_properties = num_props;
|
||||
charger_desc->get_property = gpio_charger_get_property;
|
||||
charger_desc->set_property = gpio_charger_set_property;
|
||||
charger_desc->property_is_writeable =
|
||||
gpio_charger_property_is_writeable;
|
||||
|
||||
psy_cfg.of_node = dev->of_node;
|
||||
psy_cfg.drv_data = gpio_charger;
|
||||
|
|
|
@ -147,11 +147,9 @@ static int ingenic_battery_probe(struct platform_device *pdev)
|
|||
psy_cfg.of_node = dev->of_node;
|
||||
|
||||
bat->battery = devm_power_supply_register(dev, desc, &psy_cfg);
|
||||
if (IS_ERR(bat->battery)) {
|
||||
if (PTR_ERR(bat->battery) != -EPROBE_DEFER)
|
||||
dev_err(dev, "Unable to register battery\n");
|
||||
return PTR_ERR(bat->battery);
|
||||
}
|
||||
if (IS_ERR(bat->battery))
|
||||
return dev_err_probe(dev, PTR_ERR(bat->battery),
|
||||
"Unable to register battery\n");
|
||||
|
||||
ret = power_supply_get_battery_info(bat->battery, &bat->info);
|
||||
if (ret) {
|
||||
|
|
|
@ -166,27 +166,21 @@ static int lego_ev3_battery_probe(struct platform_device *pdev)
|
|||
|
||||
batt->iio_v = devm_iio_channel_get(dev, "voltage");
|
||||
err = PTR_ERR_OR_ZERO(batt->iio_v);
|
||||
if (err) {
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get voltage iio channel\n");
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
return dev_err_probe(dev, err,
|
||||
"Failed to get voltage iio channel\n");
|
||||
|
||||
batt->iio_i = devm_iio_channel_get(dev, "current");
|
||||
err = PTR_ERR_OR_ZERO(batt->iio_i);
|
||||
if (err) {
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get current iio channel\n");
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
return dev_err_probe(dev, err,
|
||||
"Failed to get current iio channel\n");
|
||||
|
||||
batt->rechargeable_gpio = devm_gpiod_get(dev, "rechargeable", GPIOD_IN);
|
||||
err = PTR_ERR_OR_ZERO(batt->rechargeable_gpio);
|
||||
if (err) {
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get rechargeable gpio\n");
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
return dev_err_probe(dev, err,
|
||||
"Failed to get rechargeable gpio\n");
|
||||
|
||||
/*
|
||||
* The rechargeable battery indication switch cannot be changed without
|
||||
|
|
|
@ -473,7 +473,8 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
|
|||
|
||||
np = of_node_get(client->dev.of_node);
|
||||
|
||||
info->id = (enum ltc294x_id)of_device_get_match_data(&client->dev);
|
||||
info->id = (enum ltc294x_id) (uintptr_t) of_device_get_match_data(
|
||||
&client->dev);
|
||||
info->supply_desc.name = np->name;
|
||||
|
||||
/* r_sense can be negative, when sense+ is connected to the battery
|
||||
|
|
|
@ -15,196 +15,289 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/max17040_battery.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define MAX17040_VCELL 0x02
|
||||
#define MAX17040_SOC 0x04
|
||||
#define MAX17040_MODE 0x06
|
||||
#define MAX17040_VER 0x08
|
||||
#define MAX17040_RCOMP 0x0C
|
||||
#define MAX17040_CONFIG 0x0C
|
||||
#define MAX17040_STATUS 0x1A
|
||||
#define MAX17040_CMD 0xFE
|
||||
|
||||
|
||||
#define MAX17040_DELAY 1000
|
||||
#define MAX17040_BATTERY_FULL 95
|
||||
#define MAX17040_RCOMP_DEFAULT 0x9700
|
||||
|
||||
#define MAX17040_ATHD_MASK 0xFFC0
|
||||
#define MAX17040_ATHD_MASK 0x3f
|
||||
#define MAX17040_ALSC_MASK 0x40
|
||||
#define MAX17040_ATHD_DEFAULT_POWER_UP 4
|
||||
#define MAX17040_STATUS_HD_MASK 0x1000
|
||||
#define MAX17040_STATUS_SC_MASK 0x2000
|
||||
#define MAX17040_CFG_RCOMP_MASK 0xff00
|
||||
|
||||
enum chip_id {
|
||||
ID_MAX17040,
|
||||
ID_MAX17041,
|
||||
ID_MAX17043,
|
||||
ID_MAX17044,
|
||||
ID_MAX17048,
|
||||
ID_MAX17049,
|
||||
ID_MAX17058,
|
||||
ID_MAX17059,
|
||||
};
|
||||
|
||||
/* values that differ by chip_id */
|
||||
struct chip_data {
|
||||
u16 reset_val;
|
||||
u16 vcell_shift;
|
||||
u16 vcell_mul;
|
||||
u16 vcell_div;
|
||||
u8 has_low_soc_alert;
|
||||
u8 rcomp_bytes;
|
||||
u8 has_soc_alert;
|
||||
};
|
||||
|
||||
static struct chip_data max17040_family[] = {
|
||||
[ID_MAX17040] = {
|
||||
.reset_val = 0x0054,
|
||||
.vcell_shift = 4,
|
||||
.vcell_mul = 1250,
|
||||
.vcell_div = 1,
|
||||
.has_low_soc_alert = 0,
|
||||
.rcomp_bytes = 2,
|
||||
.has_soc_alert = 0,
|
||||
},
|
||||
[ID_MAX17041] = {
|
||||
.reset_val = 0x0054,
|
||||
.vcell_shift = 4,
|
||||
.vcell_mul = 2500,
|
||||
.vcell_div = 1,
|
||||
.has_low_soc_alert = 0,
|
||||
.rcomp_bytes = 2,
|
||||
.has_soc_alert = 0,
|
||||
},
|
||||
[ID_MAX17043] = {
|
||||
.reset_val = 0x0054,
|
||||
.vcell_shift = 4,
|
||||
.vcell_mul = 1250,
|
||||
.vcell_div = 1,
|
||||
.has_low_soc_alert = 1,
|
||||
.rcomp_bytes = 1,
|
||||
.has_soc_alert = 0,
|
||||
},
|
||||
[ID_MAX17044] = {
|
||||
.reset_val = 0x0054,
|
||||
.vcell_shift = 4,
|
||||
.vcell_mul = 2500,
|
||||
.vcell_div = 1,
|
||||
.has_low_soc_alert = 1,
|
||||
.rcomp_bytes = 1,
|
||||
.has_soc_alert = 0,
|
||||
},
|
||||
[ID_MAX17048] = {
|
||||
.reset_val = 0x5400,
|
||||
.vcell_shift = 0,
|
||||
.vcell_mul = 625,
|
||||
.vcell_div = 8,
|
||||
.has_low_soc_alert = 1,
|
||||
.rcomp_bytes = 1,
|
||||
.has_soc_alert = 1,
|
||||
},
|
||||
[ID_MAX17049] = {
|
||||
.reset_val = 0x5400,
|
||||
.vcell_shift = 0,
|
||||
.vcell_mul = 625,
|
||||
.vcell_div = 4,
|
||||
.has_low_soc_alert = 1,
|
||||
.rcomp_bytes = 1,
|
||||
.has_soc_alert = 1,
|
||||
},
|
||||
[ID_MAX17058] = {
|
||||
.reset_val = 0x5400,
|
||||
.vcell_shift = 0,
|
||||
.vcell_mul = 625,
|
||||
.vcell_div = 8,
|
||||
.has_low_soc_alert = 1,
|
||||
.rcomp_bytes = 1,
|
||||
.has_soc_alert = 0,
|
||||
},
|
||||
[ID_MAX17059] = {
|
||||
.reset_val = 0x5400,
|
||||
.vcell_shift = 0,
|
||||
.vcell_mul = 625,
|
||||
.vcell_div = 4,
|
||||
.has_low_soc_alert = 1,
|
||||
.rcomp_bytes = 1,
|
||||
.has_soc_alert = 0,
|
||||
},
|
||||
};
|
||||
|
||||
struct max17040_chip {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct delayed_work work;
|
||||
struct power_supply *battery;
|
||||
struct max17040_platform_data *pdata;
|
||||
struct chip_data data;
|
||||
|
||||
/* State Of Connect */
|
||||
int online;
|
||||
/* battery voltage */
|
||||
int vcell;
|
||||
/* battery capacity */
|
||||
int soc;
|
||||
/* State Of Charge */
|
||||
int status;
|
||||
/* Low alert threshold from 32% to 1% of the State of Charge */
|
||||
u32 low_soc_alert;
|
||||
/* some devices return twice the capacity */
|
||||
bool quirk_double_soc;
|
||||
/* higher 8 bits for 17043+, 16 bits for 17040,41 */
|
||||
u16 rcomp;
|
||||
};
|
||||
|
||||
static int max17040_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
static int max17040_reset(struct max17040_chip *chip)
|
||||
{
|
||||
struct max17040_chip *chip = power_supply_get_drvdata(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
val->intval = chip->status;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = chip->online;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = chip->vcell;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
val->intval = chip->soc;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
|
||||
val->intval = chip->low_soc_alert;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
return regmap_write(chip->regmap, MAX17040_CMD, chip->data.reset_val);
|
||||
}
|
||||
|
||||
static int max17040_write_reg(struct i2c_client *client, int reg, u16 value)
|
||||
static int max17040_set_low_soc_alert(struct max17040_chip *chip, u32 level)
|
||||
{
|
||||
level = 32 - level * (chip->quirk_double_soc ? 2 : 1);
|
||||
return regmap_update_bits(chip->regmap, MAX17040_CONFIG,
|
||||
MAX17040_ATHD_MASK, level);
|
||||
}
|
||||
|
||||
static int max17040_set_soc_alert(struct max17040_chip *chip, bool enable)
|
||||
{
|
||||
return regmap_update_bits(chip->regmap, MAX17040_CONFIG,
|
||||
MAX17040_ALSC_MASK, enable ? MAX17040_ALSC_MASK : 0);
|
||||
}
|
||||
|
||||
static int max17040_set_rcomp(struct max17040_chip *chip, u16 rcomp)
|
||||
{
|
||||
u16 mask = chip->data.rcomp_bytes == 2 ?
|
||||
0xffff : MAX17040_CFG_RCOMP_MASK;
|
||||
|
||||
return regmap_update_bits(chip->regmap, MAX17040_CONFIG, mask, rcomp);
|
||||
}
|
||||
|
||||
static int max17040_raw_vcell_to_uvolts(struct max17040_chip *chip, u16 vcell)
|
||||
{
|
||||
struct chip_data *d = &chip->data;
|
||||
|
||||
return (vcell >> d->vcell_shift) * d->vcell_mul / d->vcell_div;
|
||||
}
|
||||
|
||||
|
||||
static int max17040_get_vcell(struct max17040_chip *chip)
|
||||
{
|
||||
u32 vcell;
|
||||
|
||||
regmap_read(chip->regmap, MAX17040_VCELL, &vcell);
|
||||
|
||||
return max17040_raw_vcell_to_uvolts(chip, vcell);
|
||||
}
|
||||
|
||||
static int max17040_get_soc(struct max17040_chip *chip)
|
||||
{
|
||||
u32 soc;
|
||||
|
||||
regmap_read(chip->regmap, MAX17040_SOC, &soc);
|
||||
|
||||
return soc >> (chip->quirk_double_soc ? 9 : 8);
|
||||
}
|
||||
|
||||
static int max17040_get_version(struct max17040_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
u32 version;
|
||||
|
||||
ret = i2c_smbus_write_word_swapped(client, reg, value);
|
||||
ret = regmap_read(chip->regmap, MAX17040_VER, &version);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
return ret ? ret : version;
|
||||
}
|
||||
|
||||
static int max17040_read_reg(struct i2c_client *client, int reg)
|
||||
static int max17040_get_online(struct max17040_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(client, reg);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
return chip->pdata && chip->pdata->battery_online ?
|
||||
chip->pdata->battery_online() : 1;
|
||||
}
|
||||
|
||||
static void max17040_reset(struct i2c_client *client)
|
||||
static int max17040_get_status(struct max17040_chip *chip)
|
||||
{
|
||||
max17040_write_reg(client, MAX17040_CMD, 0x0054);
|
||||
}
|
||||
|
||||
static int max17040_set_low_soc_alert(struct i2c_client *client, u32 level)
|
||||
{
|
||||
int ret;
|
||||
u16 data;
|
||||
|
||||
level = 32 - level;
|
||||
data = max17040_read_reg(client, MAX17040_RCOMP);
|
||||
/* clear the alrt bit and set LSb 5 bits */
|
||||
data &= MAX17040_ATHD_MASK;
|
||||
data |= level;
|
||||
ret = max17040_write_reg(client, MAX17040_RCOMP, data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max17040_get_vcell(struct i2c_client *client)
|
||||
{
|
||||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||||
u16 vcell;
|
||||
|
||||
vcell = max17040_read_reg(client, MAX17040_VCELL);
|
||||
|
||||
chip->vcell = (vcell >> 4) * 1250;
|
||||
}
|
||||
|
||||
static void max17040_get_soc(struct i2c_client *client)
|
||||
{
|
||||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||||
u16 soc;
|
||||
|
||||
soc = max17040_read_reg(client, MAX17040_SOC);
|
||||
|
||||
chip->soc = (soc >> 8);
|
||||
}
|
||||
|
||||
static void max17040_get_version(struct i2c_client *client)
|
||||
{
|
||||
u16 version;
|
||||
|
||||
version = max17040_read_reg(client, MAX17040_VER);
|
||||
|
||||
dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version);
|
||||
}
|
||||
|
||||
static void max17040_get_online(struct i2c_client *client)
|
||||
{
|
||||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (chip->pdata && chip->pdata->battery_online)
|
||||
chip->online = chip->pdata->battery_online();
|
||||
else
|
||||
chip->online = 1;
|
||||
}
|
||||
|
||||
static void max17040_get_status(struct i2c_client *client)
|
||||
{
|
||||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (!chip->pdata || !chip->pdata->charger_online
|
||||
|| !chip->pdata->charger_enable) {
|
||||
chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
|| !chip->pdata->charger_enable)
|
||||
return POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
|
||||
if (chip->pdata->charger_online()) {
|
||||
if (max17040_get_soc(chip) > MAX17040_BATTERY_FULL)
|
||||
return POWER_SUPPLY_STATUS_FULL;
|
||||
|
||||
if (chip->pdata->charger_online())
|
||||
if (chip->pdata->charger_enable())
|
||||
chip->status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
return POWER_SUPPLY_STATUS_CHARGING;
|
||||
else
|
||||
chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
} else {
|
||||
chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
if (chip->soc > MAX17040_BATTERY_FULL)
|
||||
chip->status = POWER_SUPPLY_STATUS_FULL;
|
||||
return POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
else
|
||||
return POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
static int max17040_get_of_data(struct max17040_chip *chip)
|
||||
{
|
||||
struct device *dev = &chip->client->dev;
|
||||
struct chip_data *data = &max17040_family[
|
||||
(uintptr_t) of_device_get_match_data(dev)];
|
||||
int rcomp_len;
|
||||
u8 rcomp[2];
|
||||
|
||||
chip->quirk_double_soc = device_property_read_bool(dev,
|
||||
"maxim,double-soc");
|
||||
|
||||
chip->low_soc_alert = MAX17040_ATHD_DEFAULT_POWER_UP;
|
||||
device_property_read_u32(dev,
|
||||
"maxim,alert-low-soc-level",
|
||||
&chip->low_soc_alert);
|
||||
|
||||
if (chip->low_soc_alert <= 0 || chip->low_soc_alert >= 33)
|
||||
if (chip->low_soc_alert <= 0 ||
|
||||
chip->low_soc_alert > (chip->quirk_double_soc ? 16 : 32)) {
|
||||
dev_err(dev, "maxim,alert-low-soc-level out of bounds\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rcomp_len = device_property_count_u8(dev, "maxim,rcomp");
|
||||
chip->rcomp = MAX17040_RCOMP_DEFAULT;
|
||||
if (rcomp_len == data->rcomp_bytes) {
|
||||
device_property_read_u8_array(dev, "maxim,rcomp",
|
||||
rcomp, rcomp_len);
|
||||
chip->rcomp = rcomp_len == 2 ?
|
||||
rcomp[0] << 8 | rcomp[1] :
|
||||
rcomp[0] << 8;
|
||||
} else if (rcomp_len > 0) {
|
||||
dev_err(dev, "maxim,rcomp has incorrect length\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max17040_check_changes(struct i2c_client *client)
|
||||
static void max17040_check_changes(struct max17040_chip *chip)
|
||||
{
|
||||
max17040_get_vcell(client);
|
||||
max17040_get_soc(client);
|
||||
max17040_get_online(client);
|
||||
max17040_get_status(client);
|
||||
chip->soc = max17040_get_soc(chip);
|
||||
chip->status = max17040_get_status(chip);
|
||||
}
|
||||
|
||||
static void max17040_queue_work(struct max17040_chip *chip)
|
||||
{
|
||||
queue_delayed_work(system_power_efficient_wq, &chip->work,
|
||||
MAX17040_DELAY);
|
||||
}
|
||||
|
||||
static void max17040_stop_work(void *data)
|
||||
{
|
||||
struct max17040_chip *chip = data;
|
||||
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
}
|
||||
|
||||
static void max17040_work(struct work_struct *work)
|
||||
|
@ -217,30 +310,51 @@ static void max17040_work(struct work_struct *work)
|
|||
/* store SOC and status to check changes */
|
||||
last_soc = chip->soc;
|
||||
last_status = chip->status;
|
||||
max17040_check_changes(chip->client);
|
||||
max17040_check_changes(chip);
|
||||
|
||||
/* check changes and send uevent */
|
||||
if (last_soc != chip->soc || last_status != chip->status)
|
||||
power_supply_changed(chip->battery);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &chip->work,
|
||||
MAX17040_DELAY);
|
||||
max17040_queue_work(chip);
|
||||
}
|
||||
|
||||
/* Returns true if alert cause was SOC change, not low SOC */
|
||||
static bool max17040_handle_soc_alert(struct max17040_chip *chip)
|
||||
{
|
||||
bool ret = true;
|
||||
u32 data;
|
||||
|
||||
regmap_read(chip->regmap, MAX17040_STATUS, &data);
|
||||
|
||||
if (data & MAX17040_STATUS_HD_MASK) {
|
||||
// this alert was caused by low soc
|
||||
ret = false;
|
||||
}
|
||||
if (data & MAX17040_STATUS_SC_MASK) {
|
||||
// soc change bit -- deassert to mark as handled
|
||||
regmap_write(chip->regmap, MAX17040_STATUS,
|
||||
data & ~MAX17040_STATUS_SC_MASK);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t max17040_thread_handler(int id, void *dev)
|
||||
{
|
||||
struct max17040_chip *chip = dev;
|
||||
struct i2c_client *client = chip->client;
|
||||
|
||||
dev_warn(&client->dev, "IRQ: Alert battery low level");
|
||||
if (!(chip->data.has_soc_alert && max17040_handle_soc_alert(chip)))
|
||||
dev_warn(&chip->client->dev, "IRQ: Alert battery low level\n");
|
||||
|
||||
/* read registers */
|
||||
max17040_check_changes(chip->client);
|
||||
max17040_check_changes(chip);
|
||||
|
||||
/* send uevent */
|
||||
power_supply_changed(chip->battery);
|
||||
|
||||
/* reset alert bit */
|
||||
max17040_set_low_soc_alert(client, chip->low_soc_alert);
|
||||
max17040_set_low_soc_alert(chip, chip->low_soc_alert);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -279,12 +393,13 @@ static int max17040_set_property(struct power_supply *psy,
|
|||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
|
||||
/* alert threshold can be programmed from 1% up to 32% */
|
||||
if ((val->intval < 1) || (val->intval > 32)) {
|
||||
/* alert threshold can be programmed from 1% up to 16/32% */
|
||||
if ((val->intval < 1) ||
|
||||
(val->intval > (chip->quirk_double_soc ? 16 : 32))) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ret = max17040_set_low_soc_alert(chip->client, val->intval);
|
||||
ret = max17040_set_low_soc_alert(chip, val->intval);
|
||||
chip->low_soc_alert = val->intval;
|
||||
break;
|
||||
default:
|
||||
|
@ -294,6 +409,41 @@ static int max17040_set_property(struct power_supply *psy,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int max17040_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct max17040_chip *chip = power_supply_get_drvdata(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
val->intval = max17040_get_status(chip);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = max17040_get_online(chip);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = max17040_get_vcell(chip);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
val->intval = max17040_get_soc(chip);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN:
|
||||
val->intval = chip->low_soc_alert;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config max17040_regmap = {
|
||||
.reg_bits = 8,
|
||||
.reg_stride = 2,
|
||||
.val_bits = 16,
|
||||
.val_format_endian = REGMAP_ENDIAN_BIG,
|
||||
};
|
||||
|
||||
static enum power_supply_property max17040_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
|
@ -318,6 +468,8 @@ static int max17040_probe(struct i2c_client *client,
|
|||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct max17040_chip *chip;
|
||||
enum chip_id chip_id;
|
||||
bool enable_irq = false;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
|
||||
|
@ -328,37 +480,68 @@ static int max17040_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
chip->client = client;
|
||||
chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
|
||||
chip->pdata = client->dev.platform_data;
|
||||
ret = max17040_get_of_data(chip);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"failed: low SOC alert OF data out of bounds\n");
|
||||
return ret;
|
||||
chip_id = (enum chip_id) id->driver_data;
|
||||
if (client->dev.of_node) {
|
||||
ret = max17040_get_of_data(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
chip_id = (enum chip_id) (uintptr_t)
|
||||
of_device_get_match_data(&client->dev);
|
||||
}
|
||||
chip->data = max17040_family[chip_id];
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
psy_cfg.drv_data = chip;
|
||||
|
||||
chip->battery = power_supply_register(&client->dev,
|
||||
chip->battery = devm_power_supply_register(&client->dev,
|
||||
&max17040_battery_desc, &psy_cfg);
|
||||
if (IS_ERR(chip->battery)) {
|
||||
dev_err(&client->dev, "failed: power supply register\n");
|
||||
return PTR_ERR(chip->battery);
|
||||
}
|
||||
|
||||
max17040_reset(client);
|
||||
max17040_get_version(client);
|
||||
ret = max17040_get_version(chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
dev_dbg(&chip->client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", ret);
|
||||
|
||||
if (chip_id == ID_MAX17040 || chip_id == ID_MAX17041)
|
||||
max17040_reset(chip);
|
||||
|
||||
max17040_set_rcomp(chip, chip->rcomp);
|
||||
|
||||
/* check interrupt */
|
||||
if (client->irq && of_device_is_compatible(client->dev.of_node,
|
||||
"maxim,max77836-battery")) {
|
||||
ret = max17040_set_low_soc_alert(client, chip->low_soc_alert);
|
||||
if (client->irq && chip->data.has_low_soc_alert) {
|
||||
ret = max17040_set_low_soc_alert(chip, chip->low_soc_alert);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to set low SOC alert: err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
enable_irq = true;
|
||||
}
|
||||
|
||||
if (client->irq && chip->data.has_soc_alert) {
|
||||
ret = max17040_set_soc_alert(chip, 1);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to set SOC alert: err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
enable_irq = true;
|
||||
} else {
|
||||
/* soc alerts negate the need for polling */
|
||||
INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
|
||||
ret = devm_add_action(&client->dev, max17040_stop_work, chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
max17040_queue_work(chip);
|
||||
}
|
||||
|
||||
if (enable_irq) {
|
||||
ret = max17040_enable_alert_irq(chip);
|
||||
if (ret) {
|
||||
client->irq = 0;
|
||||
|
@ -367,19 +550,6 @@ static int max17040_probe(struct i2c_client *client,
|
|||
}
|
||||
}
|
||||
|
||||
INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
|
||||
queue_delayed_work(system_power_efficient_wq, &chip->work,
|
||||
MAX17040_DELAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max17040_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
power_supply_unregister(chip->battery);
|
||||
cancel_delayed_work(&chip->work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -390,7 +560,11 @@ static int max17040_suspend(struct device *dev)
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
cancel_delayed_work(&chip->work);
|
||||
if (client->irq && chip->data.has_soc_alert)
|
||||
// disable soc alert to prevent wakeup
|
||||
max17040_set_soc_alert(chip, 0);
|
||||
else
|
||||
cancel_delayed_work(&chip->work);
|
||||
|
||||
if (client->irq && device_may_wakeup(dev))
|
||||
enable_irq_wake(client->irq);
|
||||
|
@ -403,12 +577,14 @@ static int max17040_resume(struct device *dev)
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max17040_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &chip->work,
|
||||
MAX17040_DELAY);
|
||||
|
||||
if (client->irq && device_may_wakeup(dev))
|
||||
disable_irq_wake(client->irq);
|
||||
|
||||
if (client->irq && chip->data.has_soc_alert)
|
||||
max17040_set_soc_alert(chip, 1);
|
||||
else
|
||||
max17040_queue_work(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -422,16 +598,30 @@ static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
|
|||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct i2c_device_id max17040_id[] = {
|
||||
{ "max17040" },
|
||||
{ "max77836-battery" },
|
||||
{ }
|
||||
{ "max17040", ID_MAX17040 },
|
||||
{ "max17041", ID_MAX17041 },
|
||||
{ "max17043", ID_MAX17043 },
|
||||
{ "max77836-battery", ID_MAX17043 },
|
||||
{ "max17044", ID_MAX17044 },
|
||||
{ "max17048", ID_MAX17048 },
|
||||
{ "max17049", ID_MAX17049 },
|
||||
{ "max17058", ID_MAX17058 },
|
||||
{ "max17059", ID_MAX17059 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max17040_id);
|
||||
|
||||
static const struct of_device_id max17040_of_match[] = {
|
||||
{ .compatible = "maxim,max17040" },
|
||||
{ .compatible = "maxim,max77836-battery" },
|
||||
{ },
|
||||
{ .compatible = "maxim,max17040", .data = (void *) ID_MAX17040 },
|
||||
{ .compatible = "maxim,max17041", .data = (void *) ID_MAX17041 },
|
||||
{ .compatible = "maxim,max17043", .data = (void *) ID_MAX17043 },
|
||||
{ .compatible = "maxim,max77836-battery", .data = (void *) ID_MAX17043 },
|
||||
{ .compatible = "maxim,max17044", .data = (void *) ID_MAX17044 },
|
||||
{ .compatible = "maxim,max17048", .data = (void *) ID_MAX17048 },
|
||||
{ .compatible = "maxim,max17049", .data = (void *) ID_MAX17049 },
|
||||
{ .compatible = "maxim,max17058", .data = (void *) ID_MAX17058 },
|
||||
{ .compatible = "maxim,max17059", .data = (void *) ID_MAX17059 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max17040_of_match);
|
||||
|
||||
|
@ -442,7 +632,6 @@ static struct i2c_driver max17040_i2c_driver = {
|
|||
.pm = MAX17040_PM_OPS,
|
||||
},
|
||||
.probe = max17040_probe,
|
||||
.remove = max17040_remove,
|
||||
.id_table = max17040_id,
|
||||
};
|
||||
module_i2c_driver(max17040_i2c_driver);
|
||||
|
|
|
@ -104,11 +104,6 @@ static int pm2xxx_charger_current_map[] = {
|
|||
3000,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id pm2xxx_ident[] = {
|
||||
{ "pm2301", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void set_lpn_pin(struct pm2xxx_charger *pm2)
|
||||
{
|
||||
if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin)) {
|
||||
|
@ -396,7 +391,7 @@ static int pm2_int_reg3(void *pm2_data, int val)
|
|||
|
||||
if (val & (PM2XXX_INT4_ITCHARGINGON)) {
|
||||
dev_dbg(pm2->dev ,
|
||||
"chargind operation has started\n");
|
||||
"charging operation has started\n");
|
||||
}
|
||||
|
||||
if (val & (PM2XXX_INT4_ITVRESUME)) {
|
||||
|
|
|
@ -579,6 +579,12 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
|||
info->charge_term_current_ua = -EINVAL;
|
||||
info->constant_charge_current_max_ua = -EINVAL;
|
||||
info->constant_charge_voltage_max_uv = -EINVAL;
|
||||
info->temp_ambient_alert_min = INT_MIN;
|
||||
info->temp_ambient_alert_max = INT_MAX;
|
||||
info->temp_alert_min = INT_MIN;
|
||||
info->temp_alert_max = INT_MAX;
|
||||
info->temp_min = INT_MIN;
|
||||
info->temp_max = INT_MAX;
|
||||
info->factory_internal_resistance_uohm = -EINVAL;
|
||||
info->resist_table = NULL;
|
||||
|
||||
|
@ -639,6 +645,19 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
|||
of_property_read_u32(battery_np, "factory-internal-resistance-micro-ohms",
|
||||
&info->factory_internal_resistance_uohm);
|
||||
|
||||
of_property_read_u32_index(battery_np, "ambient-celsius",
|
||||
0, &info->temp_ambient_alert_min);
|
||||
of_property_read_u32_index(battery_np, "ambient-celsius",
|
||||
1, &info->temp_ambient_alert_max);
|
||||
of_property_read_u32_index(battery_np, "alert-celsius",
|
||||
0, &info->temp_alert_min);
|
||||
of_property_read_u32_index(battery_np, "alert-celsius",
|
||||
1, &info->temp_alert_max);
|
||||
of_property_read_u32_index(battery_np, "operating-range-celsius",
|
||||
0, &info->temp_min);
|
||||
of_property_read_u32_index(battery_np, "operating-range-celsius",
|
||||
1, &info->temp_max);
|
||||
|
||||
len = of_property_count_u32_elems(battery_np, "ocv-capacity-celsius");
|
||||
if (len < 0 && len != -EINVAL) {
|
||||
err = len;
|
||||
|
|
|
@ -56,6 +56,7 @@ static const char * const POWER_SUPPLY_TYPE_TEXT[] = {
|
|||
[POWER_SUPPLY_TYPE_USB_PD] = "USB_PD",
|
||||
[POWER_SUPPLY_TYPE_USB_PD_DRP] = "USB_PD_DRP",
|
||||
[POWER_SUPPLY_TYPE_APPLE_BRICK_ID] = "BrickID",
|
||||
[POWER_SUPPLY_TYPE_WIRELESS] = "Wireless",
|
||||
};
|
||||
|
||||
static const char * const POWER_SUPPLY_USB_TYPE_TEXT[] = {
|
||||
|
|
|
@ -0,0 +1,556 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Power supply driver for the RICOH RN5T618 power management chip family
|
||||
*
|
||||
* Copyright (C) 2020 Andreas Kemnade
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/rn5t618.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define CHG_STATE_ADP_INPUT 0x40
|
||||
#define CHG_STATE_USB_INPUT 0x80
|
||||
#define CHG_STATE_MASK 0x1f
|
||||
#define CHG_STATE_CHG_OFF 0
|
||||
#define CHG_STATE_CHG_READY_VADP 1
|
||||
#define CHG_STATE_CHG_TRICKLE 2
|
||||
#define CHG_STATE_CHG_RAPID 3
|
||||
#define CHG_STATE_CHG_COMPLETE 4
|
||||
#define CHG_STATE_SUSPEND 5
|
||||
#define CHG_STATE_VCHG_OVER_VOL 6
|
||||
#define CHG_STATE_BAT_ERROR 7
|
||||
#define CHG_STATE_NO_BAT 8
|
||||
#define CHG_STATE_BAT_OVER_VOL 9
|
||||
#define CHG_STATE_BAT_TEMP_ERR 10
|
||||
#define CHG_STATE_DIE_ERR 11
|
||||
#define CHG_STATE_DIE_SHUTDOWN 12
|
||||
#define CHG_STATE_NO_BAT2 13
|
||||
#define CHG_STATE_CHG_READY_VUSB 14
|
||||
|
||||
#define FG_ENABLE 1
|
||||
|
||||
struct rn5t618_power_info {
|
||||
struct rn5t618 *rn5t618;
|
||||
struct platform_device *pdev;
|
||||
struct power_supply *battery;
|
||||
struct power_supply *usb;
|
||||
struct power_supply *adp;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static enum power_supply_property rn5t618_usb_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static enum power_supply_property rn5t618_adp_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
|
||||
static enum power_supply_property rn5t618_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
};
|
||||
|
||||
static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info,
|
||||
u8 reg, u16 *result)
|
||||
{
|
||||
int ret, i;
|
||||
u8 data[2];
|
||||
u16 old, new;
|
||||
|
||||
old = 0;
|
||||
/* Prevent races when registers are changing. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = regmap_bulk_read(info->rn5t618->regmap,
|
||||
reg, data, sizeof(data));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
new = data[0] << 8;
|
||||
new |= data[1];
|
||||
if (new == old)
|
||||
break;
|
||||
|
||||
old = new;
|
||||
}
|
||||
|
||||
*result = new;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_decode_status(unsigned int status)
|
||||
{
|
||||
switch (status & CHG_STATE_MASK) {
|
||||
case CHG_STATE_CHG_OFF:
|
||||
case CHG_STATE_SUSPEND:
|
||||
case CHG_STATE_VCHG_OVER_VOL:
|
||||
case CHG_STATE_DIE_SHUTDOWN:
|
||||
return POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
|
||||
case CHG_STATE_CHG_TRICKLE:
|
||||
case CHG_STATE_CHG_RAPID:
|
||||
return POWER_SUPPLY_STATUS_CHARGING;
|
||||
|
||||
case CHG_STATE_CHG_COMPLETE:
|
||||
return POWER_SUPPLY_STATUS_FULL;
|
||||
|
||||
default:
|
||||
return POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
}
|
||||
}
|
||||
|
||||
static int rn5t618_battery_status(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
unsigned int v;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
|
||||
if (v & 0xc0) { /* USB or ADP plugged */
|
||||
val->intval = rn5t618_decode_status(v);
|
||||
} else
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_present(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
unsigned int v;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
v &= CHG_STATE_MASK;
|
||||
if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2))
|
||||
val->intval = 0;
|
||||
else
|
||||
val->intval = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u16 res;
|
||||
int ret;
|
||||
|
||||
ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = res * 2 * 2500 / 4095 * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_current_now(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u16 res;
|
||||
int ret;
|
||||
|
||||
ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* current is negative when discharging */
|
||||
val->intval = sign_extend32(res, 13) * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_capacity(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
unsigned int v;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_temp(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u16 res;
|
||||
int ret;
|
||||
|
||||
ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = sign_extend32(res, 11) * 10 / 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_tte(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u16 res;
|
||||
int ret;
|
||||
|
||||
ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (res == 65535)
|
||||
return -ENODATA;
|
||||
|
||||
val->intval = res * 60;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u16 res;
|
||||
int ret;
|
||||
|
||||
ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (res == 65535)
|
||||
return -ENODATA;
|
||||
|
||||
val->intval = res * 60;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u16 res;
|
||||
int ret;
|
||||
|
||||
ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = res * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_charge_now(struct rn5t618_power_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u16 res;
|
||||
int ret;
|
||||
|
||||
ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = res * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int ret = 0;
|
||||
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
ret = rn5t618_battery_status(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
ret = rn5t618_battery_present(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = rn5t618_battery_voltage_now(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
ret = rn5t618_battery_current_now(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = rn5t618_battery_capacity(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
ret = rn5t618_battery_temp(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
|
||||
ret = rn5t618_battery_tte(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
|
||||
ret = rn5t618_battery_ttf(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
ret = rn5t618_battery_charge_full(info, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
||||
ret = rn5t618_battery_charge_now(info, val);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rn5t618_adp_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
|
||||
unsigned int chgstate;
|
||||
bool online;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
online = !!(chgstate & CHG_STATE_ADP_INPUT);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = online;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (!online) {
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
break;
|
||||
}
|
||||
val->intval = rn5t618_decode_status(chgstate);
|
||||
if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rn5t618_usb_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
|
||||
unsigned int chgstate;
|
||||
bool online;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
online = !!(chgstate & CHG_STATE_USB_INPUT);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = online;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (!online) {
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
break;
|
||||
}
|
||||
val->intval = rn5t618_decode_status(chgstate);
|
||||
if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct power_supply_desc rn5t618_battery_desc = {
|
||||
.name = "rn5t618-battery",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = rn5t618_battery_props,
|
||||
.num_properties = ARRAY_SIZE(rn5t618_battery_props),
|
||||
.get_property = rn5t618_battery_get_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc rn5t618_adp_desc = {
|
||||
.name = "rn5t618-adp",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.properties = rn5t618_adp_props,
|
||||
.num_properties = ARRAY_SIZE(rn5t618_adp_props),
|
||||
.get_property = rn5t618_adp_get_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc rn5t618_usb_desc = {
|
||||
.name = "rn5t618-usb",
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.properties = rn5t618_usb_props,
|
||||
.num_properties = ARRAY_SIZE(rn5t618_usb_props),
|
||||
.get_property = rn5t618_usb_get_property,
|
||||
};
|
||||
|
||||
static irqreturn_t rn5t618_charger_irq(int irq, void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct rn5t618_power_info *info = dev_get_drvdata(dev);
|
||||
|
||||
unsigned int ctrl, stat1, stat2, err;
|
||||
|
||||
regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err);
|
||||
regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl);
|
||||
regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1);
|
||||
regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2);
|
||||
|
||||
regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0);
|
||||
regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0);
|
||||
regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0);
|
||||
regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0);
|
||||
|
||||
dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n",
|
||||
err, ctrl, stat1, stat2);
|
||||
|
||||
power_supply_changed(info->usb);
|
||||
power_supply_changed(info->adp);
|
||||
power_supply_changed(info->battery);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rn5t618_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int v;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct rn5t618_power_info *info;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->pdev = pdev;
|
||||
info->rn5t618 = dev_get_drvdata(pdev->dev.parent);
|
||||
info->irq = -1;
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(v & FG_ENABLE)) {
|
||||
/* E.g. the vendor kernels of various Kobo and Tolino Ebook
|
||||
* readers disable the fuel gauge on shutdown. If a kernel
|
||||
* without fuel gauge support is booted after that, the fuel
|
||||
* gauge will get decalibrated.
|
||||
*/
|
||||
dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n");
|
||||
dev_info(&pdev->dev, "Expect imprecise results\n");
|
||||
regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL,
|
||||
FG_ENABLE, FG_ENABLE);
|
||||
}
|
||||
|
||||
psy_cfg.drv_data = info;
|
||||
info->battery = devm_power_supply_register(&pdev->dev,
|
||||
&rn5t618_battery_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(info->battery)) {
|
||||
ret = PTR_ERR(info->battery);
|
||||
dev_err(&pdev->dev, "failed to register battery: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
info->adp = devm_power_supply_register(&pdev->dev,
|
||||
&rn5t618_adp_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(info->adp)) {
|
||||
ret = PTR_ERR(info->adp);
|
||||
dev_err(&pdev->dev, "failed to register adp: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
info->usb = devm_power_supply_register(&pdev->dev,
|
||||
&rn5t618_usb_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(info->usb)) {
|
||||
ret = PTR_ERR(info->usb);
|
||||
dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (info->rn5t618->irq_data)
|
||||
info->irq = regmap_irq_get_virq(info->rn5t618->irq_data,
|
||||
RN5T618_IRQ_CHG);
|
||||
|
||||
if (info->irq < 0)
|
||||
info->irq = -1;
|
||||
else {
|
||||
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
|
||||
rn5t618_charger_irq,
|
||||
IRQF_ONESHOT,
|
||||
"rn5t618_power",
|
||||
&pdev->dev);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "request IRQ:%d fail\n",
|
||||
info->irq);
|
||||
info->irq = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rn5t618_power_driver = {
|
||||
.driver = {
|
||||
.name = "rn5t618-power",
|
||||
},
|
||||
.probe = rn5t618_power_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(rn5t618_power_driver);
|
||||
MODULE_ALIAS("platform:rn5t618-power");
|
||||
MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1731,11 +1731,13 @@ static const struct of_device_id rt9455_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, rt9455_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id rt9455_i2c_acpi_match[] = {
|
||||
{ "RT945500", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt9455_i2c_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver rt9455_driver = {
|
||||
.probe = rt9455_probe,
|
||||
|
|
|
@ -193,7 +193,6 @@ struct sbs_info {
|
|||
struct power_supply *power_supply;
|
||||
bool is_present;
|
||||
struct gpio_desc *gpio_detect;
|
||||
bool enable_detection;
|
||||
bool charger_broadcasts;
|
||||
int last_state;
|
||||
int poll_time;
|
||||
|
@ -480,37 +479,6 @@ static bool sbs_bat_needs_calibration(struct i2c_client *client)
|
|||
return !!(ret & BIT(7));
|
||||
}
|
||||
|
||||
static int sbs_get_battery_presence_and_health(
|
||||
struct i2c_client *client, enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Dummy command; if it succeeds, battery is present. */
|
||||
ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
|
||||
|
||||
if (ret < 0) { /* battery not present*/
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT) {
|
||||
val->intval = 0;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT)
|
||||
val->intval = 1; /* battery present */
|
||||
else { /* POWER_SUPPLY_PROP_HEALTH */
|
||||
if (sbs_bat_needs_calibration(client)) {
|
||||
val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED;
|
||||
} else {
|
||||
/* SBS spec doesn't have a general health command. */
|
||||
val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbs_get_ti_battery_presence_and_health(
|
||||
struct i2c_client *client, enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
|
@ -569,6 +537,41 @@ static int sbs_get_ti_battery_presence_and_health(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sbs_get_battery_presence_and_health(
|
||||
struct i2c_client *client, enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct sbs_info *chip = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
if (chip->flags & SBS_FLAGS_TI_BQ20ZX5)
|
||||
return sbs_get_ti_battery_presence_and_health(client, psp, val);
|
||||
|
||||
/* Dummy command; if it succeeds, battery is present. */
|
||||
ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
|
||||
|
||||
if (ret < 0) { /* battery not present*/
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT) {
|
||||
val->intval = 0;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT)
|
||||
val->intval = 1; /* battery present */
|
||||
else { /* POWER_SUPPLY_PROP_HEALTH */
|
||||
if (sbs_bat_needs_calibration(client)) {
|
||||
val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED;
|
||||
} else {
|
||||
/* SBS spec doesn't have a general health command. */
|
||||
val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbs_get_battery_property(struct i2c_client *client,
|
||||
int reg_offset, enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
|
@ -871,12 +874,7 @@ static int sbs_get_property(struct power_supply *psy,
|
|||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
if (chip->flags & SBS_FLAGS_TI_BQ20ZX5)
|
||||
ret = sbs_get_ti_battery_presence_and_health(client,
|
||||
psp, val);
|
||||
else
|
||||
ret = sbs_get_battery_presence_and_health(client, psp,
|
||||
val);
|
||||
ret = sbs_get_battery_presence_and_health(client, psp, val);
|
||||
|
||||
/* this can only be true if no gpio is used */
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT)
|
||||
|
@ -967,32 +965,30 @@ static int sbs_get_property(struct power_supply *psy,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!chip->enable_detection)
|
||||
goto done;
|
||||
if (!chip->gpio_detect && chip->is_present != (ret >= 0)) {
|
||||
bool old_present = chip->is_present;
|
||||
union power_supply_propval val;
|
||||
int err = sbs_get_battery_presence_and_health(
|
||||
client, POWER_SUPPLY_PROP_PRESENT, &val);
|
||||
|
||||
if (!chip->gpio_detect &&
|
||||
chip->is_present != (ret >= 0)) {
|
||||
sbs_update_presence(chip, (ret >= 0));
|
||||
power_supply_changed(chip->power_supply);
|
||||
sbs_update_presence(chip, !err && val.intval);
|
||||
|
||||
if (old_present != chip->is_present)
|
||||
power_supply_changed(chip->power_supply);
|
||||
}
|
||||
|
||||
done:
|
||||
if (!ret) {
|
||||
/* Convert units to match requirements for power supply class */
|
||||
sbs_unit_adjustment(client, psp, val);
|
||||
dev_dbg(&client->dev,
|
||||
"%s: property = %d, value = %x\n", __func__,
|
||||
psp, val->intval);
|
||||
} else if (!chip->is_present) {
|
||||
/* battery not present, so return NODATA for properties */
|
||||
ret = -ENODATA;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s: property = %d, value = %x\n", __func__, psp, val->intval);
|
||||
|
||||
if (ret && chip->is_present)
|
||||
return ret;
|
||||
|
||||
/* battery not present, so return NODATA for properties */
|
||||
if (ret)
|
||||
return -ENODATA;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sbs_supply_changed(struct sbs_info *chip)
|
||||
|
@ -1098,7 +1094,6 @@ static int sbs_probe(struct i2c_client *client)
|
|||
|
||||
chip->flags = (u32)(uintptr_t)device_get_match_data(&client->dev);
|
||||
chip->client = client;
|
||||
chip->enable_detection = false;
|
||||
psy_cfg.of_node = client->dev.of_node;
|
||||
psy_cfg.drv_data = chip;
|
||||
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
|
@ -1159,15 +1154,19 @@ skip_gpio:
|
|||
* to the battery.
|
||||
*/
|
||||
if (!(force_load || chip->gpio_detect)) {
|
||||
rc = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
|
||||
union power_supply_propval val;
|
||||
|
||||
if (rc < 0) {
|
||||
dev_err(&client->dev, "%s: Failed to get device status\n",
|
||||
__func__);
|
||||
rc = sbs_get_battery_presence_and_health(
|
||||
client, POWER_SUPPLY_PROP_PRESENT, &val);
|
||||
if (rc < 0 || !val.intval) {
|
||||
dev_err(&client->dev, "Failed to get present status\n");
|
||||
rc = -ENODEV;
|
||||
goto exit_psupply;
|
||||
}
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&chip->work, sbs_delayed_work);
|
||||
|
||||
chip->power_supply = devm_power_supply_register(&client->dev, sbs_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(chip->power_supply)) {
|
||||
|
@ -1180,10 +1179,6 @@ skip_gpio:
|
|||
dev_info(&client->dev,
|
||||
"%s: battery gas gauge device registered\n", client->name);
|
||||
|
||||
INIT_DELAYED_WORK(&chip->work, sbs_delayed_work);
|
||||
|
||||
chip->enable_detection = true;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_psupply:
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -352,8 +352,8 @@ static int param_set_ac_online(const char *key, const struct kernel_param *kp)
|
|||
|
||||
static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
strcpy(buffer, map_get_key(map_ac_online, ac_online, "unknown"));
|
||||
return strlen(buffer);
|
||||
return sprintf(buffer, "%s\n",
|
||||
map_get_key(map_ac_online, ac_online, "unknown"));
|
||||
}
|
||||
|
||||
static int param_set_usb_online(const char *key, const struct kernel_param *kp)
|
||||
|
@ -365,8 +365,8 @@ static int param_set_usb_online(const char *key, const struct kernel_param *kp)
|
|||
|
||||
static int param_get_usb_online(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
strcpy(buffer, map_get_key(map_ac_online, usb_online, "unknown"));
|
||||
return strlen(buffer);
|
||||
return sprintf(buffer, "%s\n",
|
||||
map_get_key(map_ac_online, usb_online, "unknown"));
|
||||
}
|
||||
|
||||
static int param_set_battery_status(const char *key,
|
||||
|
@ -379,8 +379,8 @@ static int param_set_battery_status(const char *key,
|
|||
|
||||
static int param_get_battery_status(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
strcpy(buffer, map_get_key(map_status, battery_status, "unknown"));
|
||||
return strlen(buffer);
|
||||
return sprintf(buffer, "%s\n",
|
||||
map_get_key(map_ac_online, battery_status, "unknown"));
|
||||
}
|
||||
|
||||
static int param_set_battery_health(const char *key,
|
||||
|
@ -393,8 +393,8 @@ static int param_set_battery_health(const char *key,
|
|||
|
||||
static int param_get_battery_health(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
strcpy(buffer, map_get_key(map_health, battery_health, "unknown"));
|
||||
return strlen(buffer);
|
||||
return sprintf(buffer, "%s\n",
|
||||
map_get_key(map_ac_online, battery_health, "unknown"));
|
||||
}
|
||||
|
||||
static int param_set_battery_present(const char *key,
|
||||
|
@ -408,8 +408,8 @@ static int param_set_battery_present(const char *key,
|
|||
static int param_get_battery_present(char *buffer,
|
||||
const struct kernel_param *kp)
|
||||
{
|
||||
strcpy(buffer, map_get_key(map_present, battery_present, "unknown"));
|
||||
return strlen(buffer);
|
||||
return sprintf(buffer, "%s\n",
|
||||
map_get_key(map_ac_online, battery_present, "unknown"));
|
||||
}
|
||||
|
||||
static int param_set_battery_technology(const char *key,
|
||||
|
@ -424,9 +424,9 @@ static int param_set_battery_technology(const char *key,
|
|||
static int param_get_battery_technology(char *buffer,
|
||||
const struct kernel_param *kp)
|
||||
{
|
||||
strcpy(buffer,
|
||||
map_get_key(map_technology, battery_technology, "unknown"));
|
||||
return strlen(buffer);
|
||||
return sprintf(buffer, "%s\n",
|
||||
map_get_key(map_ac_online, battery_technology,
|
||||
"unknown"));
|
||||
}
|
||||
|
||||
static int param_set_battery_capacity(const char *key,
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
/* Interrupt Status */
|
||||
#define UCS1002_REG_INTERRUPT_STATUS 0x10
|
||||
# define F_ERR BIT(7)
|
||||
# define F_DISCHARGE_ERR BIT(6)
|
||||
# define F_RESET BIT(5)
|
||||
# define F_MIN_KEEP_OUT BIT(4)
|
||||
|
@ -103,6 +104,9 @@ struct ucs1002_info {
|
|||
struct regulator_dev *rdev;
|
||||
bool present;
|
||||
bool output_disable;
|
||||
struct delayed_work health_poll;
|
||||
int health;
|
||||
|
||||
};
|
||||
|
||||
static enum power_supply_property ucs1002_props[] = {
|
||||
|
@ -362,32 +366,6 @@ static int ucs1002_get_usb_type(struct ucs1002_info *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ucs1002_get_health(struct ucs1002_info *info,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
unsigned int reg;
|
||||
int ret, health;
|
||||
|
||||
ret = regmap_read(info->regmap, UCS1002_REG_INTERRUPT_STATUS, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (reg & F_TSD)
|
||||
health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
else if (reg & (F_OVER_VOLT | F_BACK_VOLT))
|
||||
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
|
||||
else if (reg & F_OVER_ILIM)
|
||||
health = POWER_SUPPLY_HEALTH_OVERCURRENT;
|
||||
else if (reg & (F_DISCHARGE_ERR | F_MIN_KEEP_OUT))
|
||||
health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
|
||||
else
|
||||
health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
|
||||
val->intval = health;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ucs1002_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
|
@ -406,7 +384,7 @@ static int ucs1002_get_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_USB_TYPE:
|
||||
return ucs1002_get_usb_type(info, val);
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
return ucs1002_get_health(info, val);
|
||||
return val->intval = info->health;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = info->present;
|
||||
return 0;
|
||||
|
@ -458,6 +436,38 @@ static const struct power_supply_desc ucs1002_charger_desc = {
|
|||
.num_properties = ARRAY_SIZE(ucs1002_props),
|
||||
};
|
||||
|
||||
static void ucs1002_health_poll(struct work_struct *work)
|
||||
{
|
||||
struct ucs1002_info *info = container_of(work, struct ucs1002_info,
|
||||
health_poll.work);
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
ret = regmap_read(info->regmap, UCS1002_REG_INTERRUPT_STATUS, ®);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
/* bad health and no status change, just schedule us again in a while */
|
||||
if ((reg & F_ERR) && info->health != POWER_SUPPLY_HEALTH_GOOD) {
|
||||
schedule_delayed_work(&info->health_poll,
|
||||
msecs_to_jiffies(2000));
|
||||
return;
|
||||
}
|
||||
|
||||
if (reg & F_TSD)
|
||||
info->health = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
else if (reg & (F_OVER_VOLT | F_BACK_VOLT))
|
||||
info->health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
|
||||
else if (reg & F_OVER_ILIM)
|
||||
info->health = POWER_SUPPLY_HEALTH_OVERCURRENT;
|
||||
else if (reg & (F_DISCHARGE_ERR | F_MIN_KEEP_OUT))
|
||||
info->health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
|
||||
else
|
||||
info->health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
|
||||
sysfs_notify(&info->charger->dev.kobj, NULL, "health");
|
||||
}
|
||||
|
||||
static irqreturn_t ucs1002_charger_irq(int irq, void *data)
|
||||
{
|
||||
int ret, regval;
|
||||
|
@ -484,7 +494,7 @@ static irqreturn_t ucs1002_alert_irq(int irq, void *data)
|
|||
{
|
||||
struct ucs1002_info *info = data;
|
||||
|
||||
power_supply_changed(info->charger);
|
||||
mod_delayed_work(system_wq, &info->health_poll, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -632,6 +642,9 @@ static int ucs1002_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
info->health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
INIT_DELAYED_WORK(&info->health_poll, ucs1002_health_poll);
|
||||
|
||||
if (irq_a_det > 0) {
|
||||
ret = devm_request_threaded_irq(dev, irq_a_det, NULL,
|
||||
ucs1002_charger_irq,
|
||||
|
@ -645,10 +658,8 @@ static int ucs1002_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
if (irq_alert > 0) {
|
||||
ret = devm_request_threaded_irq(dev, irq_alert, NULL,
|
||||
ucs1002_alert_irq,
|
||||
IRQF_ONESHOT,
|
||||
"ucs1002-alert", info);
|
||||
ret = devm_request_irq(dev, irq_alert, ucs1002_alert_irq,
|
||||
0,"ucs1002-alert", info);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request ALERT threaded irq: %d\n",
|
||||
ret);
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0-or-later or MIT) */
|
||||
/*
|
||||
* Author: David Heidelberg <david@ixit.cz>
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_SMB347_CHARGER_H
|
||||
#define _DT_BINDINGS_SMB347_CHARGER_H
|
||||
|
||||
/* Charging compensation method */
|
||||
#define SMB3XX_SOFT_TEMP_COMPENSATE_NONE 0
|
||||
#define SMB3XX_SOFT_TEMP_COMPENSATE_CURRENT 1
|
||||
#define SMB3XX_SOFT_TEMP_COMPENSATE_VOLTAGE 2
|
||||
|
||||
/* Charging enable control */
|
||||
#define SMB3XX_CHG_ENABLE_SW 0
|
||||
#define SMB3XX_CHG_ENABLE_PIN_ACTIVE_LOW 1
|
||||
#define SMB3XX_CHG_ENABLE_PIN_ACTIVE_HIGH 2
|
||||
|
||||
#endif
|
|
@ -32,6 +32,7 @@ enum bq27xxx_chip {
|
|||
BQ27621,
|
||||
BQ27Z561,
|
||||
BQ28Z610,
|
||||
BQ34Z100,
|
||||
};
|
||||
|
||||
struct bq27xxx_device_info;
|
||||
|
|
|
@ -31,22 +31,16 @@ enum polling_modes {
|
|||
CM_POLL_CHARGING_ONLY,
|
||||
};
|
||||
|
||||
enum cm_event_types {
|
||||
CM_EVENT_UNKNOWN = 0,
|
||||
CM_EVENT_BATT_FULL,
|
||||
CM_EVENT_BATT_IN,
|
||||
CM_EVENT_BATT_OUT,
|
||||
CM_EVENT_BATT_OVERHEAT,
|
||||
CM_EVENT_BATT_COLD,
|
||||
CM_EVENT_EXT_PWR_IN_OUT,
|
||||
CM_EVENT_CHG_START_STOP,
|
||||
CM_EVENT_OTHERS,
|
||||
enum cm_batt_temp {
|
||||
CM_BATT_OK = 0,
|
||||
CM_BATT_OVERHEAT,
|
||||
CM_BATT_COLD,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct charger_cable
|
||||
* @extcon_name: the name of extcon device.
|
||||
* @name: the name of charger cable(external connector).
|
||||
* @name: the name of the cable connector
|
||||
* @extcon_dev: the extcon device.
|
||||
* @wq: the workqueue to control charger according to the state of
|
||||
* charger cable. If charger cable is attached, enable charger.
|
||||
|
@ -62,9 +56,10 @@ enum cm_event_types {
|
|||
struct charger_cable {
|
||||
const char *extcon_name;
|
||||
const char *name;
|
||||
struct extcon_dev *extcon_dev;
|
||||
u64 extcon_type;
|
||||
|
||||
/* The charger-manager use Extcon framework */
|
||||
struct extcon_specific_cable_nb extcon_dev;
|
||||
struct work_struct wq;
|
||||
struct notifier_block nb;
|
||||
|
||||
|
@ -131,11 +126,10 @@ struct charger_regulator {
|
|||
* @psy_name: the name of power-supply-class for charger manager
|
||||
* @polling_mode:
|
||||
* Determine which polling mode will be used
|
||||
* @fullbatt_vchkdrop_ms:
|
||||
* @fullbatt_vchkdrop_uV:
|
||||
* Check voltage drop after the battery is fully charged.
|
||||
* If it has dropped more than fullbatt_vchkdrop_uV after
|
||||
* fullbatt_vchkdrop_ms, CM will restart charging.
|
||||
* If it has dropped more than fullbatt_vchkdrop_uV
|
||||
* CM will restart charging.
|
||||
* @fullbatt_uV: voltage in microvolt
|
||||
* If VBATT >= fullbatt_uV, it is assumed to be full.
|
||||
* @fullbatt_soc: state of Charge in %
|
||||
|
@ -172,7 +166,6 @@ struct charger_desc {
|
|||
enum polling_modes polling_mode;
|
||||
unsigned int polling_interval_ms;
|
||||
|
||||
unsigned int fullbatt_vchkdrop_ms;
|
||||
unsigned int fullbatt_vchkdrop_uV;
|
||||
unsigned int fullbatt_uV;
|
||||
unsigned int fullbatt_soc;
|
||||
|
@ -211,9 +204,6 @@ struct charger_desc {
|
|||
* @charger_stat: array of power_supply for chargers
|
||||
* @tzd_batt : thermal zone device for battery
|
||||
* @charger_enabled: the state of charger
|
||||
* @fullbatt_vchk_jiffies_at:
|
||||
* jiffies at the time full battery check will occur.
|
||||
* @fullbatt_vchk_work: work queue for full battery check
|
||||
* @emergency_stop:
|
||||
* When setting true, stop charging
|
||||
* @psy_name_buf: the name of power-supply-class for charger manager
|
||||
|
@ -224,6 +214,7 @@ struct charger_desc {
|
|||
* saved status of battery before entering suspend-to-RAM
|
||||
* @charging_start_time: saved start time of enabling charging
|
||||
* @charging_end_time: saved end time of disabling charging
|
||||
* @battery_status: Current battery status
|
||||
*/
|
||||
struct charger_manager {
|
||||
struct list_head entry;
|
||||
|
@ -235,9 +226,6 @@ struct charger_manager {
|
|||
#endif
|
||||
bool charger_enabled;
|
||||
|
||||
unsigned long fullbatt_vchk_jiffies_at;
|
||||
struct delayed_work fullbatt_vchk_work;
|
||||
|
||||
int emergency_stop;
|
||||
|
||||
char psy_name_buf[PSY_NAME_MAX + 1];
|
||||
|
@ -246,13 +234,8 @@ struct charger_manager {
|
|||
|
||||
u64 charging_start_time;
|
||||
u64 charging_end_time;
|
||||
|
||||
int battery_status;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_CHARGER_MANAGER)
|
||||
extern void cm_notify_event(struct power_supply *psy,
|
||||
enum cm_event_types type, char *msg);
|
||||
#else
|
||||
static inline void cm_notify_event(struct power_supply *psy,
|
||||
enum cm_event_types type, char *msg) { }
|
||||
#endif
|
||||
#endif /* _CHARGER_MANAGER_H */
|
||||
|
|
|
@ -13,18 +13,12 @@
|
|||
* struct gpio_charger_platform_data - platform_data for gpio_charger devices
|
||||
* @name: Name for the chargers power_supply device
|
||||
* @type: Type of the charger
|
||||
* @gpio: GPIO which is used to indicate the chargers status
|
||||
* @gpio_active_low: Should be set to 1 if the GPIO is active low otherwise 0
|
||||
* @supplied_to: Array of battery names to which this chargers supplies power
|
||||
* @num_supplicants: Number of entries in the supplied_to array
|
||||
*/
|
||||
struct gpio_charger_platform_data {
|
||||
const char *name;
|
||||
enum power_supply_type type;
|
||||
|
||||
int gpio;
|
||||
int gpio_active_low;
|
||||
|
||||
char **supplied_to;
|
||||
size_t num_supplicants;
|
||||
};
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Summit Microelectronics SMB347 Battery Charger Driver
|
||||
*
|
||||
* Copyright (C) 2011, Intel Corporation
|
||||
*
|
||||
* Authors: Bruce E. Robertson <bruce.e.robertson@intel.com>
|
||||
* Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef SMB347_CHARGER_H
|
||||
#define SMB347_CHARGER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
enum {
|
||||
/* use the default compensation method */
|
||||
SMB347_SOFT_TEMP_COMPENSATE_DEFAULT = -1,
|
||||
|
||||
SMB347_SOFT_TEMP_COMPENSATE_NONE,
|
||||
SMB347_SOFT_TEMP_COMPENSATE_CURRENT,
|
||||
SMB347_SOFT_TEMP_COMPENSATE_VOLTAGE,
|
||||
};
|
||||
|
||||
/* Use default factory programmed value for hard/soft temperature limit */
|
||||
#define SMB347_TEMP_USE_DEFAULT -273
|
||||
|
||||
/*
|
||||
* Charging enable can be controlled by software (via i2c) by
|
||||
* smb347-charger driver or by EN pin (active low/high).
|
||||
*/
|
||||
enum smb347_chg_enable {
|
||||
SMB347_CHG_ENABLE_SW,
|
||||
SMB347_CHG_ENABLE_PIN_ACTIVE_LOW,
|
||||
SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct smb347_charger_platform_data - platform data for SMB347 charger
|
||||
* @battery_info: Information about the battery
|
||||
* @max_charge_current: maximum current (in uA) the battery can be charged
|
||||
* @max_charge_voltage: maximum voltage (in uV) the battery can be charged
|
||||
* @pre_charge_current: current (in uA) to use in pre-charging phase
|
||||
* @termination_current: current (in uA) used to determine when the
|
||||
* charging cycle terminates
|
||||
* @pre_to_fast_voltage: voltage (in uV) treshold used for transitioning to
|
||||
* pre-charge to fast charge mode
|
||||
* @mains_current_limit: maximum input current drawn from AC/DC input (in uA)
|
||||
* @usb_hc_current_limit: maximum input high current (in uA) drawn from USB
|
||||
* input
|
||||
* @chip_temp_threshold: die temperature where device starts limiting charge
|
||||
* current [%100 - %130] (in degree C)
|
||||
* @soft_cold_temp_limit: soft cold temperature limit [%0 - %15] (in degree C),
|
||||
* granularity is 5 deg C.
|
||||
* @soft_hot_temp_limit: soft hot temperature limit [%40 - %55] (in degree C),
|
||||
* granularity is 5 deg C.
|
||||
* @hard_cold_temp_limit: hard cold temperature limit [%-5 - %10] (in degree C),
|
||||
* granularity is 5 deg C.
|
||||
* @hard_hot_temp_limit: hard hot temperature limit [%50 - %65] (in degree C),
|
||||
* granularity is 5 deg C.
|
||||
* @suspend_on_hard_temp_limit: suspend charging when hard limit is hit
|
||||
* @soft_temp_limit_compensation: compensation method when soft temperature
|
||||
* limit is hit
|
||||
* @charge_current_compensation: current (in uA) for charging compensation
|
||||
* current when temperature hits soft limits
|
||||
* @use_mains: AC/DC input can be used
|
||||
* @use_usb: USB input can be used
|
||||
* @use_usb_otg: USB OTG output can be used (not implemented yet)
|
||||
* @irq_gpio: GPIO number used for interrupts (%-1 if not used)
|
||||
* @enable_control: how charging enable/disable is controlled
|
||||
* (driver/pin controls)
|
||||
*
|
||||
* @use_main, @use_usb, and @use_usb_otg are means to enable/disable
|
||||
* hardware support for these. This is useful when we want to have for
|
||||
* example OTG charging controlled via OTG transceiver driver and not by
|
||||
* the SMB347 hardware.
|
||||
*
|
||||
* Hard and soft temperature limit values are given as described in the
|
||||
* device data sheet and assuming NTC beta value is %3750. Even if this is
|
||||
* not the case, these values should be used. They can be mapped to the
|
||||
* corresponding NTC beta values with the help of table %2 in the data
|
||||
* sheet. So for example if NTC beta is %3375 and we want to program hard
|
||||
* hot limit to be %53 deg C, @hard_hot_temp_limit should be set to %50.
|
||||
*
|
||||
* If zero value is given in any of the current and voltage values, the
|
||||
* factory programmed default will be used. For soft/hard temperature
|
||||
* values, pass in %SMB347_TEMP_USE_DEFAULT instead.
|
||||
*/
|
||||
struct smb347_charger_platform_data {
|
||||
struct power_supply_info battery_info;
|
||||
unsigned int max_charge_current;
|
||||
unsigned int max_charge_voltage;
|
||||
unsigned int pre_charge_current;
|
||||
unsigned int termination_current;
|
||||
unsigned int pre_to_fast_voltage;
|
||||
unsigned int mains_current_limit;
|
||||
unsigned int usb_hc_current_limit;
|
||||
unsigned int chip_temp_threshold;
|
||||
int soft_cold_temp_limit;
|
||||
int soft_hot_temp_limit;
|
||||
int hard_cold_temp_limit;
|
||||
int hard_hot_temp_limit;
|
||||
bool suspend_on_hard_temp_limit;
|
||||
unsigned int soft_temp_limit_compensation;
|
||||
unsigned int charge_current_compensation;
|
||||
bool use_mains;
|
||||
bool use_usb;
|
||||
bool use_usb_otg;
|
||||
int irq_gpio;
|
||||
enum smb347_chg_enable enable_control;
|
||||
};
|
||||
|
||||
#endif /* SMB347_CHARGER_H */
|
|
@ -186,6 +186,7 @@ enum power_supply_type {
|
|||
POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery Port */
|
||||
POWER_SUPPLY_TYPE_USB_PD_DRP, /* PD Dual Role Port */
|
||||
POWER_SUPPLY_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */
|
||||
POWER_SUPPLY_TYPE_WIRELESS, /* Wireless */
|
||||
};
|
||||
|
||||
enum power_supply_usb_type {
|
||||
|
@ -365,6 +366,12 @@ struct power_supply_battery_info {
|
|||
int constant_charge_voltage_max_uv; /* microVolts */
|
||||
int factory_internal_resistance_uohm; /* microOhms */
|
||||
int ocv_temp[POWER_SUPPLY_OCV_TEMP_MAX];/* celsius */
|
||||
int temp_ambient_alert_min; /* celsius */
|
||||
int temp_ambient_alert_max; /* celsius */
|
||||
int temp_alert_min; /* celsius */
|
||||
int temp_alert_max; /* celsius */
|
||||
int temp_min; /* celsius */
|
||||
int temp_max; /* celsius */
|
||||
struct power_supply_battery_ocv_table *ocv_table[POWER_SUPPLY_OCV_TEMP_MAX];
|
||||
int ocv_table_size[POWER_SUPPLY_OCV_TEMP_MAX];
|
||||
struct power_supply_resistance_temp_table *resist_table;
|
||||
|
|
Загрузка…
Ссылка в новой задаче