mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
power supply and reset changes for the v5.17 series
power-supply core: - introduce "No Battery" health status - use library interpolation - add power_supply_battery_info documentation - migrate power_supply_battery_info to be fully heap allocated making it more obvious that it needs to be free'd manually Drivers: - max77976-charger: new driver - qcom-smbb: add pm8226 charger support - bq25890-charger: support battery temperature readings - ab8500: continue migrating towards using standard core APIs -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmHb+9YACgkQ2O7X88g7 +pqhGw/+NyqnkSIsU4udxYJY47ooaZ7f2rApFueJSre0Xzwi37SQFFvstBb196YP B1mr2H16Slni0kRItu+B1H04mI1y1o7zT4E84s1DoMQjILLtxh+LiT8tefhhWtBs 5a6IiUKtxo2HZZgreTqyAAjqPYkdRGDkChK87zBZdxIGcaGHXkRlyuTSR2P406r/ qvA5uCkVg7CMqXf0RemcIlEOvSxaPXZz+PVJjn6qbjSioQHtOekoxoMBziy31Nhm Qp0sEYYlW6ZRpaP/IFU21sZb8zaH+isOrg2U/LttgfABdwtEVUz/nygZwSD0ncBi zSUrc4Mu/goh7m5oY91HUsis3fzgABMd/xdaDDzJoh91LvguE9lA2vP5r7hEDLVD S7v9RNNEfALce5sHGAEXQX0IztD0xZhSRe6jpeAYLVB0OG1Tae3q/6dlEHQsz2rb oANYsxrAU0hf2MnsXa6FnR1cnVJNm7z/bQpTFbU7guSX8Vi5n8jzmghoi3piCjyk 9YXMROuivXuaBz1wXNk2IXzdYwtOTeateo2yYdSQol3UnYgUtIrn+qBVeuElbC3C qkb21yTpEIk3aoZOjbKFze7ks6L8c5Nip+66s4WkcAucK3Uxii1QpTR9f1+TdxN0 vjybsIRHqPnCh6yl1JR/0NNvFPGQWkJt6sveQXas/LAZ77MOMro= =9cda -----END PGP SIGNATURE----- Merge tag 'for-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset updates from Sebastian Reichel: "Power-supply core: - introduce "No Battery" health status - use library interpolation - add power_supply_battery_info documentation - migrate power_supply_battery_info to be fully heap allocated making it more obvious that it needs to be free'd manually Drivers: - max77976-charger: new driver - qcom-smbb: add pm8226 charger support - bq25890-charger: support battery temperature readings - ab8500: continue migrating towards using standard core APIs" * tag 'for-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (28 commits) power: supply_core: Pass pointer to battery info power: supply: ab8500: Fix the error handling path of ab8500_charger_probe() power: reset: mt6397: Check for null res pointer power: bq25890: add POWER_SUPPLY_PROP_TEMP power: supply: qcom_smbb: support pm8226 dt-bindings: power: supply: pm8941-charger: add pm8226 power: supply: ab8500: Standardize capacity lookup power: supply: ab8500: Standardize temp res lookup power: supply: ab8500: Standardize CV voltage power: supply: ab8500: Standardize CC current power: supply: ab8500: Make recharge capacity a constant power: supply: ab8500: Standardize termination current power: supply: ab8500: Standardize internal resistance power: supply: ab8500_fg: Init battery data in bind() power: supply: ab8500: Standardize voltages power: supply: ab8500: Standardize technology power: supply: ab8500: Standardize design capacity power: supply: ab8500: Use only one battery type power: supply: ab8500: Drop unused battery types power: supply: ab8500: Standardize operating temperature ...
This commit is contained in:
commit
039053c119
@ -413,7 +413,7 @@ Description:
|
||||
"Over voltage", "Unspecified failure", "Cold",
|
||||
"Watchdog timer expire", "Safety timer expire",
|
||||
"Over current", "Calibration required", "Warm",
|
||||
"Cool", "Hot"
|
||||
"Cool", "Hot", "No battery"
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/precharge_current
|
||||
Date: June 2017
|
||||
|
@ -1,41 +0,0 @@
|
||||
Driver a GPIO line that can be used to turn the power off.
|
||||
|
||||
The driver supports both level triggered and edge triggered power off.
|
||||
At driver load time, the driver will request the given gpio line and
|
||||
install a handler to power off the system. If the optional properties
|
||||
'input' is not found, the GPIO line will be driven in the inactive
|
||||
state. Otherwise its configured as an input.
|
||||
|
||||
When the power-off handler is called, the gpio is configured as an
|
||||
output, and drive active, so triggering a level triggered power off
|
||||
condition. This will also cause an inactive->active edge condition, so
|
||||
triggering positive edge triggered power off. After a delay of 100ms,
|
||||
the GPIO is set to inactive, thus causing an active->inactive edge,
|
||||
triggering negative edge triggered power off. After another 100ms
|
||||
delay the GPIO is driver active again. If the power is still on and
|
||||
the CPU still running after a 3000ms delay, a WARN_ON(1) is emitted.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "gpio-poweroff".
|
||||
- gpios : The GPIO to set high/low, see "gpios property" in
|
||||
Documentation/devicetree/bindings/gpio/gpio.txt. If the pin should be
|
||||
low to power down the board set it to "Active Low", otherwise set
|
||||
gpio to "Active High".
|
||||
|
||||
Optional properties:
|
||||
- input : Initially configure the GPIO line as an input. Only reconfigure
|
||||
it to an output when the power-off handler is called. If this optional
|
||||
property is not specified, the GPIO is initialized as an output in its
|
||||
inactive state.
|
||||
- active-delay-ms: Delay (default 100) to wait after driving gpio active
|
||||
- inactive-delay-ms: Delay (default 100) to wait after driving gpio inactive
|
||||
- timeout-ms: Time to wait before asserting a WARN_ON(1). If nothing is
|
||||
specified, 3000 ms is used.
|
||||
|
||||
Examples:
|
||||
|
||||
gpio-poweroff {
|
||||
compatible = "gpio-poweroff";
|
||||
gpios = <&gpio 4 0>;
|
||||
timeout-ms = <3000>;
|
||||
};
|
@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/reset/gpio-poweroff.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GPIO controlled power off
|
||||
|
||||
maintainers:
|
||||
- Sebastian Reichel <sre@kernel.org>
|
||||
|
||||
description: >
|
||||
System power off support via a GPIO line. When a shutdown is
|
||||
executed the operating system is expected to switch the GPIO
|
||||
from inactive to active. After a delay (active-delay-ms) it
|
||||
is expected to be switched back to inactive. After another
|
||||
delay (inactive-delay-ms) it is configured as active again.
|
||||
Finally the operating system assumes the power off failed if
|
||||
the system is still running after waiting some time (timeout-ms).
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: gpio-poweroff
|
||||
|
||||
gpios:
|
||||
maxItems: 1
|
||||
|
||||
input:
|
||||
type: boolean
|
||||
description: >
|
||||
Initially configure the GPIO line as an input. Only reconfigure
|
||||
it to an output when the power-off sequence is initiated. If this optional
|
||||
property is not specified, the GPIO is initialized as an output in its inactive state.
|
||||
|
||||
active-delay-ms:
|
||||
default: 100
|
||||
description: Delay to wait after driving gpio active
|
||||
|
||||
inactive-delay-ms:
|
||||
default: 100
|
||||
description: Delay to wait after driving gpio inactive
|
||||
|
||||
timeout-ms:
|
||||
default: 3000
|
||||
description: Time to wait before assuming the power off sequence failed.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
gpio-poweroff {
|
||||
compatible = "gpio-poweroff";
|
||||
gpios = <&gpio 4 0>;
|
||||
timeout-ms = <3000>;
|
||||
};
|
@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/supply/maxim,max77976.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim Integrated MAX77976 Battery charger
|
||||
|
||||
maintainers:
|
||||
- Luca Ceresoli <luca@lucaceresoli.net>
|
||||
|
||||
description: |
|
||||
The Maxim MAX77976 is a 19Vin / 5.5A, 1-Cell Li+ battery charger
|
||||
configured via I2C.
|
||||
|
||||
allOf:
|
||||
- $ref: power-supply.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: maxim,max77976
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
charger@6b {
|
||||
compatible = "maxim,max77976";
|
||||
reg = <0x6b>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -11,7 +11,9 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,pm8941-charger
|
||||
enum:
|
||||
- qcom,pm8226-charger
|
||||
- qcom,pm8941-charger
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -11668,6 +11668,12 @@ F: Documentation/devicetree/bindings/*/*max77802.txt
|
||||
F: drivers/regulator/max77802-regulator.c
|
||||
F: include/dt-bindings/*/*max77802.h
|
||||
|
||||
MAXIM MAX77976 BATTERY CHARGER
|
||||
M: Luca Ceresoli <luca@lucaceresoli.net>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml
|
||||
F: drivers/power/supply/max77976_charger.c
|
||||
|
||||
MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
|
||||
M: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
|
||||
|
@ -57,6 +57,9 @@ static int mt6323_pwrc_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
pwrc->base = res->start;
|
||||
pwrc->regmap = mt6397_chip->regmap;
|
||||
pwrc->dev = &pdev->dev;
|
||||
|
@ -557,6 +557,18 @@ config CHARGER_MAX77693
|
||||
help
|
||||
Say Y to enable support for the Maxim MAX77693 battery charger.
|
||||
|
||||
config CHARGER_MAX77976
|
||||
tristate "Maxim MAX77976 battery charger driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
The Maxim MAX77976 is a 19 Vin, 5.5A 1-Cell Li+ Battery Charger
|
||||
USB OTG support. It has an I2C interface for configuration.
|
||||
|
||||
Say Y to enable support for the Maxim MAX77976 battery charger.
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called max77976_charger.
|
||||
|
||||
config CHARGER_MAX8997
|
||||
tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
|
||||
depends on MFD_MAX8997 && REGULATOR_MAX8997
|
||||
|
@ -75,6 +75,7 @@ obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
|
||||
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
|
||||
obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX77976) += max77976_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
|
||||
obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o
|
||||
|
@ -160,13 +160,6 @@
|
||||
#define BTEMP_HIGH_TH_57_1 0x02
|
||||
#define BTEMP_HIGH_TH_62 0x03
|
||||
|
||||
/* current is mA */
|
||||
#define USB_0P1A 100
|
||||
#define USB_0P2A 200
|
||||
#define USB_0P3A 300
|
||||
#define USB_0P4A 400
|
||||
#define USB_0P5A 500
|
||||
|
||||
#define LOW_BAT_3P1V 0x20
|
||||
#define LOW_BAT_2P3V 0x00
|
||||
#define LOW_BAT_RESET 0x01
|
||||
@ -203,8 +196,8 @@ enum bup_vch_sel {
|
||||
#define BATT_OVV_TH_3P7 0x00
|
||||
#define BATT_OVV_TH_4P75 0x01
|
||||
|
||||
/* A value to indicate over voltage */
|
||||
#define BATT_OVV_VALUE 4750
|
||||
/* A value to indicate over voltage (microvolts) */
|
||||
#define BATT_OVV_VALUE 4750000
|
||||
|
||||
/* VBUS OVV constants */
|
||||
#define VBUS_OVV_SELECT_MASK 0x78
|
||||
@ -291,16 +284,6 @@ struct ab8500_res_to_temp {
|
||||
int resist;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab8500_v_to_cap - Table for translating voltage to capacity
|
||||
* @voltage: Voltage in mV
|
||||
* @capacity: Capacity in percent
|
||||
*/
|
||||
struct ab8500_v_to_cap {
|
||||
int voltage;
|
||||
int capacity;
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
struct ab8500_fg;
|
||||
|
||||
@ -314,10 +297,9 @@ struct ab8500_fg;
|
||||
* @init_total_time: Total init time during startup
|
||||
* @high_curr_time: Time current has to be high to go to recovery
|
||||
* @accu_charging: FG accumulation time while charging
|
||||
* @accu_high_curr: FG accumulation time in high current mode
|
||||
* @high_curr_threshold: High current threshold, in mA
|
||||
* @lowbat_threshold: Low battery threshold, in mV
|
||||
* @overbat_threshold: Over battery threshold, in mV
|
||||
* @accu_high_curr_ua: FG accumulation time in high current mode
|
||||
* @high_curr_threshold_ua: High current threshold, in uA
|
||||
* @lowbat_threshold_uv: Low battery threshold, in uV
|
||||
* @battok_falling_th_sel0 Threshold in mV for battOk signal sel0
|
||||
* Resolution in 50 mV step.
|
||||
* @battok_raising_th_sel1 Threshold in mV for battOk signal sel1
|
||||
@ -342,9 +324,8 @@ struct ab8500_fg_parameters {
|
||||
int high_curr_time;
|
||||
int accu_charging;
|
||||
int accu_high_curr;
|
||||
int high_curr_threshold;
|
||||
int lowbat_threshold;
|
||||
int overbat_threshold;
|
||||
int high_curr_threshold_ua;
|
||||
int lowbat_threshold_uv;
|
||||
int battok_falling_th_sel0;
|
||||
int battok_raising_th_sel1;
|
||||
int user_cap_limit;
|
||||
@ -359,31 +340,21 @@ struct ab8500_fg_parameters {
|
||||
/**
|
||||
* struct ab8500_charger_maximization - struct used by the board config.
|
||||
* @use_maxi: Enable maximization for this battery type
|
||||
* @maxi_chg_curr: Maximum charger current allowed
|
||||
* @maxi_chg_curr_ua: Maximum charger current allowed in microampere
|
||||
* @maxi_wait_cycles: cycles to wait before setting charger current
|
||||
* @charger_curr_step delta between two charger current settings (mA)
|
||||
* @charger_curr_step_ua: delta between two charger current settings (uA)
|
||||
*/
|
||||
struct ab8500_maxim_parameters {
|
||||
bool ena_maxi;
|
||||
int chg_curr;
|
||||
int chg_curr_ua;
|
||||
int wait_cycles;
|
||||
int charger_curr_step;
|
||||
int charger_curr_step_ua;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab8500_battery_type - different batteries supported
|
||||
* @name: battery technology
|
||||
* @resis_high: battery upper resistance limit
|
||||
* @resis_low: battery lower resistance limit
|
||||
* @charge_full_design: Maximum battery capacity in mAh
|
||||
* @nominal_voltage: Nominal voltage of the battery in mV
|
||||
* @termination_vol: max voltage upto which battery can be charged
|
||||
* @termination_curr battery charging termination current in mA
|
||||
* @recharge_cap battery capacity limit that will trigger a new
|
||||
* full charging cycle in the case where maintenan-
|
||||
* -ce charging has been disabled
|
||||
* @normal_cur_lvl: charger current in normal state in mA
|
||||
* @normal_vol_lvl: charger voltage in normal state in mV
|
||||
* @maint_a_cur_lvl: charger current in maintenance A state in mA
|
||||
* @maint_a_vol_lvl: charger voltage in maintenance A state in mV
|
||||
* @maint_a_chg_timer_h: charge time in maintenance A state
|
||||
@ -392,25 +363,12 @@ struct ab8500_maxim_parameters {
|
||||
* @maint_b_chg_timer_h: charge time in maintenance B state
|
||||
* @low_high_cur_lvl: charger current in temp low/high state in mA
|
||||
* @low_high_vol_lvl: charger voltage in temp low/high state in mV'
|
||||
* @battery_resistance: battery inner resistance in mOhm.
|
||||
* @n_r_t_tbl_elements: number of elements in r_to_t_tbl
|
||||
* @r_to_t_tbl: table containing resistance to temp points
|
||||
* @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl
|
||||
* @v_to_cap_tbl: Voltage to capacity (in %) table
|
||||
* @n_batres_tbl_elements number of elements in the batres_tbl
|
||||
* @batres_tbl battery internal resistance vs temperature table
|
||||
*/
|
||||
struct ab8500_battery_type {
|
||||
int name;
|
||||
int resis_high;
|
||||
int resis_low;
|
||||
int charge_full_design;
|
||||
int nominal_voltage;
|
||||
int termination_vol;
|
||||
int termination_curr;
|
||||
int recharge_cap;
|
||||
int normal_cur_lvl;
|
||||
int normal_vol_lvl;
|
||||
int maint_a_cur_lvl;
|
||||
int maint_a_vol_lvl;
|
||||
int maint_a_chg_timer_h;
|
||||
@ -419,13 +377,8 @@ struct ab8500_battery_type {
|
||||
int maint_b_chg_timer_h;
|
||||
int low_high_cur_lvl;
|
||||
int low_high_vol_lvl;
|
||||
int battery_resistance;
|
||||
int n_temp_tbl_elements;
|
||||
const struct ab8500_res_to_temp *r_to_t_tbl;
|
||||
int n_v_cap_tbl_elements;
|
||||
const struct ab8500_v_to_cap *v_to_cap_tbl;
|
||||
int n_batres_tbl_elements;
|
||||
const struct batres_vs_temp *batres_tbl;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -446,24 +399,21 @@ struct ab8500_bm_capacity_levels {
|
||||
|
||||
/**
|
||||
* struct ab8500_bm_charger_parameters - Charger specific parameters
|
||||
* @usb_volt_max: maximum allowed USB charger voltage in mV
|
||||
* @usb_curr_max: maximum allowed USB charger current in mA
|
||||
* @ac_volt_max: maximum allowed AC charger voltage in mV
|
||||
* @ac_curr_max: maximum allowed AC charger current in mA
|
||||
* @usb_volt_max_uv: maximum allowed USB charger voltage in uV
|
||||
* @usb_curr_max_ua: maximum allowed USB charger current in uA
|
||||
* @ac_volt_max_uv: maximum allowed AC charger voltage in uV
|
||||
* @ac_curr_max_ua: maximum allowed AC charger current in uA
|
||||
*/
|
||||
struct ab8500_bm_charger_parameters {
|
||||
int usb_volt_max;
|
||||
int usb_curr_max;
|
||||
int ac_volt_max;
|
||||
int ac_curr_max;
|
||||
int usb_volt_max_uv;
|
||||
int usb_curr_max_ua;
|
||||
int ac_volt_max_uv;
|
||||
int ac_curr_max_ua;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab8500_bm_data - ab8500 battery management data
|
||||
* @temp_under under this temp, charging is stopped
|
||||
* @temp_low between this temp and temp_under charging is reduced
|
||||
* @temp_high between this temp and temp_over charging is reduced
|
||||
* @temp_over over this temp, charging is stopped
|
||||
* @bi battery info from device tree
|
||||
* @temp_now present battery temperature
|
||||
* @temp_interval_chg temperature measurement interval in s when charging
|
||||
* @temp_interval_nochg temperature measurement interval in s when not charging
|
||||
@ -478,16 +428,10 @@ struct ab8500_bm_charger_parameters {
|
||||
* @enable_overshoot flag to enable VBAT overshoot control
|
||||
* @auto_trig flag to enable auto adc trigger
|
||||
* @fg_res resistance of FG resistor in 0.1mOhm
|
||||
* @n_btypes number of elements in array bat_type
|
||||
* @batt_id index of the identified battery in array bat_type
|
||||
* @interval_charging charge alg cycle period time when charging (sec)
|
||||
* @interval_not_charging charge alg cycle period time when not charging (sec)
|
||||
* @temp_hysteresis temperature hysteresis
|
||||
* @gnd_lift_resistance Battery ground to phone ground resistance (mOhm)
|
||||
* @n_chg_out_curr number of elements in array chg_output_curr
|
||||
* @n_chg_in_curr number of elements in array chg_input_curr
|
||||
* @chg_output_curr charger output current level map
|
||||
* @chg_input_curr charger input current level map
|
||||
* @maxi maximization parameters
|
||||
* @cap_levels capacity in percent for the different capacity levels
|
||||
* @bat_type table of supported battery types
|
||||
@ -495,10 +439,7 @@ struct ab8500_bm_charger_parameters {
|
||||
* @fg_params fuel gauge parameters
|
||||
*/
|
||||
struct ab8500_bm_data {
|
||||
int temp_under;
|
||||
int temp_low;
|
||||
int temp_high;
|
||||
int temp_over;
|
||||
struct power_supply_battery_info *bi;
|
||||
int temp_now;
|
||||
int temp_interval_chg;
|
||||
int temp_interval_nochg;
|
||||
@ -513,16 +454,10 @@ struct ab8500_bm_data {
|
||||
bool auto_trig;
|
||||
enum ab8500_adc_therm adc_therm;
|
||||
int fg_res;
|
||||
int n_btypes;
|
||||
int batt_id;
|
||||
int interval_charging;
|
||||
int interval_not_charging;
|
||||
int temp_hysteresis;
|
||||
int gnd_lift_resistance;
|
||||
int n_chg_out_curr;
|
||||
int n_chg_in_curr;
|
||||
int *chg_output_curr;
|
||||
int *chg_input_curr;
|
||||
const struct ab8500_maxim_parameters *maxi;
|
||||
const struct ab8500_bm_capacity_levels *cap_levels;
|
||||
struct ab8500_battery_type *bat_type;
|
||||
@ -547,17 +482,6 @@ struct res_to_temp {
|
||||
int resist;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batres_vs_temp - defines one point in a temp vs battery internal
|
||||
* resistance curve.
|
||||
* @temp: battery pack temperature in Celsius
|
||||
* @resist: battery internal reistance in mOhm
|
||||
*/
|
||||
struct batres_vs_temp {
|
||||
int temp;
|
||||
int resist;
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
struct ab8500_fg;
|
||||
|
||||
@ -570,9 +494,10 @@ int ab8500_fg_inst_curr_start(struct ab8500_fg *di);
|
||||
int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res);
|
||||
int ab8500_fg_inst_curr_started(struct ab8500_fg *di);
|
||||
int ab8500_fg_inst_curr_done(struct ab8500_fg *di);
|
||||
int ab8500_bm_of_probe(struct device *dev,
|
||||
struct device_node *np,
|
||||
int ab8500_bm_of_probe(struct power_supply *psy,
|
||||
struct ab8500_bm_data *bm);
|
||||
void ab8500_bm_of_remove(struct power_supply *psy,
|
||||
struct ab8500_bm_data *bm);
|
||||
|
||||
extern struct platform_driver ab8500_fg_driver;
|
||||
extern struct platform_driver ab8500_btemp_driver;
|
||||
|
@ -31,16 +31,16 @@ struct ux500_charger_ops {
|
||||
* struct ux500_charger - power supply ux500 charger sub class
|
||||
* @psy power supply base class
|
||||
* @ops ux500 charger operations
|
||||
* @max_out_volt maximum output charger voltage in mV
|
||||
* @max_out_curr maximum output charger current in mA
|
||||
* @max_out_volt_uv maximum output charger voltage in uV
|
||||
* @max_out_curr_ua maximum output charger current in uA
|
||||
* @enabled indicates if this charger is used or not
|
||||
* @external external charger unit (pm2xxx)
|
||||
*/
|
||||
struct ux500_charger {
|
||||
struct power_supply *psy;
|
||||
struct ux500_charger_ops ops;
|
||||
int max_out_volt;
|
||||
int max_out_curr;
|
||||
int max_out_volt_uv;
|
||||
int max_out_curr_ua;
|
||||
int wdt_refresh;
|
||||
bool enabled;
|
||||
bool external;
|
||||
|
@ -5,127 +5,42 @@
|
||||
|
||||
#include "ab8500-bm.h"
|
||||
|
||||
/*
|
||||
* These are the defined batteries that uses a NTC and ID resistor placed
|
||||
* inside of the battery pack.
|
||||
* Note that the res_to_temp table must be strictly sorted by falling resistance
|
||||
* values to work.
|
||||
*/
|
||||
const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = {
|
||||
{-5, 53407},
|
||||
{ 0, 48594},
|
||||
{ 5, 43804},
|
||||
{10, 39188},
|
||||
{15, 34870},
|
||||
{20, 30933},
|
||||
{25, 27422},
|
||||
{30, 24347},
|
||||
{35, 21694},
|
||||
{40, 19431},
|
||||
{45, 17517},
|
||||
{50, 15908},
|
||||
{55, 14561},
|
||||
{60, 13437},
|
||||
{65, 12500},
|
||||
};
|
||||
EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor);
|
||||
/* Default: under this temperature, charging is stopped */
|
||||
#define AB8500_TEMP_UNDER 3
|
||||
/* Default: between this temp and AB8500_TEMP_UNDER charging is reduced */
|
||||
#define AB8500_TEMP_LOW 8
|
||||
/* Default: between this temp and AB8500_TEMP_OVER charging is reduced */
|
||||
#define AB8500_TEMP_HIGH 43
|
||||
/* Default: over this temp, charging is stopped */
|
||||
#define AB8500_TEMP_OVER 48
|
||||
/* Default: temperature hysteresis */
|
||||
#define AB8500_TEMP_HYSTERESIS 3
|
||||
|
||||
const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor);
|
||||
EXPORT_SYMBOL(ab8500_temp_tbl_a_size);
|
||||
|
||||
const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = {
|
||||
{-5, 200000},
|
||||
{ 0, 159024},
|
||||
{ 5, 151921},
|
||||
{10, 144300},
|
||||
{15, 136424},
|
||||
{20, 128565},
|
||||
{25, 120978},
|
||||
{30, 113875},
|
||||
{35, 107397},
|
||||
{40, 101629},
|
||||
{45, 96592},
|
||||
{50, 92253},
|
||||
{55, 88569},
|
||||
{60, 85461},
|
||||
{65, 82869},
|
||||
};
|
||||
EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor);
|
||||
|
||||
const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor);
|
||||
EXPORT_SYMBOL(ab8500_temp_tbl_b_size);
|
||||
|
||||
static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = {
|
||||
{4171, 100},
|
||||
{4114, 95},
|
||||
{4009, 83},
|
||||
{3947, 74},
|
||||
{3907, 67},
|
||||
{3863, 59},
|
||||
{3830, 56},
|
||||
{3813, 53},
|
||||
{3791, 46},
|
||||
{3771, 33},
|
||||
{3754, 25},
|
||||
{3735, 20},
|
||||
{3717, 17},
|
||||
{3681, 13},
|
||||
{3664, 8},
|
||||
{3651, 6},
|
||||
{3635, 5},
|
||||
{3560, 3},
|
||||
{3408, 1},
|
||||
{3247, 0},
|
||||
};
|
||||
|
||||
static const struct ab8500_v_to_cap cap_tbl_b_thermistor[] = {
|
||||
{4161, 100},
|
||||
{4124, 98},
|
||||
{4044, 90},
|
||||
{4003, 85},
|
||||
{3966, 80},
|
||||
{3933, 75},
|
||||
{3888, 67},
|
||||
{3849, 60},
|
||||
{3813, 55},
|
||||
{3787, 47},
|
||||
{3772, 30},
|
||||
{3751, 25},
|
||||
{3718, 20},
|
||||
{3681, 16},
|
||||
{3660, 14},
|
||||
{3589, 10},
|
||||
{3546, 7},
|
||||
{3495, 4},
|
||||
{3404, 2},
|
||||
{3250, 0},
|
||||
};
|
||||
|
||||
static const struct ab8500_v_to_cap cap_tbl[] = {
|
||||
{4186, 100},
|
||||
{4163, 99},
|
||||
{4114, 95},
|
||||
{4068, 90},
|
||||
{3990, 80},
|
||||
{3926, 70},
|
||||
{3898, 65},
|
||||
{3866, 60},
|
||||
{3833, 55},
|
||||
{3812, 50},
|
||||
{3787, 40},
|
||||
{3768, 30},
|
||||
{3747, 25},
|
||||
{3730, 20},
|
||||
{3705, 15},
|
||||
{3699, 14},
|
||||
{3684, 12},
|
||||
{3672, 9},
|
||||
{3657, 7},
|
||||
{3638, 6},
|
||||
{3556, 4},
|
||||
{3424, 2},
|
||||
{3317, 1},
|
||||
{3094, 0},
|
||||
static struct power_supply_battery_ocv_table ocv_cap_tbl[] = {
|
||||
{ .ocv = 4186000, .capacity = 100},
|
||||
{ .ocv = 4163000, .capacity = 99},
|
||||
{ .ocv = 4114000, .capacity = 95},
|
||||
{ .ocv = 4068000, .capacity = 90},
|
||||
{ .ocv = 3990000, .capacity = 80},
|
||||
{ .ocv = 3926000, .capacity = 70},
|
||||
{ .ocv = 3898000, .capacity = 65},
|
||||
{ .ocv = 3866000, .capacity = 60},
|
||||
{ .ocv = 3833000, .capacity = 55},
|
||||
{ .ocv = 3812000, .capacity = 50},
|
||||
{ .ocv = 3787000, .capacity = 40},
|
||||
{ .ocv = 3768000, .capacity = 30},
|
||||
{ .ocv = 3747000, .capacity = 25},
|
||||
{ .ocv = 3730000, .capacity = 20},
|
||||
{ .ocv = 3705000, .capacity = 15},
|
||||
{ .ocv = 3699000, .capacity = 14},
|
||||
{ .ocv = 3684000, .capacity = 12},
|
||||
{ .ocv = 3672000, .capacity = 9},
|
||||
{ .ocv = 3657000, .capacity = 7},
|
||||
{ .ocv = 3638000, .capacity = 6},
|
||||
{ .ocv = 3556000, .capacity = 4},
|
||||
{ .ocv = 3424000, .capacity = 2},
|
||||
{ .ocv = 3317000, .capacity = 1},
|
||||
{ .ocv = 3094000, .capacity = 0},
|
||||
};
|
||||
|
||||
/*
|
||||
@ -152,244 +67,33 @@ static const struct ab8500_res_to_temp temp_tbl[] = {
|
||||
|
||||
/*
|
||||
* Note that the batres_vs_temp table must be strictly sorted by falling
|
||||
* temperature values to work.
|
||||
* temperature values to work. Factory resistance is 300 mOhm and the
|
||||
* resistance values to the right are percentages of 300 mOhm.
|
||||
*/
|
||||
static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
|
||||
{ 40, 120},
|
||||
{ 30, 135},
|
||||
{ 20, 165},
|
||||
{ 10, 230},
|
||||
{ 00, 325},
|
||||
{-10, 445},
|
||||
{-20, 595},
|
||||
static struct power_supply_resistance_temp_table temp_to_batres_tbl_thermistor[] = {
|
||||
{ .temp = 40, .resistance = 40 /* 120 mOhm */ },
|
||||
{ .temp = 30, .resistance = 45 /* 135 mOhm */ },
|
||||
{ .temp = 20, .resistance = 55 /* 165 mOhm */ },
|
||||
{ .temp = 10, .resistance = 77 /* 230 mOhm */ },
|
||||
{ .temp = 00, .resistance = 108 /* 325 mOhm */ },
|
||||
{ .temp = -10, .resistance = 158 /* 445 mOhm */ },
|
||||
{ .temp = -20, .resistance = 198 /* 595 mOhm */ },
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that the batres_vs_temp table must be strictly sorted by falling
|
||||
* temperature values to work.
|
||||
*/
|
||||
static const struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
|
||||
{ 60, 300},
|
||||
{ 30, 300},
|
||||
{ 20, 300},
|
||||
{ 10, 300},
|
||||
{ 00, 300},
|
||||
{-10, 300},
|
||||
{-20, 300},
|
||||
};
|
||||
|
||||
/* battery resistance table for LI ION 9100 battery */
|
||||
static const struct batres_vs_temp temp_to_batres_tbl_9100[] = {
|
||||
{ 60, 180},
|
||||
{ 30, 180},
|
||||
{ 20, 180},
|
||||
{ 10, 180},
|
||||
{ 00, 180},
|
||||
{-10, 180},
|
||||
{-20, 180},
|
||||
};
|
||||
|
||||
static struct ab8500_battery_type bat_type_thermistor[] = {
|
||||
[BATTERY_UNKNOWN] = {
|
||||
/* First element always represent the UNKNOWN battery */
|
||||
.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
|
||||
.resis_high = 0,
|
||||
.resis_low = 0,
|
||||
.battery_resistance = 300,
|
||||
.charge_full_design = 612,
|
||||
.nominal_voltage = 3700,
|
||||
.termination_vol = 4050,
|
||||
.termination_curr = 200,
|
||||
.recharge_cap = 95,
|
||||
.normal_cur_lvl = 400,
|
||||
.normal_vol_lvl = 4100,
|
||||
.maint_a_cur_lvl = 400,
|
||||
.maint_a_vol_lvl = 4050,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 400,
|
||||
.maint_b_vol_lvl = 4000,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
|
||||
.r_to_t_tbl = temp_tbl,
|
||||
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
||||
.v_to_cap_tbl = cap_tbl,
|
||||
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
||||
.batres_tbl = temp_to_batres_tbl_thermistor,
|
||||
},
|
||||
{
|
||||
.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
||||
.resis_high = 53407,
|
||||
.resis_low = 12500,
|
||||
.battery_resistance = 300,
|
||||
.charge_full_design = 900,
|
||||
.nominal_voltage = 3600,
|
||||
.termination_vol = 4150,
|
||||
.termination_curr = 80,
|
||||
.recharge_cap = 95,
|
||||
.normal_cur_lvl = 700,
|
||||
.normal_vol_lvl = 4200,
|
||||
.maint_a_cur_lvl = 600,
|
||||
.maint_a_vol_lvl = 4150,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 600,
|
||||
.maint_b_vol_lvl = 4100,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor),
|
||||
.r_to_t_tbl = ab8500_temp_tbl_a_thermistor,
|
||||
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_a_thermistor),
|
||||
.v_to_cap_tbl = cap_tbl_a_thermistor,
|
||||
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
||||
.batres_tbl = temp_to_batres_tbl_thermistor,
|
||||
|
||||
},
|
||||
{
|
||||
.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
||||
.resis_high = 200000,
|
||||
.resis_low = 82869,
|
||||
.battery_resistance = 300,
|
||||
.charge_full_design = 900,
|
||||
.nominal_voltage = 3600,
|
||||
.termination_vol = 4150,
|
||||
.termination_curr = 80,
|
||||
.recharge_cap = 95,
|
||||
.normal_cur_lvl = 700,
|
||||
.normal_vol_lvl = 4200,
|
||||
.maint_a_cur_lvl = 600,
|
||||
.maint_a_vol_lvl = 4150,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 600,
|
||||
.maint_b_vol_lvl = 4100,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor),
|
||||
.r_to_t_tbl = ab8500_temp_tbl_b_thermistor,
|
||||
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_b_thermistor),
|
||||
.v_to_cap_tbl = cap_tbl_b_thermistor,
|
||||
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
||||
.batres_tbl = temp_to_batres_tbl_thermistor,
|
||||
},
|
||||
};
|
||||
|
||||
static struct ab8500_battery_type bat_type_ext_thermistor[] = {
|
||||
[BATTERY_UNKNOWN] = {
|
||||
/* First element always represent the UNKNOWN battery */
|
||||
.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
|
||||
.resis_high = 0,
|
||||
.resis_low = 0,
|
||||
.battery_resistance = 300,
|
||||
.charge_full_design = 612,
|
||||
.nominal_voltage = 3700,
|
||||
.termination_vol = 4050,
|
||||
.termination_curr = 200,
|
||||
.recharge_cap = 95,
|
||||
.normal_cur_lvl = 400,
|
||||
.normal_vol_lvl = 4100,
|
||||
.maint_a_cur_lvl = 400,
|
||||
.maint_a_vol_lvl = 4050,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 400,
|
||||
.maint_b_vol_lvl = 4000,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
|
||||
.r_to_t_tbl = temp_tbl,
|
||||
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
||||
.v_to_cap_tbl = cap_tbl,
|
||||
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
||||
.batres_tbl = temp_to_batres_tbl_thermistor,
|
||||
},
|
||||
/*
|
||||
* These are the batteries that doesn't have an internal NTC resistor to measure
|
||||
* its temperature. The temperature in this case is measure with a NTC placed
|
||||
* near the battery but on the PCB.
|
||||
*/
|
||||
{
|
||||
.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
||||
.resis_high = 76000,
|
||||
.resis_low = 53000,
|
||||
.battery_resistance = 300,
|
||||
.charge_full_design = 900,
|
||||
.nominal_voltage = 3700,
|
||||
.termination_vol = 4150,
|
||||
.termination_curr = 100,
|
||||
.recharge_cap = 95,
|
||||
.normal_cur_lvl = 700,
|
||||
.normal_vol_lvl = 4200,
|
||||
.maint_a_cur_lvl = 600,
|
||||
.maint_a_vol_lvl = 4150,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 600,
|
||||
.maint_b_vol_lvl = 4100,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
|
||||
.r_to_t_tbl = temp_tbl,
|
||||
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
||||
.v_to_cap_tbl = cap_tbl,
|
||||
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
||||
.batres_tbl = temp_to_batres_tbl_thermistor,
|
||||
},
|
||||
{
|
||||
.name = POWER_SUPPLY_TECHNOLOGY_LION,
|
||||
.resis_high = 30000,
|
||||
.resis_low = 10000,
|
||||
.battery_resistance = 300,
|
||||
.charge_full_design = 950,
|
||||
.nominal_voltage = 3700,
|
||||
.termination_vol = 4150,
|
||||
.termination_curr = 100,
|
||||
.recharge_cap = 95,
|
||||
.normal_cur_lvl = 700,
|
||||
.normal_vol_lvl = 4200,
|
||||
.maint_a_cur_lvl = 600,
|
||||
.maint_a_vol_lvl = 4150,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 600,
|
||||
.maint_b_vol_lvl = 4100,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
|
||||
.r_to_t_tbl = temp_tbl,
|
||||
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
||||
.v_to_cap_tbl = cap_tbl,
|
||||
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
||||
.batres_tbl = temp_to_batres_tbl_thermistor,
|
||||
},
|
||||
{
|
||||
.name = POWER_SUPPLY_TECHNOLOGY_LION,
|
||||
.resis_high = 95000,
|
||||
.resis_low = 76001,
|
||||
.battery_resistance = 300,
|
||||
.charge_full_design = 950,
|
||||
.nominal_voltage = 3700,
|
||||
.termination_vol = 4150,
|
||||
.termination_curr = 100,
|
||||
.recharge_cap = 95,
|
||||
.normal_cur_lvl = 700,
|
||||
.normal_vol_lvl = 4200,
|
||||
.maint_a_cur_lvl = 600,
|
||||
.maint_a_vol_lvl = 4150,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 600,
|
||||
.maint_b_vol_lvl = 4100,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
|
||||
.r_to_t_tbl = temp_tbl,
|
||||
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
||||
.v_to_cap_tbl = cap_tbl,
|
||||
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
||||
.batres_tbl = temp_to_batres_tbl_thermistor,
|
||||
},
|
||||
/* Default battery type for reference designs is the unknown type */
|
||||
static struct ab8500_battery_type bat_type_thermistor_unknown = {
|
||||
.resis_high = 0,
|
||||
.resis_low = 0,
|
||||
.maint_a_cur_lvl = 400,
|
||||
.maint_a_vol_lvl = 4050,
|
||||
.maint_a_chg_timer_h = 60,
|
||||
.maint_b_cur_lvl = 400,
|
||||
.maint_b_vol_lvl = 4000,
|
||||
.maint_b_chg_timer_h = 200,
|
||||
.low_high_cur_lvl = 300,
|
||||
.low_high_vol_lvl = 4000,
|
||||
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
|
||||
.r_to_t_tbl = temp_tbl,
|
||||
};
|
||||
|
||||
static const struct ab8500_bm_capacity_levels cap_levels = {
|
||||
@ -409,8 +113,8 @@ static const struct ab8500_fg_parameters fg = {
|
||||
.high_curr_time = 60,
|
||||
.accu_charging = 30,
|
||||
.accu_high_curr = 30,
|
||||
.high_curr_threshold = 50,
|
||||
.lowbat_threshold = 3100,
|
||||
.high_curr_threshold_ua = 50000,
|
||||
.lowbat_threshold_uv = 3100000,
|
||||
.battok_falling_th_sel0 = 2860,
|
||||
.battok_raising_th_sel1 = 2860,
|
||||
.maint_thres = 95,
|
||||
@ -424,41 +128,20 @@ static const struct ab8500_fg_parameters fg = {
|
||||
|
||||
static const struct ab8500_maxim_parameters ab8500_maxi_params = {
|
||||
.ena_maxi = true,
|
||||
.chg_curr = 910,
|
||||
.chg_curr_ua = 910000,
|
||||
.wait_cycles = 10,
|
||||
.charger_curr_step = 100,
|
||||
.charger_curr_step_ua = 100000,
|
||||
};
|
||||
|
||||
static const struct ab8500_bm_charger_parameters chg = {
|
||||
.usb_volt_max = 5500,
|
||||
.usb_curr_max = 1500,
|
||||
.ac_volt_max = 7500,
|
||||
.ac_curr_max = 1500,
|
||||
};
|
||||
|
||||
/*
|
||||
* This array maps the raw hex value to charger output current used by the
|
||||
* AB8500 values
|
||||
*/
|
||||
static int ab8500_charge_output_curr_map[] = {
|
||||
100, 200, 300, 400, 500, 600, 700, 800,
|
||||
900, 1000, 1100, 1200, 1300, 1400, 1500, 1500,
|
||||
};
|
||||
|
||||
/*
|
||||
* This array maps the raw hex value to charger input current used by the
|
||||
* AB8500 values
|
||||
*/
|
||||
static int ab8500_charge_input_curr_map[] = {
|
||||
50, 98, 193, 290, 380, 450, 500, 600,
|
||||
700, 800, 900, 1000, 1100, 1300, 1400, 1500,
|
||||
.usb_volt_max_uv = 5500000,
|
||||
.usb_curr_max_ua = 1500000,
|
||||
.ac_volt_max_uv = 7500000,
|
||||
.ac_curr_max_ua = 1500000,
|
||||
};
|
||||
|
||||
/* This is referenced directly in the charger code */
|
||||
struct ab8500_bm_data ab8500_bm_data = {
|
||||
.temp_under = 3,
|
||||
.temp_low = 8,
|
||||
.temp_high = 43,
|
||||
.temp_over = 48,
|
||||
.main_safety_tmr_h = 4,
|
||||
.temp_interval_chg = 20,
|
||||
.temp_interval_nochg = 120,
|
||||
@ -472,71 +155,91 @@ struct ab8500_bm_data ab8500_bm_data = {
|
||||
.enable_overshoot = false,
|
||||
.fg_res = 100,
|
||||
.cap_levels = &cap_levels,
|
||||
.bat_type = bat_type_thermistor,
|
||||
.n_btypes = ARRAY_SIZE(bat_type_thermistor),
|
||||
.batt_id = 0,
|
||||
.bat_type = &bat_type_thermistor_unknown,
|
||||
.interval_charging = 5,
|
||||
.interval_not_charging = 120,
|
||||
.temp_hysteresis = 3,
|
||||
.gnd_lift_resistance = 34,
|
||||
.chg_output_curr = ab8500_charge_output_curr_map,
|
||||
.n_chg_out_curr = ARRAY_SIZE(ab8500_charge_output_curr_map),
|
||||
.maxi = &ab8500_maxi_params,
|
||||
.chg_params = &chg,
|
||||
.fg_params = &fg,
|
||||
.chg_input_curr = ab8500_charge_input_curr_map,
|
||||
.n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map),
|
||||
};
|
||||
|
||||
int ab8500_bm_of_probe(struct device *dev,
|
||||
struct device_node *np,
|
||||
int ab8500_bm_of_probe(struct power_supply *psy,
|
||||
struct ab8500_bm_data *bm)
|
||||
{
|
||||
const struct batres_vs_temp *tmp_batres_tbl;
|
||||
struct device_node *battery_node;
|
||||
const char *btech;
|
||||
int i;
|
||||
struct power_supply_battery_info *bi;
|
||||
struct device *dev = &psy->dev;
|
||||
int ret;
|
||||
|
||||
battery_node = of_parse_phandle(np, "monitored-battery", 0);
|
||||
if (!battery_node) {
|
||||
dev_err(dev, "battery node or reference missing\n");
|
||||
return -EINVAL;
|
||||
ret = power_supply_get_battery_info(psy, &bm->bi);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot retrieve battery info\n");
|
||||
return ret;
|
||||
}
|
||||
bi = bm->bi;
|
||||
|
||||
/* Fill in defaults for any data missing from the device tree */
|
||||
if (bi->charge_full_design_uah < 0)
|
||||
/* The default capacity is 612 mAh for unknown batteries */
|
||||
bi->charge_full_design_uah = 612000;
|
||||
|
||||
/*
|
||||
* All of these voltages need to be specified or we will simply
|
||||
* fall back to safe defaults.
|
||||
*/
|
||||
if ((bi->voltage_min_design_uv < 0) ||
|
||||
(bi->voltage_max_design_uv < 0) ||
|
||||
(bi->overvoltage_limit_uv < 0)) {
|
||||
/* Nominal voltage is 3.7V for unknown batteries */
|
||||
bi->voltage_min_design_uv = 3700000;
|
||||
bi->voltage_max_design_uv = 3700000;
|
||||
/* Termination voltage (overcharge limit) 4.05V */
|
||||
bi->overvoltage_limit_uv = 4050000;
|
||||
}
|
||||
|
||||
btech = of_get_property(battery_node, "stericsson,battery-type", NULL);
|
||||
if (!btech) {
|
||||
dev_warn(dev, "missing property battery-name/type\n");
|
||||
of_node_put(battery_node);
|
||||
return -EINVAL;
|
||||
if (bi->constant_charge_current_max_ua < 0)
|
||||
bi->constant_charge_current_max_ua = 400000;
|
||||
|
||||
if (bi->constant_charge_voltage_max_uv < 0)
|
||||
bi->constant_charge_voltage_max_uv = 4100000;
|
||||
|
||||
if (bi->charge_term_current_ua)
|
||||
/* Charging stops when we drop below this current */
|
||||
bi->charge_term_current_ua = 200000;
|
||||
|
||||
/*
|
||||
* Internal resistance and factory resistance are tightly coupled
|
||||
* so both MUST be defined or we fall back to defaults.
|
||||
*/
|
||||
if ((bi->factory_internal_resistance_uohm < 0) ||
|
||||
!bi->resist_table) {
|
||||
bi->factory_internal_resistance_uohm = 300000;
|
||||
bi->resist_table = temp_to_batres_tbl_thermistor;
|
||||
bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor);
|
||||
}
|
||||
|
||||
if (strncmp(btech, "LION", 4) == 0) {
|
||||
bm->no_maintenance = true;
|
||||
bm->chg_unknown_bat = true;
|
||||
bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
|
||||
bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150;
|
||||
bm->bat_type[BATTERY_UNKNOWN].recharge_cap = 95;
|
||||
bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520;
|
||||
bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200;
|
||||
if (!bi->ocv_table[0]) {
|
||||
/* Default capacity table at say 25 degrees Celsius */
|
||||
bi->ocv_temp[0] = 25;
|
||||
bi->ocv_table[0] = ocv_cap_tbl;
|
||||
bi->ocv_table_size[0] = ARRAY_SIZE(ocv_cap_tbl);
|
||||
}
|
||||
|
||||
if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) {
|
||||
if (strncmp(btech, "LION", 4) == 0)
|
||||
tmp_batres_tbl = temp_to_batres_tbl_9100;
|
||||
else
|
||||
tmp_batres_tbl = temp_to_batres_tbl_thermistor;
|
||||
} else {
|
||||
bm->n_btypes = 4;
|
||||
bm->bat_type = bat_type_ext_thermistor;
|
||||
bm->adc_therm = AB8500_ADC_THERM_BATTEMP;
|
||||
tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor;
|
||||
}
|
||||
|
||||
/* select the battery resolution table */
|
||||
for (i = 0; i < bm->n_btypes; ++i)
|
||||
bm->bat_type[i].batres_tbl = tmp_batres_tbl;
|
||||
|
||||
of_node_put(battery_node);
|
||||
if (bi->temp_min == INT_MIN)
|
||||
bi->temp_min = AB8500_TEMP_UNDER;
|
||||
if (bi->temp_max == INT_MAX)
|
||||
bi->temp_max = AB8500_TEMP_OVER;
|
||||
if (bi->temp_alert_min == INT_MIN)
|
||||
bi->temp_alert_min = AB8500_TEMP_LOW;
|
||||
if (bi->temp_alert_max == INT_MAX)
|
||||
bi->temp_alert_max = AB8500_TEMP_HIGH;
|
||||
bm->temp_hysteresis = AB8500_TEMP_HYSTERESIS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ab8500_bm_of_remove(struct power_supply *psy,
|
||||
struct ab8500_bm_data *bm)
|
||||
{
|
||||
power_supply_put_battery_info(psy, bm->bi);
|
||||
}
|
||||
|
@ -451,15 +451,13 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
|
||||
*/
|
||||
static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
|
||||
{
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
int temp, ret;
|
||||
static int prev;
|
||||
int rbat, rntc, vntc;
|
||||
u8 id;
|
||||
|
||||
id = di->bm->batt_id;
|
||||
|
||||
if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL &&
|
||||
id != BATTERY_UNKNOWN) {
|
||||
if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) &&
|
||||
(bi && (bi->technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN))) {
|
||||
|
||||
rbat = ab8500_btemp_get_batctrl_res(di);
|
||||
if (rbat < 0) {
|
||||
@ -473,8 +471,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
|
||||
}
|
||||
|
||||
temp = ab8500_btemp_res_to_temp(di,
|
||||
di->bm->bat_type[id].r_to_t_tbl,
|
||||
di->bm->bat_type[id].n_temp_tbl_elements, rbat);
|
||||
di->bm->bat_type->r_to_t_tbl,
|
||||
di->bm->bat_type->n_temp_tbl_elements, rbat);
|
||||
} else {
|
||||
ret = iio_read_channel_processed(di->btemp_ball, &vntc);
|
||||
if (ret < 0) {
|
||||
@ -490,8 +488,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
|
||||
rntc = 230000 * vntc / (VTVOUT_V - vntc);
|
||||
|
||||
temp = ab8500_btemp_res_to_temp(di,
|
||||
di->bm->bat_type[id].r_to_t_tbl,
|
||||
di->bm->bat_type[id].n_temp_tbl_elements, rntc);
|
||||
di->bm->bat_type->r_to_t_tbl,
|
||||
di->bm->bat_type->n_temp_tbl_elements, rntc);
|
||||
prev = temp;
|
||||
}
|
||||
dev_dbg(di->dev, "Battery temperature is %d\n", temp);
|
||||
@ -512,7 +510,6 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
|
||||
u8 i;
|
||||
|
||||
di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
|
||||
di->bm->batt_id = BATTERY_UNKNOWN;
|
||||
|
||||
res = ab8500_btemp_get_batctrl_res(di);
|
||||
if (res < 0) {
|
||||
@ -520,40 +517,37 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* BATTERY_UNKNOWN is defined on position 0, skip it! */
|
||||
for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) {
|
||||
if ((res <= di->bm->bat_type[i].resis_high) &&
|
||||
(res >= di->bm->bat_type[i].resis_low)) {
|
||||
dev_dbg(di->dev, "Battery detected on %s"
|
||||
" low %d < res %d < high: %d"
|
||||
" index: %d\n",
|
||||
di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ?
|
||||
"BATCTRL" : "BATTEMP",
|
||||
di->bm->bat_type[i].resis_low, res,
|
||||
di->bm->bat_type[i].resis_high, i);
|
||||
|
||||
di->bm->batt_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (di->bm->batt_id == BATTERY_UNKNOWN) {
|
||||
if ((res <= di->bm->bat_type->resis_high) &&
|
||||
(res >= di->bm->bat_type->resis_low)) {
|
||||
dev_info(di->dev, "Battery detected on %s"
|
||||
" low %d < res %d < high: %d"
|
||||
" index: %d\n",
|
||||
di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ?
|
||||
"BATCTRL" : "BATTEMP",
|
||||
di->bm->bat_type->resis_low, res,
|
||||
di->bm->bat_type->resis_high, i);
|
||||
} else {
|
||||
dev_warn(di->dev, "Battery identified as unknown"
|
||||
", resistance %d Ohm\n", res);
|
||||
", resistance %d Ohm\n", res);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only have to change current source if the
|
||||
* detected type is Type 1.
|
||||
* detected type is Type 1 (LIPO) resis_high = 53407, resis_low = 12500
|
||||
* if someone hacks this in.
|
||||
*
|
||||
* FIXME: make sure this is done automatically for the batteries
|
||||
* that need it.
|
||||
*/
|
||||
if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL &&
|
||||
di->bm->batt_id == 1) {
|
||||
if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) &&
|
||||
(di->bm->bi && (di->bm->bi->technology == POWER_SUPPLY_TECHNOLOGY_LIPO)) &&
|
||||
(res <= 53407) && (res >= 12500)) {
|
||||
dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
|
||||
di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
|
||||
}
|
||||
|
||||
return di->bm->batt_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -814,7 +808,10 @@ static int ab8500_btemp_get_property(struct power_supply *psy,
|
||||
val->intval = 1;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = di->bm->bat_type[di->bm->batt_id].name;
|
||||
if (di->bm->bi)
|
||||
val->intval = di->bm->bi->technology;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
val->intval = ab8500_btemp_get_temp(di);
|
||||
|
@ -46,8 +46,15 @@
|
||||
/* Five minutes expressed in seconds */
|
||||
#define FIVE_MINUTES_IN_SECONDS 300
|
||||
|
||||
#define CHARGALG_CURR_STEP_LOW 0
|
||||
#define CHARGALG_CURR_STEP_HIGH 100
|
||||
#define CHARGALG_CURR_STEP_LOW_UA 0
|
||||
#define CHARGALG_CURR_STEP_HIGH_UA 100000
|
||||
|
||||
/*
|
||||
* This is the battery capacity limit that will trigger a new
|
||||
* full charging cycle in the case where maintenance charging
|
||||
* has been disabled
|
||||
*/
|
||||
#define AB8500_RECHARGE_CAP 95
|
||||
|
||||
enum ab8500_chargers {
|
||||
NO_CHG,
|
||||
@ -63,14 +70,14 @@ struct ab8500_chargalg_charger_info {
|
||||
enum ab8500_chargers charger_type;
|
||||
bool usb_chg_ok;
|
||||
bool ac_chg_ok;
|
||||
int usb_volt;
|
||||
int usb_curr;
|
||||
int ac_volt;
|
||||
int ac_curr;
|
||||
int usb_vset;
|
||||
int usb_iset;
|
||||
int ac_vset;
|
||||
int ac_iset;
|
||||
int usb_volt_uv;
|
||||
int usb_curr_ua;
|
||||
int ac_volt_uv;
|
||||
int ac_curr_ua;
|
||||
int usb_vset_uv;
|
||||
int usb_iset_ua;
|
||||
int ac_vset_uv;
|
||||
int ac_iset_ua;
|
||||
};
|
||||
|
||||
struct ab8500_chargalg_suspension_status {
|
||||
@ -81,14 +88,14 @@ struct ab8500_chargalg_suspension_status {
|
||||
|
||||
struct ab8500_chargalg_current_step_status {
|
||||
bool curr_step_change;
|
||||
int curr_step;
|
||||
int curr_step_ua;
|
||||
};
|
||||
|
||||
struct ab8500_chargalg_battery_data {
|
||||
int temp;
|
||||
int volt;
|
||||
int avg_curr;
|
||||
int inst_curr;
|
||||
int volt_uv;
|
||||
int avg_curr_ua;
|
||||
int inst_curr_ua;
|
||||
int percent;
|
||||
};
|
||||
|
||||
@ -177,13 +184,13 @@ struct ab8500_chargalg_events {
|
||||
|
||||
/**
|
||||
* struct ab8500_charge_curr_maximization - Charger maximization parameters
|
||||
* @original_iset: the non optimized/maximised charger current
|
||||
* @current_iset: the charging current used at this moment
|
||||
* @test_delta_i: the delta between the current we want to charge and the
|
||||
* @original_iset_ua: the non optimized/maximised charger current
|
||||
* @current_iset_ua: the charging current used at this moment
|
||||
* @test_delta_i_ua: the delta between the current we want to charge and the
|
||||
current that is really going into the battery
|
||||
* @condition_cnt: number of iterations needed before a new charger current
|
||||
is set
|
||||
* @max_current: maximum charger current
|
||||
* @max_current_ua: maximum charger current
|
||||
* @wait_cnt: to avoid too fast current step down in case of charger
|
||||
* voltage collapse, we insert this delay between step
|
||||
* down
|
||||
@ -191,11 +198,11 @@ struct ab8500_chargalg_events {
|
||||
increased
|
||||
*/
|
||||
struct ab8500_charge_curr_maximization {
|
||||
int original_iset;
|
||||
int current_iset;
|
||||
int test_delta_i;
|
||||
int original_iset_ua;
|
||||
int current_iset_ua;
|
||||
int test_delta_i_ua;
|
||||
int condition_cnt;
|
||||
int max_current;
|
||||
int max_current_ua;
|
||||
int wait_cnt;
|
||||
u8 level;
|
||||
};
|
||||
@ -345,6 +352,8 @@ static void ab8500_chargalg_state_to(struct ab8500_chargalg *di,
|
||||
|
||||
static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di)
|
||||
{
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
|
||||
switch (di->charge_state) {
|
||||
case STATE_NORMAL:
|
||||
case STATE_MAINTENANCE_A:
|
||||
@ -356,13 +365,13 @@ static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di)
|
||||
|
||||
if (di->chg_info.charger_type & USB_CHG) {
|
||||
return di->usb_chg->ops.check_enable(di->usb_chg,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
|
||||
bi->constant_charge_voltage_max_uv,
|
||||
bi->constant_charge_current_max_ua);
|
||||
} else if ((di->chg_info.charger_type & AC_CHG) &&
|
||||
!(di->ac_chg->external)) {
|
||||
return di->ac_chg->ops.check_enable(di->ac_chg,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
|
||||
bi->constant_charge_voltage_max_uv,
|
||||
bi->constant_charge_current_max_ua);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -537,14 +546,14 @@ static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di)
|
||||
* ab8500_chargalg_ac_en() - Turn on/off the AC charger
|
||||
* @di: pointer to the ab8500_chargalg structure
|
||||
* @enable: charger on/off
|
||||
* @vset: requested charger output voltage
|
||||
* @iset: requested charger output current
|
||||
* @vset_uv: requested charger output voltage in microvolt
|
||||
* @iset_ua: requested charger output current in microampere
|
||||
*
|
||||
* The AC charger will be turned on/off with the requested charge voltage and
|
||||
* current
|
||||
*/
|
||||
static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable,
|
||||
int vset, int iset)
|
||||
int vset_uv, int iset_ua)
|
||||
{
|
||||
static int ab8500_chargalg_ex_ac_enable_toggle;
|
||||
|
||||
@ -552,13 +561,13 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable,
|
||||
return -ENXIO;
|
||||
|
||||
/* Select maximum of what both the charger and the battery supports */
|
||||
if (di->ac_chg->max_out_volt)
|
||||
vset = min(vset, di->ac_chg->max_out_volt);
|
||||
if (di->ac_chg->max_out_curr)
|
||||
iset = min(iset, di->ac_chg->max_out_curr);
|
||||
if (di->ac_chg->max_out_volt_uv)
|
||||
vset_uv = min(vset_uv, di->ac_chg->max_out_volt_uv);
|
||||
if (di->ac_chg->max_out_curr_ua)
|
||||
iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua);
|
||||
|
||||
di->chg_info.ac_iset = iset;
|
||||
di->chg_info.ac_vset = vset;
|
||||
di->chg_info.ac_iset_ua = iset_ua;
|
||||
di->chg_info.ac_vset_uv = vset_uv;
|
||||
|
||||
/* Enable external charger */
|
||||
if (enable && di->ac_chg->external &&
|
||||
@ -568,47 +577,47 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable,
|
||||
ab8500_chargalg_ex_ac_enable_toggle++;
|
||||
}
|
||||
|
||||
return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset);
|
||||
return di->ac_chg->ops.enable(di->ac_chg, enable, vset_uv, iset_ua);
|
||||
}
|
||||
|
||||
/**
|
||||
* ab8500_chargalg_usb_en() - Turn on/off the USB charger
|
||||
* @di: pointer to the ab8500_chargalg structure
|
||||
* @enable: charger on/off
|
||||
* @vset: requested charger output voltage
|
||||
* @iset: requested charger output current
|
||||
* @vset_uv: requested charger output voltage in microvolt
|
||||
* @iset_ua: requested charger output current in microampere
|
||||
*
|
||||
* The USB charger will be turned on/off with the requested charge voltage and
|
||||
* current
|
||||
*/
|
||||
static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable,
|
||||
int vset, int iset)
|
||||
int vset_uv, int iset_ua)
|
||||
{
|
||||
if (!di->usb_chg || !di->usb_chg->ops.enable)
|
||||
return -ENXIO;
|
||||
|
||||
/* Select maximum of what both the charger and the battery supports */
|
||||
if (di->usb_chg->max_out_volt)
|
||||
vset = min(vset, di->usb_chg->max_out_volt);
|
||||
if (di->usb_chg->max_out_curr)
|
||||
iset = min(iset, di->usb_chg->max_out_curr);
|
||||
if (di->usb_chg->max_out_volt_uv)
|
||||
vset_uv = min(vset_uv, di->usb_chg->max_out_volt_uv);
|
||||
if (di->usb_chg->max_out_curr_ua)
|
||||
iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua);
|
||||
|
||||
di->chg_info.usb_iset = iset;
|
||||
di->chg_info.usb_vset = vset;
|
||||
di->chg_info.usb_iset_ua = iset_ua;
|
||||
di->chg_info.usb_vset_uv = vset_uv;
|
||||
|
||||
return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset);
|
||||
return di->usb_chg->ops.enable(di->usb_chg, enable, vset_uv, iset_ua);
|
||||
}
|
||||
|
||||
/**
|
||||
* ab8500_chargalg_update_chg_curr() - Update charger current
|
||||
* @di: pointer to the ab8500_chargalg structure
|
||||
* @iset: requested charger output current
|
||||
* @iset_ua: requested charger output current in microampere
|
||||
*
|
||||
* The charger output current will be updated for the charger
|
||||
* that is currently in use
|
||||
*/
|
||||
static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di,
|
||||
int iset)
|
||||
int iset_ua)
|
||||
{
|
||||
/* Check if charger exists and update current if charging */
|
||||
if (di->ac_chg && di->ac_chg->ops.update_curr &&
|
||||
@ -617,24 +626,24 @@ static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di,
|
||||
* Select maximum of what both the charger
|
||||
* and the battery supports
|
||||
*/
|
||||
if (di->ac_chg->max_out_curr)
|
||||
iset = min(iset, di->ac_chg->max_out_curr);
|
||||
if (di->ac_chg->max_out_curr_ua)
|
||||
iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua);
|
||||
|
||||
di->chg_info.ac_iset = iset;
|
||||
di->chg_info.ac_iset_ua = iset_ua;
|
||||
|
||||
return di->ac_chg->ops.update_curr(di->ac_chg, iset);
|
||||
return di->ac_chg->ops.update_curr(di->ac_chg, iset_ua);
|
||||
} else if (di->usb_chg && di->usb_chg->ops.update_curr &&
|
||||
di->chg_info.charger_type & USB_CHG) {
|
||||
/*
|
||||
* Select maximum of what both the charger
|
||||
* and the battery supports
|
||||
*/
|
||||
if (di->usb_chg->max_out_curr)
|
||||
iset = min(iset, di->usb_chg->max_out_curr);
|
||||
if (di->usb_chg->max_out_curr_ua)
|
||||
iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua);
|
||||
|
||||
di->chg_info.usb_iset = iset;
|
||||
di->chg_info.usb_iset_ua = iset_ua;
|
||||
|
||||
return di->usb_chg->ops.update_curr(di->usb_chg, iset);
|
||||
return di->usb_chg->ops.update_curr(di->usb_chg, iset_ua);
|
||||
}
|
||||
|
||||
return -ENXIO;
|
||||
@ -683,28 +692,28 @@ static void ab8500_chargalg_hold_charging(struct ab8500_chargalg *di)
|
||||
/**
|
||||
* ab8500_chargalg_start_charging() - Start the charger
|
||||
* @di: pointer to the ab8500_chargalg structure
|
||||
* @vset: requested charger output voltage
|
||||
* @iset: requested charger output current
|
||||
* @vset_uv: requested charger output voltage in microvolt
|
||||
* @iset_ua: requested charger output current in microampere
|
||||
*
|
||||
* A charger will be enabled depending on the requested charger type that was
|
||||
* detected previously.
|
||||
*/
|
||||
static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di,
|
||||
int vset, int iset)
|
||||
int vset_uv, int iset_ua)
|
||||
{
|
||||
switch (di->chg_info.charger_type) {
|
||||
case AC_CHG:
|
||||
dev_dbg(di->dev,
|
||||
"AC parameters: Vset %d, Ich %d\n", vset, iset);
|
||||
"AC parameters: Vset %d, Ich %d\n", vset_uv, iset_ua);
|
||||
ab8500_chargalg_usb_en(di, false, 0, 0);
|
||||
ab8500_chargalg_ac_en(di, true, vset, iset);
|
||||
ab8500_chargalg_ac_en(di, true, vset_uv, iset_ua);
|
||||
break;
|
||||
|
||||
case USB_CHG:
|
||||
dev_dbg(di->dev,
|
||||
"USB parameters: Vset %d, Ich %d\n", vset, iset);
|
||||
"USB parameters: Vset %d, Ich %d\n", vset_uv, iset_ua);
|
||||
ab8500_chargalg_ac_en(di, false, 0, 0);
|
||||
ab8500_chargalg_usb_en(di, true, vset, iset);
|
||||
ab8500_chargalg_usb_en(di, true, vset_uv, iset_ua);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -722,27 +731,29 @@ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di,
|
||||
*/
|
||||
static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di)
|
||||
{
|
||||
if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) &&
|
||||
di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) {
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
|
||||
if (di->batt_data.temp > (bi->temp_alert_min + di->t_hyst_norm) &&
|
||||
di->batt_data.temp < (bi->temp_alert_max - di->t_hyst_norm)) {
|
||||
/* Temp OK! */
|
||||
di->events.btemp_underover = false;
|
||||
di->events.btemp_lowhigh = false;
|
||||
di->t_hyst_norm = 0;
|
||||
di->t_hyst_lowhigh = 0;
|
||||
} else {
|
||||
if (((di->batt_data.temp >= di->bm->temp_high) &&
|
||||
if (((di->batt_data.temp >= bi->temp_alert_max) &&
|
||||
(di->batt_data.temp <
|
||||
(di->bm->temp_over - di->t_hyst_lowhigh))) ||
|
||||
(bi->temp_max - di->t_hyst_lowhigh))) ||
|
||||
((di->batt_data.temp >
|
||||
(di->bm->temp_under + di->t_hyst_lowhigh)) &&
|
||||
(di->batt_data.temp <= di->bm->temp_low))) {
|
||||
(bi->temp_min + di->t_hyst_lowhigh)) &&
|
||||
(di->batt_data.temp <= bi->temp_alert_min))) {
|
||||
/* TEMP minor!!!!! */
|
||||
di->events.btemp_underover = false;
|
||||
di->events.btemp_lowhigh = true;
|
||||
di->t_hyst_norm = di->bm->temp_hysteresis;
|
||||
di->t_hyst_lowhigh = 0;
|
||||
} else if (di->batt_data.temp <= di->bm->temp_under ||
|
||||
di->batt_data.temp >= di->bm->temp_over) {
|
||||
} else if (di->batt_data.temp <= bi->temp_min ||
|
||||
di->batt_data.temp >= bi->temp_max) {
|
||||
/* TEMP major!!!!! */
|
||||
di->events.btemp_underover = true;
|
||||
di->events.btemp_lowhigh = false;
|
||||
@ -766,12 +777,12 @@ static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di)
|
||||
*/
|
||||
static void ab8500_chargalg_check_charger_voltage(struct ab8500_chargalg *di)
|
||||
{
|
||||
if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max)
|
||||
if (di->chg_info.usb_volt_uv > di->bm->chg_params->usb_volt_max_uv)
|
||||
di->chg_info.usb_chg_ok = false;
|
||||
else
|
||||
di->chg_info.usb_chg_ok = true;
|
||||
|
||||
if (di->chg_info.ac_volt > di->bm->chg_params->ac_volt_max)
|
||||
if (di->chg_info.ac_volt_uv > di->bm->chg_params->ac_volt_max_uv)
|
||||
di->chg_info.ac_chg_ok = false;
|
||||
else
|
||||
di->chg_info.ac_chg_ok = true;
|
||||
@ -790,12 +801,12 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di)
|
||||
{
|
||||
if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
|
||||
di->charge_state == STATE_NORMAL &&
|
||||
!di->maintenance_chg && (di->batt_data.volt >=
|
||||
di->bm->bat_type[di->bm->batt_id].termination_vol ||
|
||||
!di->maintenance_chg && (di->batt_data.volt_uv >=
|
||||
di->bm->bi->overvoltage_limit_uv ||
|
||||
di->events.usb_cv_active || di->events.ac_cv_active) &&
|
||||
di->batt_data.avg_curr <
|
||||
di->bm->bat_type[di->bm->batt_id].termination_curr &&
|
||||
di->batt_data.avg_curr > 0) {
|
||||
di->batt_data.avg_curr_ua <
|
||||
di->bm->bi->charge_term_current_ua &&
|
||||
di->batt_data.avg_curr_ua > 0) {
|
||||
if (++di->eoc_cnt >= EOC_COND_CNT) {
|
||||
di->eoc_cnt = 0;
|
||||
di->charge_status = POWER_SUPPLY_STATUS_FULL;
|
||||
@ -816,12 +827,12 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di)
|
||||
|
||||
static void init_maxim_chg_curr(struct ab8500_chargalg *di)
|
||||
{
|
||||
di->ccm.original_iset =
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl;
|
||||
di->ccm.current_iset =
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl;
|
||||
di->ccm.test_delta_i = di->bm->maxi->charger_curr_step;
|
||||
di->ccm.max_current = di->bm->maxi->chg_curr;
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
|
||||
di->ccm.original_iset_ua = bi->constant_charge_current_max_ua;
|
||||
di->ccm.current_iset_ua = bi->constant_charge_current_max_ua;
|
||||
di->ccm.test_delta_i_ua = di->bm->maxi->charger_curr_step_ua;
|
||||
di->ccm.max_current_ua = di->bm->maxi->chg_curr_ua;
|
||||
di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
|
||||
di->ccm.level = 0;
|
||||
}
|
||||
@ -837,12 +848,12 @@ static void init_maxim_chg_curr(struct ab8500_chargalg *di)
|
||||
*/
|
||||
static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di)
|
||||
{
|
||||
int delta_i;
|
||||
int delta_i_ua;
|
||||
|
||||
if (!di->bm->maxi->ena_maxi)
|
||||
return MAXIM_RET_NOACTION;
|
||||
|
||||
delta_i = di->ccm.original_iset - di->batt_data.inst_curr;
|
||||
delta_i_ua = di->ccm.original_iset_ua - di->batt_data.inst_curr_ua;
|
||||
|
||||
if (di->events.vbus_collapsed) {
|
||||
dev_dbg(di->dev, "Charger voltage has collapsed %d\n",
|
||||
@ -851,9 +862,9 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di)
|
||||
dev_dbg(di->dev, "lowering current\n");
|
||||
di->ccm.wait_cnt++;
|
||||
di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
|
||||
di->ccm.max_current =
|
||||
di->ccm.current_iset - di->ccm.test_delta_i;
|
||||
di->ccm.current_iset = di->ccm.max_current;
|
||||
di->ccm.max_current_ua =
|
||||
di->ccm.current_iset_ua - di->ccm.test_delta_i_ua;
|
||||
di->ccm.current_iset_ua = di->ccm.max_current_ua;
|
||||
di->ccm.level--;
|
||||
return MAXIM_RET_CHANGE;
|
||||
} else {
|
||||
@ -866,36 +877,36 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di)
|
||||
|
||||
di->ccm.wait_cnt = 0;
|
||||
|
||||
if (di->batt_data.inst_curr > di->ccm.original_iset) {
|
||||
dev_dbg(di->dev, " Maximization Ibat (%dmA) too high"
|
||||
" (limit %dmA) (current iset: %dmA)!\n",
|
||||
di->batt_data.inst_curr, di->ccm.original_iset,
|
||||
di->ccm.current_iset);
|
||||
if (di->batt_data.inst_curr_ua > di->ccm.original_iset_ua) {
|
||||
dev_dbg(di->dev, " Maximization Ibat (%duA) too high"
|
||||
" (limit %duA) (current iset: %duA)!\n",
|
||||
di->batt_data.inst_curr_ua, di->ccm.original_iset_ua,
|
||||
di->ccm.current_iset_ua);
|
||||
|
||||
if (di->ccm.current_iset == di->ccm.original_iset)
|
||||
if (di->ccm.current_iset_ua == di->ccm.original_iset_ua)
|
||||
return MAXIM_RET_NOACTION;
|
||||
|
||||
di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
|
||||
di->ccm.current_iset = di->ccm.original_iset;
|
||||
di->ccm.current_iset_ua = di->ccm.original_iset_ua;
|
||||
di->ccm.level = 0;
|
||||
|
||||
return MAXIM_RET_IBAT_TOO_HIGH;
|
||||
}
|
||||
|
||||
if (delta_i > di->ccm.test_delta_i &&
|
||||
(di->ccm.current_iset + di->ccm.test_delta_i) <
|
||||
di->ccm.max_current) {
|
||||
if (delta_i_ua > di->ccm.test_delta_i_ua &&
|
||||
(di->ccm.current_iset_ua + di->ccm.test_delta_i_ua) <
|
||||
di->ccm.max_current_ua) {
|
||||
if (di->ccm.condition_cnt-- == 0) {
|
||||
/* Increse the iset with cco.test_delta_i */
|
||||
di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
|
||||
di->ccm.current_iset += di->ccm.test_delta_i;
|
||||
di->ccm.current_iset_ua += di->ccm.test_delta_i_ua;
|
||||
di->ccm.level++;
|
||||
dev_dbg(di->dev, " Maximization needed, increase"
|
||||
" with %d mA to %dmA (Optimal ibat: %d)"
|
||||
" with %d uA to %duA (Optimal ibat: %d uA)"
|
||||
" Level %d\n",
|
||||
di->ccm.test_delta_i,
|
||||
di->ccm.current_iset,
|
||||
di->ccm.original_iset,
|
||||
di->ccm.test_delta_i_ua,
|
||||
di->ccm.current_iset_ua,
|
||||
di->ccm.original_iset_ua,
|
||||
di->ccm.level);
|
||||
return MAXIM_RET_CHANGE;
|
||||
} else {
|
||||
@ -909,6 +920,7 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di)
|
||||
|
||||
static void handle_maxim_chg_curr(struct ab8500_chargalg *di)
|
||||
{
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
enum maxim_ret ret;
|
||||
int result;
|
||||
|
||||
@ -916,13 +928,13 @@ static void handle_maxim_chg_curr(struct ab8500_chargalg *di)
|
||||
switch (ret) {
|
||||
case MAXIM_RET_CHANGE:
|
||||
result = ab8500_chargalg_update_chg_curr(di,
|
||||
di->ccm.current_iset);
|
||||
di->ccm.current_iset_ua);
|
||||
if (result)
|
||||
dev_err(di->dev, "failed to set chg curr\n");
|
||||
break;
|
||||
case MAXIM_RET_IBAT_TOO_HIGH:
|
||||
result = ab8500_chargalg_update_chg_curr(di,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
|
||||
bi->constant_charge_current_max_ua);
|
||||
if (result)
|
||||
dev_err(di->dev, "failed to set chg curr\n");
|
||||
break;
|
||||
@ -1158,13 +1170,13 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
switch (ext->desc->type) {
|
||||
case POWER_SUPPLY_TYPE_BATTERY:
|
||||
di->batt_data.volt = ret.intval / 1000;
|
||||
di->batt_data.volt_uv = ret.intval;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_MAINS:
|
||||
di->chg_info.ac_volt = ret.intval / 1000;
|
||||
di->chg_info.ac_volt_uv = ret.intval;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_USB:
|
||||
di->chg_info.usb_volt = ret.intval / 1000;
|
||||
di->chg_info.usb_volt_uv = ret.intval;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1217,15 +1229,13 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
switch (ext->desc->type) {
|
||||
case POWER_SUPPLY_TYPE_MAINS:
|
||||
di->chg_info.ac_curr =
|
||||
ret.intval / 1000;
|
||||
break;
|
||||
di->chg_info.ac_curr_ua = ret.intval;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_USB:
|
||||
di->chg_info.usb_curr =
|
||||
ret.intval / 1000;
|
||||
di->chg_info.usb_curr_ua = ret.intval;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_BATTERY:
|
||||
di->batt_data.inst_curr = ret.intval / 1000;
|
||||
di->batt_data.inst_curr_ua = ret.intval;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1235,7 +1245,7 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data)
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
switch (ext->desc->type) {
|
||||
case POWER_SUPPLY_TYPE_BATTERY:
|
||||
di->batt_data.avg_curr = ret.intval / 1000;
|
||||
di->batt_data.avg_curr_ua = ret.intval;
|
||||
break;
|
||||
case POWER_SUPPLY_TYPE_USB:
|
||||
if (ret.intval)
|
||||
@ -1289,9 +1299,10 @@ static void ab8500_chargalg_external_power_changed(struct power_supply *psy)
|
||||
*/
|
||||
static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
{
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
int charger_status;
|
||||
int ret;
|
||||
int curr_step_lvl;
|
||||
int curr_step_lvl_ua;
|
||||
|
||||
/* Collect data from all power_supply class devices */
|
||||
class_for_each_device(power_supply_class, NULL,
|
||||
@ -1395,9 +1406,9 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
"State %s Active_chg %d Chg_status %d AC %d USB %d "
|
||||
"AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d "
|
||||
"USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n",
|
||||
di->batt_data.volt,
|
||||
di->batt_data.avg_curr,
|
||||
di->batt_data.inst_curr,
|
||||
di->batt_data.volt_uv,
|
||||
di->batt_data.avg_curr_ua,
|
||||
di->batt_data.inst_curr_ua,
|
||||
di->batt_data.temp,
|
||||
di->batt_data.percent,
|
||||
di->maintenance_chg,
|
||||
@ -1410,12 +1421,12 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
di->chg_info.online_chg & USB_CHG,
|
||||
di->events.ac_cv_active,
|
||||
di->events.usb_cv_active,
|
||||
di->chg_info.ac_curr,
|
||||
di->chg_info.usb_curr,
|
||||
di->chg_info.ac_vset,
|
||||
di->chg_info.ac_iset,
|
||||
di->chg_info.usb_vset,
|
||||
di->chg_info.usb_iset);
|
||||
di->chg_info.ac_curr_ua,
|
||||
di->chg_info.usb_curr_ua,
|
||||
di->chg_info.ac_vset_uv,
|
||||
di->chg_info.ac_iset_ua,
|
||||
di->chg_info.usb_vset_uv,
|
||||
di->chg_info.usb_iset_ua);
|
||||
|
||||
switch (di->charge_state) {
|
||||
case STATE_HANDHELD_INIT:
|
||||
@ -1500,16 +1511,15 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
break;
|
||||
|
||||
case STATE_NORMAL_INIT:
|
||||
if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW)
|
||||
if (di->curr_status.curr_step_ua == CHARGALG_CURR_STEP_LOW_UA)
|
||||
ab8500_chargalg_stop_charging(di);
|
||||
else {
|
||||
curr_step_lvl = di->bm->bat_type[
|
||||
di->bm->batt_id].normal_cur_lvl
|
||||
* di->curr_status.curr_step
|
||||
/ CHARGALG_CURR_STEP_HIGH;
|
||||
curr_step_lvl_ua = bi->constant_charge_current_max_ua
|
||||
* di->curr_status.curr_step_ua
|
||||
/ CHARGALG_CURR_STEP_HIGH_UA;
|
||||
ab8500_chargalg_start_charging(di,
|
||||
di->bm->bat_type[di->bm->batt_id]
|
||||
.normal_vol_lvl, curr_step_lvl);
|
||||
bi->constant_charge_voltage_max_uv,
|
||||
curr_step_lvl_ua);
|
||||
}
|
||||
|
||||
ab8500_chargalg_state_to(di, STATE_NORMAL);
|
||||
@ -1543,21 +1553,17 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
fallthrough;
|
||||
|
||||
case STATE_WAIT_FOR_RECHARGE:
|
||||
if (di->batt_data.percent <=
|
||||
di->bm->bat_type[di->bm->batt_id].recharge_cap)
|
||||
if (di->batt_data.percent <= AB8500_RECHARGE_CAP)
|
||||
ab8500_chargalg_state_to(di, STATE_NORMAL_INIT);
|
||||
break;
|
||||
|
||||
case STATE_MAINTENANCE_A_INIT:
|
||||
ab8500_chargalg_stop_safety_timer(di);
|
||||
ab8500_chargalg_start_maintenance_timer(di,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].maint_a_chg_timer_h);
|
||||
di->bm->bat_type->maint_a_chg_timer_h);
|
||||
ab8500_chargalg_start_charging(di,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].maint_a_vol_lvl,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].maint_a_cur_lvl);
|
||||
di->bm->bat_type->maint_a_vol_lvl,
|
||||
di->bm->bat_type->maint_a_cur_lvl);
|
||||
ab8500_chargalg_state_to(di, STATE_MAINTENANCE_A);
|
||||
power_supply_changed(di->chargalg_psy);
|
||||
fallthrough;
|
||||
@ -1571,13 +1577,10 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
|
||||
case STATE_MAINTENANCE_B_INIT:
|
||||
ab8500_chargalg_start_maintenance_timer(di,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].maint_b_chg_timer_h);
|
||||
di->bm->bat_type->maint_b_chg_timer_h);
|
||||
ab8500_chargalg_start_charging(di,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].maint_b_vol_lvl,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].maint_b_cur_lvl);
|
||||
di->bm->bat_type->maint_b_vol_lvl,
|
||||
di->bm->bat_type->maint_b_cur_lvl);
|
||||
ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B);
|
||||
power_supply_changed(di->chargalg_psy);
|
||||
fallthrough;
|
||||
@ -1591,10 +1594,8 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
|
||||
case STATE_TEMP_LOWHIGH_INIT:
|
||||
ab8500_chargalg_start_charging(di,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].low_high_vol_lvl,
|
||||
di->bm->bat_type[
|
||||
di->bm->batt_id].low_high_cur_lvl);
|
||||
di->bm->bat_type->low_high_vol_lvl,
|
||||
di->bm->bat_type->low_high_cur_lvl);
|
||||
ab8500_chargalg_stop_maintenance_timer(di);
|
||||
di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
ab8500_chargalg_state_to(di, STATE_TEMP_LOWHIGH);
|
||||
@ -1722,7 +1723,7 @@ static int ab8500_chargalg_get_property(struct power_supply *psy,
|
||||
if (di->events.batt_ovv) {
|
||||
val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
|
||||
} else if (di->events.btemp_underover) {
|
||||
if (di->batt_data.temp <= di->bm->temp_under)
|
||||
if (di->batt_data.temp <= di->bm->bi->temp_min)
|
||||
val->intval = POWER_SUPPLY_HEALTH_COLD;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
@ -1744,7 +1745,7 @@ static int ab8500_chargalg_get_property(struct power_supply *psy,
|
||||
static ssize_t ab8500_chargalg_curr_step_show(struct ab8500_chargalg *di,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", di->curr_status.curr_step);
|
||||
return sprintf(buf, "%d\n", di->curr_status.curr_step_ua);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_chargalg_curr_step_store(struct ab8500_chargalg *di,
|
||||
@ -1757,9 +1758,9 @@ static ssize_t ab8500_chargalg_curr_step_store(struct ab8500_chargalg *di,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
di->curr_status.curr_step = param;
|
||||
if (di->curr_status.curr_step >= CHARGALG_CURR_STEP_LOW &&
|
||||
di->curr_status.curr_step <= CHARGALG_CURR_STEP_HIGH) {
|
||||
di->curr_status.curr_step_ua = param;
|
||||
if (di->curr_status.curr_step_ua >= CHARGALG_CURR_STEP_LOW_UA &&
|
||||
di->curr_status.curr_step_ua <= CHARGALG_CURR_STEP_HIGH_UA) {
|
||||
di->curr_status.curr_step_change = true;
|
||||
queue_work(di->chargalg_wq, &di->chargalg_work);
|
||||
} else
|
||||
@ -2056,7 +2057,7 @@ static int ab8500_chargalg_probe(struct platform_device *pdev)
|
||||
dev_err(di->dev, "failed to create sysfs entry\n");
|
||||
return ret;
|
||||
}
|
||||
di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;
|
||||
di->curr_status.curr_step_ua = CHARGALG_CURR_STEP_HIGH_UA;
|
||||
|
||||
dev_info(di->dev, "probe success\n");
|
||||
return component_add(dev, &ab8500_chargalg_component_ops);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,6 @@
|
||||
|
||||
#include "ab8500-bm.h"
|
||||
|
||||
#define MILLI_TO_MICRO 1000
|
||||
#define FG_LSB_IN_MA 1627
|
||||
#define QLSB_NANO_AMP_HOURS_X10 1071
|
||||
#define INS_CURR_TIMEOUT (3 * HZ)
|
||||
@ -157,10 +156,10 @@ struct inst_curr_result_list {
|
||||
* @dev: Pointer to the structure device
|
||||
* @node: a list of AB8500 FGs, hence prepared for reentrance
|
||||
* @irq holds the CCEOC interrupt number
|
||||
* @vbat: Battery voltage in mV
|
||||
* @vbat_nom: Nominal battery voltage in mV
|
||||
* @inst_curr: Instantenous battery current in mA
|
||||
* @avg_curr: Average battery current in mA
|
||||
* @vbat_uv: Battery voltage in uV
|
||||
* @vbat_nom_uv: Nominal battery voltage in uV
|
||||
* @inst_curr_ua: Instantenous battery current in uA
|
||||
* @avg_curr_ua: Average battery current in uA
|
||||
* @bat_temp battery temperature
|
||||
* @fg_samples: Number of samples used in the FG accumulation
|
||||
* @accu_charge: Accumulated charge from the last conversion
|
||||
@ -199,10 +198,10 @@ struct ab8500_fg {
|
||||
struct device *dev;
|
||||
struct list_head node;
|
||||
int irq;
|
||||
int vbat;
|
||||
int vbat_nom;
|
||||
int inst_curr;
|
||||
int avg_curr;
|
||||
int vbat_uv;
|
||||
int vbat_nom_uv;
|
||||
int inst_curr_ua;
|
||||
int avg_curr_ua;
|
||||
int bat_temp;
|
||||
int fg_samples;
|
||||
int accu_charge;
|
||||
@ -266,84 +265,84 @@ static enum power_supply_property ab8500_fg_props[] = {
|
||||
|
||||
/*
|
||||
* This array maps the raw hex value to lowbat voltage used by the AB8500
|
||||
* Values taken from the UM0836
|
||||
* Values taken from the UM0836, in microvolts.
|
||||
*/
|
||||
static int ab8500_fg_lowbat_voltage_map[] = {
|
||||
2300 ,
|
||||
2325 ,
|
||||
2350 ,
|
||||
2375 ,
|
||||
2400 ,
|
||||
2425 ,
|
||||
2450 ,
|
||||
2475 ,
|
||||
2500 ,
|
||||
2525 ,
|
||||
2550 ,
|
||||
2575 ,
|
||||
2600 ,
|
||||
2625 ,
|
||||
2650 ,
|
||||
2675 ,
|
||||
2700 ,
|
||||
2725 ,
|
||||
2750 ,
|
||||
2775 ,
|
||||
2800 ,
|
||||
2825 ,
|
||||
2850 ,
|
||||
2875 ,
|
||||
2900 ,
|
||||
2925 ,
|
||||
2950 ,
|
||||
2975 ,
|
||||
3000 ,
|
||||
3025 ,
|
||||
3050 ,
|
||||
3075 ,
|
||||
3100 ,
|
||||
3125 ,
|
||||
3150 ,
|
||||
3175 ,
|
||||
3200 ,
|
||||
3225 ,
|
||||
3250 ,
|
||||
3275 ,
|
||||
3300 ,
|
||||
3325 ,
|
||||
3350 ,
|
||||
3375 ,
|
||||
3400 ,
|
||||
3425 ,
|
||||
3450 ,
|
||||
3475 ,
|
||||
3500 ,
|
||||
3525 ,
|
||||
3550 ,
|
||||
3575 ,
|
||||
3600 ,
|
||||
3625 ,
|
||||
3650 ,
|
||||
3675 ,
|
||||
3700 ,
|
||||
3725 ,
|
||||
3750 ,
|
||||
3775 ,
|
||||
3800 ,
|
||||
3825 ,
|
||||
3850 ,
|
||||
3850 ,
|
||||
2300000,
|
||||
2325000,
|
||||
2350000,
|
||||
2375000,
|
||||
2400000,
|
||||
2425000,
|
||||
2450000,
|
||||
2475000,
|
||||
2500000,
|
||||
2525000,
|
||||
2550000,
|
||||
2575000,
|
||||
2600000,
|
||||
2625000,
|
||||
2650000,
|
||||
2675000,
|
||||
2700000,
|
||||
2725000,
|
||||
2750000,
|
||||
2775000,
|
||||
2800000,
|
||||
2825000,
|
||||
2850000,
|
||||
2875000,
|
||||
2900000,
|
||||
2925000,
|
||||
2950000,
|
||||
2975000,
|
||||
3000000,
|
||||
3025000,
|
||||
3050000,
|
||||
3075000,
|
||||
3100000,
|
||||
3125000,
|
||||
3150000,
|
||||
3175000,
|
||||
3200000,
|
||||
3225000,
|
||||
3250000,
|
||||
3275000,
|
||||
3300000,
|
||||
3325000,
|
||||
3350000,
|
||||
3375000,
|
||||
3400000,
|
||||
3425000,
|
||||
3450000,
|
||||
3475000,
|
||||
3500000,
|
||||
3525000,
|
||||
3550000,
|
||||
3575000,
|
||||
3600000,
|
||||
3625000,
|
||||
3650000,
|
||||
3675000,
|
||||
3700000,
|
||||
3725000,
|
||||
3750000,
|
||||
3775000,
|
||||
3800000,
|
||||
3825000,
|
||||
3850000,
|
||||
3850000,
|
||||
};
|
||||
|
||||
static u8 ab8500_volt_to_regval(int voltage)
|
||||
static u8 ab8500_volt_to_regval(int voltage_uv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (voltage < ab8500_fg_lowbat_voltage_map[0])
|
||||
if (voltage_uv < ab8500_fg_lowbat_voltage_map[0])
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_fg_lowbat_voltage_map); i++) {
|
||||
if (voltage < ab8500_fg_lowbat_voltage_map[i])
|
||||
if (voltage_uv < ab8500_fg_lowbat_voltage_map[i])
|
||||
return (u8) i - 1;
|
||||
}
|
||||
|
||||
@ -354,16 +353,16 @@ static u8 ab8500_volt_to_regval(int voltage)
|
||||
/**
|
||||
* ab8500_fg_is_low_curr() - Low or high current mode
|
||||
* @di: pointer to the ab8500_fg structure
|
||||
* @curr: the current to base or our decision on
|
||||
* @curr_ua: the current to base or our decision on in microampere
|
||||
*
|
||||
* Low current mode if the current consumption is below a certain threshold
|
||||
*/
|
||||
static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr)
|
||||
static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr_ua)
|
||||
{
|
||||
/*
|
||||
* We want to know if we're in low current mode
|
||||
*/
|
||||
if (curr > -di->bm->fg_params->high_curr_threshold)
|
||||
if (curr_ua > -di->bm->fg_params->high_curr_threshold_ua)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -601,13 +600,13 @@ int ab8500_fg_inst_curr_done(struct ab8500_fg *di)
|
||||
/**
|
||||
* ab8500_fg_inst_curr_finalize() - battery instantaneous current
|
||||
* @di: pointer to the ab8500_fg structure
|
||||
* @res: battery instantenous current(on success)
|
||||
* @curr_ua: battery instantenous current in microampere (on success)
|
||||
*
|
||||
* Returns 0 or an error code
|
||||
* Note: This is part "two" and has to be called at earliest 250 ms
|
||||
* after ab8500_fg_inst_curr_start()
|
||||
*/
|
||||
int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
|
||||
int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *curr_ua)
|
||||
{
|
||||
u8 low, high;
|
||||
int val;
|
||||
@ -663,14 +662,13 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
|
||||
/*
|
||||
* Convert to unit value in mA
|
||||
* Full scale input voltage is
|
||||
* 63.160mV => LSB = 63.160mV/(4096*res) = 1.542mA
|
||||
* 63.160mV => LSB = 63.160mV/(4096*res) = 1.542.000 uA
|
||||
* Given a 250ms conversion cycle time the LSB corresponds
|
||||
* to 107.1 nAh. Convert to current by dividing by the conversion
|
||||
* time in hours (250ms = 1 / (3600 * 4)h)
|
||||
* 107.1nAh assumes 10mOhm, but fg_res is in 0.1mOhm
|
||||
*/
|
||||
val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) /
|
||||
(1000 * di->bm->fg_res);
|
||||
val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) / di->bm->fg_res;
|
||||
|
||||
if (di->turn_off_fg) {
|
||||
dev_dbg(di->dev, "%s Disable FG\n", __func__);
|
||||
@ -688,7 +686,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
|
||||
goto fail;
|
||||
}
|
||||
mutex_unlock(&di->cc_lock);
|
||||
(*res) = val;
|
||||
*curr_ua = val;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
@ -699,15 +697,15 @@ fail:
|
||||
/**
|
||||
* ab8500_fg_inst_curr_blocking() - battery instantaneous current
|
||||
* @di: pointer to the ab8500_fg structure
|
||||
* @res: battery instantenous current(on success)
|
||||
*
|
||||
* Returns 0 else error code
|
||||
* Returns battery instantenous current in microampere (on success)
|
||||
* else error code
|
||||
*/
|
||||
int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di)
|
||||
{
|
||||
int ret;
|
||||
unsigned long timeout;
|
||||
int res = 0;
|
||||
int curr_ua = 0;
|
||||
|
||||
ret = ab8500_fg_inst_curr_start(di);
|
||||
if (ret) {
|
||||
@ -730,14 +728,14 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di)
|
||||
}
|
||||
}
|
||||
|
||||
ret = ab8500_fg_inst_curr_finalize(di, &res);
|
||||
ret = ab8500_fg_inst_curr_finalize(di, &curr_ua);
|
||||
if (ret) {
|
||||
dev_err(di->dev, "Failed to finalize fg_inst\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(di->dev, "%s instant current: %d", __func__, res);
|
||||
return res;
|
||||
dev_dbg(di->dev, "%s instant current: %d uA", __func__, curr_ua);
|
||||
return curr_ua;
|
||||
fail:
|
||||
disable_irq(di->irq);
|
||||
mutex_unlock(&di->cc_lock);
|
||||
@ -797,13 +795,12 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work)
|
||||
(100 * di->bm->fg_res);
|
||||
|
||||
/*
|
||||
* Convert to unit value in mA
|
||||
* Convert to unit value in uA
|
||||
* by dividing by the conversion
|
||||
* time in hours (= samples / (3600 * 4)h)
|
||||
* and multiply with 1000
|
||||
*/
|
||||
di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) /
|
||||
(1000 * di->bm->fg_res * (di->fg_samples / 4));
|
||||
di->avg_curr_ua = (val * QLSB_NANO_AMP_HOURS_X10 * 36) /
|
||||
(di->bm->fg_res * (di->fg_samples / 4));
|
||||
|
||||
di->flags.conv_done = true;
|
||||
|
||||
@ -825,7 +822,7 @@ exit:
|
||||
* ab8500_fg_bat_voltage() - get battery voltage
|
||||
* @di: pointer to the ab8500_fg structure
|
||||
*
|
||||
* Returns battery voltage(on success) else error code
|
||||
* Returns battery voltage in microvolts (on success) else error code
|
||||
*/
|
||||
static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
|
||||
{
|
||||
@ -840,6 +837,8 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* IIO returns millivolts but we want microvolts */
|
||||
vbat *= 1000;
|
||||
prev = vbat;
|
||||
return vbat;
|
||||
}
|
||||
@ -847,41 +846,16 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
|
||||
/**
|
||||
* ab8500_fg_volt_to_capacity() - Voltage based capacity
|
||||
* @di: pointer to the ab8500_fg structure
|
||||
* @voltage: The voltage to convert to a capacity
|
||||
* @voltage_uv: The voltage to convert to a capacity in microvolt
|
||||
*
|
||||
* Returns battery capacity in per mille based on voltage
|
||||
*/
|
||||
static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
|
||||
static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage_uv)
|
||||
{
|
||||
int i, tbl_size;
|
||||
const struct ab8500_v_to_cap *tbl;
|
||||
int cap = 0;
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
|
||||
tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl;
|
||||
tbl_size = di->bm->bat_type[di->bm->batt_id].n_v_cap_tbl_elements;
|
||||
|
||||
for (i = 0; i < tbl_size; ++i) {
|
||||
if (voltage > tbl[i].voltage)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((i > 0) && (i < tbl_size)) {
|
||||
cap = fixp_linear_interpolate(
|
||||
tbl[i].voltage,
|
||||
tbl[i].capacity * 10,
|
||||
tbl[i-1].voltage,
|
||||
tbl[i-1].capacity * 10,
|
||||
voltage);
|
||||
} else if (i == 0) {
|
||||
cap = 1000;
|
||||
} else {
|
||||
cap = 0;
|
||||
}
|
||||
|
||||
dev_dbg(di->dev, "%s Vbat: %d, Cap: %d per mille",
|
||||
__func__, voltage, cap);
|
||||
|
||||
return cap;
|
||||
/* Multiply by 10 because the capacity is tracked in per mille */
|
||||
return power_supply_batinfo_ocv2cap(bi, voltage_uv, di->bat_temp) * 10;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -893,8 +867,8 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
|
||||
*/
|
||||
static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di)
|
||||
{
|
||||
di->vbat = ab8500_fg_bat_voltage(di);
|
||||
return ab8500_fg_volt_to_capacity(di, di->vbat);
|
||||
di->vbat_uv = ab8500_fg_bat_voltage(di);
|
||||
return ab8500_fg_volt_to_capacity(di, di->vbat_uv);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -902,44 +876,35 @@ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di)
|
||||
* @di: pointer to the ab8500_fg structure
|
||||
*
|
||||
* Returns battery inner resistance added with the fuel gauge resistor value
|
||||
* to get the total resistance in the whole link from gnd to bat+ node.
|
||||
* to get the total resistance in the whole link from gnd to bat+ node
|
||||
* in milliohm.
|
||||
*/
|
||||
static int ab8500_fg_battery_resistance(struct ab8500_fg *di)
|
||||
{
|
||||
int i, tbl_size;
|
||||
const struct batres_vs_temp *tbl;
|
||||
int resist = 0;
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
int resistance_percent = 0;
|
||||
int resistance;
|
||||
|
||||
tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl;
|
||||
tbl_size = di->bm->bat_type[di->bm->batt_id].n_batres_tbl_elements;
|
||||
|
||||
for (i = 0; i < tbl_size; ++i) {
|
||||
if (di->bat_temp / 10 > tbl[i].temp)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((i > 0) && (i < tbl_size)) {
|
||||
resist = fixp_linear_interpolate(
|
||||
tbl[i].temp,
|
||||
tbl[i].resist,
|
||||
tbl[i-1].temp,
|
||||
tbl[i-1].resist,
|
||||
di->bat_temp / 10);
|
||||
} else if (i == 0) {
|
||||
resist = tbl[0].resist;
|
||||
} else {
|
||||
resist = tbl[tbl_size - 1].resist;
|
||||
}
|
||||
resistance_percent = power_supply_temp2resist_simple(bi->resist_table,
|
||||
bi->resist_table_size,
|
||||
di->bat_temp / 10);
|
||||
/*
|
||||
* We get a percentage of factory resistance here so first get
|
||||
* the factory resistance in milliohms then calculate how much
|
||||
* resistance we have at this temperature.
|
||||
*/
|
||||
resistance = (bi->factory_internal_resistance_uohm / 1000);
|
||||
resistance = resistance * resistance_percent / 100;
|
||||
|
||||
dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d"
|
||||
" fg resistance %d, total: %d (mOhm)\n",
|
||||
__func__, di->bat_temp, resist, di->bm->fg_res / 10,
|
||||
(di->bm->fg_res / 10) + resist);
|
||||
__func__, di->bat_temp, resistance, di->bm->fg_res / 10,
|
||||
(di->bm->fg_res / 10) + resistance);
|
||||
|
||||
/* fg_res variable is in 0.1mOhm */
|
||||
resist += di->bm->fg_res / 10;
|
||||
resistance += di->bm->fg_res / 10;
|
||||
|
||||
return resist;
|
||||
return resistance;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -951,31 +916,34 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di)
|
||||
*/
|
||||
static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di)
|
||||
{
|
||||
int vbat_comp, res;
|
||||
int vbat_comp_uv, res;
|
||||
int i = 0;
|
||||
int vbat = 0;
|
||||
int vbat_uv = 0;
|
||||
|
||||
ab8500_fg_inst_curr_start(di);
|
||||
|
||||
do {
|
||||
vbat += ab8500_fg_bat_voltage(di);
|
||||
vbat_uv += ab8500_fg_bat_voltage(di);
|
||||
i++;
|
||||
usleep_range(5000, 6000);
|
||||
} while (!ab8500_fg_inst_curr_done(di));
|
||||
|
||||
ab8500_fg_inst_curr_finalize(di, &di->inst_curr);
|
||||
ab8500_fg_inst_curr_finalize(di, &di->inst_curr_ua);
|
||||
|
||||
di->vbat = vbat / i;
|
||||
di->vbat_uv = vbat_uv / i;
|
||||
res = ab8500_fg_battery_resistance(di);
|
||||
|
||||
/* Use Ohms law to get the load compensated voltage */
|
||||
vbat_comp = di->vbat - (di->inst_curr * res) / 1000;
|
||||
/*
|
||||
* Use Ohms law to get the load compensated voltage.
|
||||
* Divide by 1000 to get from milliohms to ohms.
|
||||
*/
|
||||
vbat_comp_uv = di->vbat_uv - (di->inst_curr_ua * res) / 1000;
|
||||
|
||||
dev_dbg(di->dev, "%s Measured Vbat: %dmV,Compensated Vbat %dmV, "
|
||||
"R: %dmOhm, Current: %dmA Vbat Samples: %d\n",
|
||||
__func__, di->vbat, vbat_comp, res, di->inst_curr, i);
|
||||
dev_dbg(di->dev, "%s Measured Vbat: %d uV,Compensated Vbat %d uV, "
|
||||
"R: %d mOhm, Current: %d uA Vbat Samples: %d\n",
|
||||
__func__, di->vbat_uv, vbat_comp_uv, res, di->inst_curr_ua, i);
|
||||
|
||||
return ab8500_fg_volt_to_capacity(di, vbat_comp);
|
||||
return ab8500_fg_volt_to_capacity(di, vbat_comp_uv);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1014,11 +982,16 @@ static int ab8500_fg_convert_mah_to_uwh(struct ab8500_fg *di, int cap_mah)
|
||||
u64 div_res;
|
||||
u32 div_rem;
|
||||
|
||||
div_res = ((u64) cap_mah) * ((u64) di->vbat_nom);
|
||||
div_rem = do_div(div_res, 1000);
|
||||
/*
|
||||
* Capacity is in milli ampere hours (10^-3)Ah
|
||||
* Nominal voltage is in microvolts (10^-6)V
|
||||
* divide by 1000000 after multiplication to get to mWh
|
||||
*/
|
||||
div_res = ((u64) cap_mah) * ((u64) di->vbat_nom_uv);
|
||||
div_rem = do_div(div_res, 1000000);
|
||||
|
||||
/* Make sure to round upwards if necessary */
|
||||
if (div_rem >= 1000 / 2)
|
||||
if (div_rem >= 1000000 / 2)
|
||||
div_res++;
|
||||
|
||||
return (int) div_res;
|
||||
@ -1057,8 +1030,8 @@ static int ab8500_fg_calc_cap_charging(struct ab8500_fg *di)
|
||||
ab8500_fg_convert_mah_to_permille(di, di->bat_cap.mah);
|
||||
|
||||
/* We need to update battery voltage and inst current when charging */
|
||||
di->vbat = ab8500_fg_bat_voltage(di);
|
||||
di->inst_curr = ab8500_fg_inst_curr_blocking(di);
|
||||
di->vbat_uv = ab8500_fg_bat_voltage(di);
|
||||
di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di);
|
||||
|
||||
return di->bat_cap.mah;
|
||||
}
|
||||
@ -1585,9 +1558,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
|
||||
* RECOVERY_SLEEP if time left.
|
||||
* If high, go to READOUT
|
||||
*/
|
||||
di->inst_curr = ab8500_fg_inst_curr_blocking(di);
|
||||
di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di);
|
||||
|
||||
if (ab8500_fg_is_low_curr(di, di->inst_curr)) {
|
||||
if (ab8500_fg_is_low_curr(di, di->inst_curr_ua)) {
|
||||
if (di->recovery_cnt >
|
||||
di->bm->fg_params->recovery_total_time) {
|
||||
di->fg_samples = SEC_TO_SAMPLE(
|
||||
@ -1620,9 +1593,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
|
||||
break;
|
||||
|
||||
case AB8500_FG_DISCHARGE_READOUT:
|
||||
di->inst_curr = ab8500_fg_inst_curr_blocking(di);
|
||||
di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di);
|
||||
|
||||
if (ab8500_fg_is_low_curr(di, di->inst_curr)) {
|
||||
if (ab8500_fg_is_low_curr(di, di->inst_curr_ua)) {
|
||||
/* Detect mode change */
|
||||
if (di->high_curr_mode) {
|
||||
di->high_curr_mode = false;
|
||||
@ -1768,9 +1741,9 @@ static void ab8500_fg_algorithm(struct ab8500_fg *di)
|
||||
di->bat_cap.prev_mah,
|
||||
di->bat_cap.prev_percent,
|
||||
di->bat_cap.prev_level,
|
||||
di->vbat,
|
||||
di->inst_curr,
|
||||
di->avg_curr,
|
||||
di->vbat_uv,
|
||||
di->inst_curr_ua,
|
||||
di->avg_curr_ua,
|
||||
di->accu_charge,
|
||||
di->flags.charging,
|
||||
di->charge_state,
|
||||
@ -1863,15 +1836,15 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work)
|
||||
*/
|
||||
static void ab8500_fg_low_bat_work(struct work_struct *work)
|
||||
{
|
||||
int vbat;
|
||||
int vbat_uv;
|
||||
|
||||
struct ab8500_fg *di = container_of(work, struct ab8500_fg,
|
||||
fg_low_bat_work.work);
|
||||
|
||||
vbat = ab8500_fg_bat_voltage(di);
|
||||
vbat_uv = ab8500_fg_bat_voltage(di);
|
||||
|
||||
/* Check if LOW_BAT still fulfilled */
|
||||
if (vbat < di->bm->fg_params->lowbat_threshold) {
|
||||
if (vbat_uv < di->bm->fg_params->lowbat_threshold_uv) {
|
||||
/* Is it time to shut down? */
|
||||
if (di->low_bat_cnt < 1) {
|
||||
di->flags.low_bat = true;
|
||||
@ -2101,15 +2074,15 @@ static int ab8500_fg_get_property(struct power_supply *psy,
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
if (di->flags.bat_ovv)
|
||||
val->intval = BATT_OVV_VALUE * 1000;
|
||||
val->intval = BATT_OVV_VALUE;
|
||||
else
|
||||
val->intval = di->vbat * 1000;
|
||||
val->intval = di->vbat_uv;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
val->intval = di->inst_curr * 1000;
|
||||
val->intval = di->inst_curr_ua;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
val->intval = di->avg_curr * 1000;
|
||||
val->intval = di->avg_curr_ua;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
|
||||
val->intval = ab8500_fg_convert_mah_to_uwh(di,
|
||||
@ -2167,11 +2140,13 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
|
||||
struct power_supply *ext = dev_get_drvdata(dev);
|
||||
const char **supplicants = (const char **)ext->supplied_to;
|
||||
struct ab8500_fg *di;
|
||||
struct power_supply_battery_info *bi;
|
||||
union power_supply_propval ret;
|
||||
int j;
|
||||
|
||||
psy = (struct power_supply *)data;
|
||||
di = power_supply_get_drvdata(psy);
|
||||
bi = di->bm->bi;
|
||||
|
||||
/*
|
||||
* For all psy where the name of your driver
|
||||
@ -2234,21 +2209,22 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
|
||||
switch (ext->desc->type) {
|
||||
case POWER_SUPPLY_TYPE_BATTERY:
|
||||
if (!di->flags.batt_id_received &&
|
||||
di->bm->batt_id != BATTERY_UNKNOWN) {
|
||||
(bi && (bi->technology !=
|
||||
POWER_SUPPLY_TECHNOLOGY_UNKNOWN))) {
|
||||
const struct ab8500_battery_type *b;
|
||||
|
||||
b = &(di->bm->bat_type[di->bm->batt_id]);
|
||||
b = di->bm->bat_type;
|
||||
|
||||
di->flags.batt_id_received = true;
|
||||
|
||||
di->bat_cap.max_mah_design =
|
||||
MILLI_TO_MICRO *
|
||||
b->charge_full_design;
|
||||
di->bm->bi->charge_full_design_uah;
|
||||
|
||||
di->bat_cap.max_mah =
|
||||
di->bat_cap.max_mah_design;
|
||||
|
||||
di->vbat_nom = b->nominal_voltage;
|
||||
di->vbat_nom_uv =
|
||||
di->bm->bi->voltage_max_design_uv;
|
||||
}
|
||||
|
||||
if (ret.intval)
|
||||
@ -2314,7 +2290,7 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di)
|
||||
AB8500_SYS_CTRL2_BLOCK,
|
||||
AB8500_LOW_BAT_REG,
|
||||
ab8500_volt_to_regval(
|
||||
di->bm->fg_params->lowbat_threshold) << 1 |
|
||||
di->bm->fg_params->lowbat_threshold_uv) << 1 |
|
||||
LOW_BAT_ENABLE);
|
||||
if (ret) {
|
||||
dev_err(di->dev, "%s write failed\n", __func__);
|
||||
@ -3018,6 +2994,10 @@ static int ab8500_fg_bind(struct device *dev, struct device *master,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
di->bat_cap.max_mah_design = di->bm->bi->charge_full_design_uah;
|
||||
di->bat_cap.max_mah = di->bat_cap.max_mah_design;
|
||||
di->vbat_nom_uv = di->bm->bi->voltage_max_design_uv;
|
||||
|
||||
/* Start the coulomb counter */
|
||||
ab8500_fg_coulomb_counter(di, true);
|
||||
/* Run the FG algorithm */
|
||||
@ -3077,13 +3057,6 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
||||
psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
|
||||
psy_cfg.drv_data = di;
|
||||
|
||||
di->bat_cap.max_mah_design = MILLI_TO_MICRO *
|
||||
di->bm->bat_type[di->bm->batt_id].charge_full_design;
|
||||
|
||||
di->bat_cap.max_mah = di->bat_cap.max_mah_design;
|
||||
|
||||
di->vbat_nom = di->bm->bat_type[di->bm->batt_id].nominal_voltage;
|
||||
|
||||
di->init_capacity = true;
|
||||
|
||||
ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT);
|
||||
|
@ -561,7 +561,7 @@ static int axp20x_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axp20x_batt_ps *axp20x_batt;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct power_supply_battery_info info;
|
||||
struct power_supply_battery_info *info;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
if (!of_device_is_available(pdev->dev.of_node))
|
||||
@ -615,8 +615,8 @@ static int axp20x_power_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) {
|
||||
int vmin = info.voltage_min_design_uv;
|
||||
int ccc = info.constant_charge_current_max_ua;
|
||||
int vmin = info->voltage_min_design_uv;
|
||||
int ccc = info->constant_charge_current_max_ua;
|
||||
|
||||
if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt,
|
||||
vmin))
|
||||
|
@ -882,7 +882,7 @@ struct dt_init {
|
||||
static int bd9995x_fw_probe(struct bd9995x_device *bd)
|
||||
{
|
||||
int ret;
|
||||
struct power_supply_battery_info info;
|
||||
struct power_supply_battery_info *info;
|
||||
u32 property;
|
||||
int i;
|
||||
int regval;
|
||||
@ -891,49 +891,41 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd)
|
||||
struct battery_init battery_inits[] = {
|
||||
{
|
||||
.name = "trickle-charging current",
|
||||
.info_data = &info.tricklecharge_current_ua,
|
||||
.range = &charging_current_ranges[0],
|
||||
.ranges = 2,
|
||||
.data = &init->itrich_set,
|
||||
}, {
|
||||
.name = "pre-charging current",
|
||||
.info_data = &info.precharge_current_ua,
|
||||
.range = &charging_current_ranges[0],
|
||||
.ranges = 2,
|
||||
.data = &init->iprech_set,
|
||||
}, {
|
||||
.name = "pre-to-trickle charge voltage threshold",
|
||||
.info_data = &info.precharge_voltage_max_uv,
|
||||
.range = &trickle_to_pre_threshold_ranges[0],
|
||||
.ranges = 2,
|
||||
.data = &init->vprechg_th_set,
|
||||
}, {
|
||||
.name = "charging termination current",
|
||||
.info_data = &info.charge_term_current_ua,
|
||||
.range = &charging_current_ranges[0],
|
||||
.ranges = 2,
|
||||
.data = &init->iterm_set,
|
||||
}, {
|
||||
.name = "charging re-start voltage",
|
||||
.info_data = &info.charge_restart_voltage_uv,
|
||||
.range = &charge_voltage_regulation_ranges[0],
|
||||
.ranges = 2,
|
||||
.data = &init->vrechg_set,
|
||||
}, {
|
||||
.name = "battery overvoltage limit",
|
||||
.info_data = &info.overvoltage_limit_uv,
|
||||
.range = &charge_voltage_regulation_ranges[0],
|
||||
.ranges = 2,
|
||||
.data = &init->vbatovp_set,
|
||||
}, {
|
||||
.name = "fast-charging max current",
|
||||
.info_data = &info.constant_charge_current_max_ua,
|
||||
.range = &fast_charge_current_ranges[0],
|
||||
.ranges = 1,
|
||||
.data = &init->ichg_set,
|
||||
}, {
|
||||
.name = "fast-charging voltage",
|
||||
.info_data = &info.constant_charge_voltage_max_uv,
|
||||
.range = &charge_voltage_regulation_ranges[0],
|
||||
.ranges = 2,
|
||||
.data = &init->vfastchg_reg_set1,
|
||||
@ -966,6 +958,16 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Put pointers to the generic battery info */
|
||||
battery_inits[0].info_data = &info->tricklecharge_current_ua;
|
||||
battery_inits[1].info_data = &info->precharge_current_ua;
|
||||
battery_inits[2].info_data = &info->precharge_voltage_max_uv;
|
||||
battery_inits[3].info_data = &info->charge_term_current_ua;
|
||||
battery_inits[4].info_data = &info->charge_restart_voltage_uv;
|
||||
battery_inits[5].info_data = &info->overvoltage_limit_uv;
|
||||
battery_inits[6].info_data = &info->constant_charge_current_max_ua;
|
||||
battery_inits[7].info_data = &info->constant_charge_voltage_max_uv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(battery_inits); i++) {
|
||||
int val = *battery_inits[i].info_data;
|
||||
const struct linear_range *range = battery_inits[i].range;
|
||||
@ -980,7 +982,7 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd)
|
||||
dev_err(bd->dev, "Unsupported value for %s\n",
|
||||
battery_inits[i].name);
|
||||
|
||||
power_supply_put_battery_info(bd->charger, &info);
|
||||
power_supply_put_battery_info(bd->charger, info);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!found) {
|
||||
@ -991,7 +993,7 @@ static int bd9995x_fw_probe(struct bd9995x_device *bd)
|
||||
*(battery_inits[i].data) = regval;
|
||||
}
|
||||
|
||||
power_supply_put_battery_info(bd->charger, &info);
|
||||
power_supply_put_battery_info(bd->charger, info);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(props); i++) {
|
||||
ret = device_property_read_u32(bd->dev, props[i].prop,
|
||||
|
@ -1670,7 +1670,7 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi)
|
||||
static int bq24190_get_config(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
const char * const s = "ti,system-minimum-microvolt";
|
||||
struct power_supply_battery_info info = {};
|
||||
struct power_supply_battery_info *info;
|
||||
int v;
|
||||
|
||||
if (device_property_read_u32(bdi->dev, s, &v) == 0) {
|
||||
@ -1684,7 +1684,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi)
|
||||
|
||||
if (bdi->dev->of_node &&
|
||||
!power_supply_get_battery_info(bdi->charger, &info)) {
|
||||
v = info.precharge_current_ua / 1000;
|
||||
v = info->precharge_current_ua / 1000;
|
||||
if (v >= BQ24190_REG_PCTCC_IPRECHG_MIN
|
||||
&& v <= BQ24190_REG_PCTCC_IPRECHG_MAX)
|
||||
bdi->iprechg = v;
|
||||
@ -1692,7 +1692,7 @@ static int bq24190_get_config(struct bq24190_dev_info *bdi)
|
||||
dev_warn(bdi->dev, "invalid value for battery:precharge-current-microamp: %d\n",
|
||||
v);
|
||||
|
||||
v = info.charge_term_current_ua / 1000;
|
||||
v = info->charge_term_current_ua / 1000;
|
||||
if (v >= BQ24190_REG_PCTCC_ITERM_MIN
|
||||
&& v <= BQ24190_REG_PCTCC_ITERM_MAX)
|
||||
bdi->iterm = v;
|
||||
|
@ -945,7 +945,7 @@ static int bq2515x_power_supply_register(struct bq2515x_device *bq2515x,
|
||||
static int bq2515x_hw_init(struct bq2515x_device *bq2515x)
|
||||
{
|
||||
int ret;
|
||||
struct power_supply_battery_info bat_info = { };
|
||||
struct power_supply_battery_info *bat_info;
|
||||
|
||||
ret = bq2515x_disable_watchdog_timers(bq2515x);
|
||||
if (ret)
|
||||
@ -969,13 +969,13 @@ static int bq2515x_hw_init(struct bq2515x_device *bq2515x)
|
||||
|
||||
} else {
|
||||
bq2515x->init_data.ichg =
|
||||
bat_info.constant_charge_current_max_ua;
|
||||
bat_info->constant_charge_current_max_ua;
|
||||
|
||||
bq2515x->init_data.vbatreg =
|
||||
bat_info.constant_charge_voltage_max_uv;
|
||||
bat_info->constant_charge_voltage_max_uv;
|
||||
|
||||
bq2515x->init_data.iprechg =
|
||||
bat_info.precharge_current_ua;
|
||||
bat_info->precharge_current_ua;
|
||||
}
|
||||
|
||||
ret = bq2515x_set_const_charge_current(bq2515x,
|
||||
|
@ -1504,7 +1504,7 @@ static int bq256xx_power_supply_init(struct bq256xx_device *bq,
|
||||
|
||||
static int bq256xx_hw_init(struct bq256xx_device *bq)
|
||||
{
|
||||
struct power_supply_battery_info bat_info = { };
|
||||
struct power_supply_battery_info *bat_info;
|
||||
int wd_reg_val = BQ256XX_WATCHDOG_DIS;
|
||||
int ret = 0;
|
||||
int i;
|
||||
@ -1526,16 +1526,16 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
|
||||
if (ret) {
|
||||
dev_warn(bq->dev, "battery info missing, default values will be applied\n");
|
||||
|
||||
bat_info.constant_charge_current_max_ua =
|
||||
bat_info->constant_charge_current_max_ua =
|
||||
bq->chip_info->bq256xx_def_ichg;
|
||||
|
||||
bat_info.constant_charge_voltage_max_uv =
|
||||
bat_info->constant_charge_voltage_max_uv =
|
||||
bq->chip_info->bq256xx_def_vbatreg;
|
||||
|
||||
bat_info.precharge_current_ua =
|
||||
bat_info->precharge_current_ua =
|
||||
bq->chip_info->bq256xx_def_iprechg;
|
||||
|
||||
bat_info.charge_term_current_ua =
|
||||
bat_info->charge_term_current_ua =
|
||||
bq->chip_info->bq256xx_def_iterm;
|
||||
|
||||
bq->init_data.ichg_max =
|
||||
@ -1545,10 +1545,10 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
|
||||
bq->chip_info->bq256xx_max_vbatreg;
|
||||
} else {
|
||||
bq->init_data.ichg_max =
|
||||
bat_info.constant_charge_current_max_ua;
|
||||
bat_info->constant_charge_current_max_ua;
|
||||
|
||||
bq->init_data.vbatreg_max =
|
||||
bat_info.constant_charge_voltage_max_uv;
|
||||
bat_info->constant_charge_voltage_max_uv;
|
||||
}
|
||||
|
||||
ret = bq->chip_info->bq256xx_set_vindpm(bq, bq->init_data.vindpm);
|
||||
@ -1560,26 +1560,26 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
|
||||
return ret;
|
||||
|
||||
ret = bq->chip_info->bq256xx_set_ichg(bq,
|
||||
bat_info.constant_charge_current_max_ua);
|
||||
bat_info->constant_charge_current_max_ua);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bq->chip_info->bq256xx_set_iprechg(bq,
|
||||
bat_info.precharge_current_ua);
|
||||
bat_info->precharge_current_ua);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bq->chip_info->bq256xx_set_vbatreg(bq,
|
||||
bat_info.constant_charge_voltage_max_uv);
|
||||
bat_info->constant_charge_voltage_max_uv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bq->chip_info->bq256xx_set_iterm(bq,
|
||||
bat_info.charge_term_current_ua);
|
||||
bat_info->charge_term_current_ua);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
power_supply_put_battery_info(bq->charger, &bat_info);
|
||||
power_supply_put_battery_info(bq->charger, bat_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -266,6 +266,7 @@ enum bq25890_table_ids {
|
||||
/* lookup tables */
|
||||
TBL_TREG,
|
||||
TBL_BOOSTI,
|
||||
TBL_TSPCT,
|
||||
};
|
||||
|
||||
/* Thermal Regulation Threshold lookup table, in degrees Celsius */
|
||||
@ -280,6 +281,28 @@ static const u32 bq25890_boosti_tbl[] = {
|
||||
|
||||
#define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl)
|
||||
|
||||
/* NTC 10K temperature lookup table in tenths of a degree */
|
||||
static const u32 bq25890_tspct_tbl[] = {
|
||||
850, 840, 830, 820, 810, 800, 790, 780,
|
||||
770, 760, 750, 740, 730, 720, 710, 700,
|
||||
690, 685, 680, 675, 670, 660, 650, 645,
|
||||
640, 630, 620, 615, 610, 600, 590, 585,
|
||||
580, 570, 565, 560, 550, 540, 535, 530,
|
||||
520, 515, 510, 500, 495, 490, 480, 475,
|
||||
470, 460, 455, 450, 440, 435, 430, 425,
|
||||
420, 410, 405, 400, 390, 385, 380, 370,
|
||||
365, 360, 355, 350, 340, 335, 330, 320,
|
||||
310, 305, 300, 290, 285, 280, 275, 270,
|
||||
260, 250, 245, 240, 230, 225, 220, 210,
|
||||
205, 200, 190, 180, 175, 170, 160, 150,
|
||||
145, 140, 130, 120, 115, 110, 100, 90,
|
||||
80, 70, 60, 50, 40, 30, 20, 10,
|
||||
0, -10, -20, -30, -40, -60, -70, -80,
|
||||
-90, -10, -120, -140, -150, -170, -190, -210,
|
||||
};
|
||||
|
||||
#define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl)
|
||||
|
||||
struct bq25890_range {
|
||||
u32 min;
|
||||
u32 max;
|
||||
@ -308,7 +331,8 @@ static const union {
|
||||
|
||||
/* lookup tables */
|
||||
[TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} },
|
||||
[TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} }
|
||||
[TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} },
|
||||
[TBL_TSPCT] = { .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} }
|
||||
};
|
||||
|
||||
static int bq25890_field_read(struct bq25890_device *bq,
|
||||
@ -388,6 +412,7 @@ static bool bq25890_is_adc_property(enum power_supply_property psp)
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@ -528,6 +553,15 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
|
||||
val->intval = ret * -50000;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
ret = bq25890_field_read(bq, F_TSPCT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* convert TS percentage into rough temperature */
|
||||
val->intval = bq25890_find_val(ret, TBL_TSPCT);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -713,6 +747,7 @@ static const enum power_supply_property bq25890_power_supply_props[] = {
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
};
|
||||
|
||||
static char *bq25890_charger_supplied_to[] = {
|
||||
|
@ -1079,7 +1079,7 @@ static int bq25980_power_supply_init(struct bq25980_device *bq,
|
||||
|
||||
static int bq25980_hw_init(struct bq25980_device *bq)
|
||||
{
|
||||
struct power_supply_battery_info bat_info = { };
|
||||
struct power_supply_battery_info *bat_info;
|
||||
int wd_reg_val = BQ25980_WATCHDOG_DIS;
|
||||
int wd_max_val = BQ25980_NUM_WD_VAL - 1;
|
||||
int ret = 0;
|
||||
@ -1112,8 +1112,8 @@ static int bq25980_hw_init(struct bq25980_device *bq)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bq->init_data.ichg_max = bat_info.constant_charge_current_max_ua;
|
||||
bq->init_data.vreg_max = bat_info.constant_charge_voltage_max_uv;
|
||||
bq->init_data.ichg_max = bat_info->constant_charge_current_max_ua;
|
||||
bq->init_data.vreg_max = bat_info->constant_charge_voltage_max_uv;
|
||||
|
||||
if (bq->state.bypass) {
|
||||
ret = regmap_update_bits(bq->regmap, BQ25980_CHRGR_CTRL_2,
|
||||
|
@ -1474,7 +1474,7 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di,
|
||||
|
||||
static void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
|
||||
{
|
||||
struct power_supply_battery_info info = {};
|
||||
struct power_supply_battery_info *info;
|
||||
unsigned int min, max;
|
||||
|
||||
if (power_supply_get_battery_info(di->bat, &info) < 0)
|
||||
@ -1485,43 +1485,43 @@ static void bq27xxx_battery_settings(struct bq27xxx_device_info *di)
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.energy_full_design_uwh != info.charge_full_design_uah) {
|
||||
if (info.energy_full_design_uwh == -EINVAL)
|
||||
if (info->energy_full_design_uwh != info->charge_full_design_uah) {
|
||||
if (info->energy_full_design_uwh == -EINVAL)
|
||||
dev_warn(di->dev, "missing battery:energy-full-design-microwatt-hours\n");
|
||||
else if (info.charge_full_design_uah == -EINVAL)
|
||||
else if (info->charge_full_design_uah == -EINVAL)
|
||||
dev_warn(di->dev, "missing battery:charge-full-design-microamp-hours\n");
|
||||
}
|
||||
|
||||
/* assume min == 0 */
|
||||
max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max;
|
||||
if (info.energy_full_design_uwh > max * 1000) {
|
||||
if (info->energy_full_design_uwh > max * 1000) {
|
||||
dev_err(di->dev, "invalid battery:energy-full-design-microwatt-hours %d\n",
|
||||
info.energy_full_design_uwh);
|
||||
info.energy_full_design_uwh = -EINVAL;
|
||||
info->energy_full_design_uwh);
|
||||
info->energy_full_design_uwh = -EINVAL;
|
||||
}
|
||||
|
||||
/* assume min == 0 */
|
||||
max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max;
|
||||
if (info.charge_full_design_uah > max * 1000) {
|
||||
if (info->charge_full_design_uah > max * 1000) {
|
||||
dev_err(di->dev, "invalid battery:charge-full-design-microamp-hours %d\n",
|
||||
info.charge_full_design_uah);
|
||||
info.charge_full_design_uah = -EINVAL;
|
||||
info->charge_full_design_uah);
|
||||
info->charge_full_design_uah = -EINVAL;
|
||||
}
|
||||
|
||||
min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min;
|
||||
max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max;
|
||||
if ((info.voltage_min_design_uv < min * 1000 ||
|
||||
info.voltage_min_design_uv > max * 1000) &&
|
||||
info.voltage_min_design_uv != -EINVAL) {
|
||||
if ((info->voltage_min_design_uv < min * 1000 ||
|
||||
info->voltage_min_design_uv > max * 1000) &&
|
||||
info->voltage_min_design_uv != -EINVAL) {
|
||||
dev_err(di->dev, "invalid battery:voltage-min-design-microvolt %d\n",
|
||||
info.voltage_min_design_uv);
|
||||
info.voltage_min_design_uv = -EINVAL;
|
||||
info->voltage_min_design_uv);
|
||||
info->voltage_min_design_uv = -EINVAL;
|
||||
}
|
||||
|
||||
if ((info.energy_full_design_uwh != -EINVAL &&
|
||||
info.charge_full_design_uah != -EINVAL) ||
|
||||
info.voltage_min_design_uv != -EINVAL)
|
||||
bq27xxx_battery_set_config(di, &info);
|
||||
if ((info->energy_full_design_uwh != -EINVAL &&
|
||||
info->charge_full_design_uah != -EINVAL) ||
|
||||
info->voltage_min_design_uv != -EINVAL)
|
||||
bq27xxx_battery_set_config(di, info);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -61,7 +61,7 @@ struct cw_battery {
|
||||
struct delayed_work battery_delay_work;
|
||||
struct regmap *regmap;
|
||||
struct power_supply *rk_bat;
|
||||
struct power_supply_battery_info battery;
|
||||
struct power_supply_battery_info *battery;
|
||||
u8 *bat_profile;
|
||||
|
||||
bool charger_attached;
|
||||
@ -505,22 +505,22 @@ static int cw_battery_get_property(struct power_supply *psy,
|
||||
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
|
||||
if (cw_bat->battery.charge_full_design_uah > 0)
|
||||
val->intval = cw_bat->battery.charge_full_design_uah;
|
||||
if (cw_bat->battery->charge_full_design_uah > 0)
|
||||
val->intval = cw_bat->battery->charge_full_design_uah;
|
||||
else
|
||||
val->intval = 0;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
||||
val->intval = cw_bat->battery.charge_full_design_uah;
|
||||
val->intval = cw_bat->battery->charge_full_design_uah;
|
||||
val->intval = val->intval * cw_bat->soc / 100;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
if (cw_battery_valid_time_to_empty(cw_bat) &&
|
||||
cw_bat->battery.charge_full_design_uah > 0) {
|
||||
cw_bat->battery->charge_full_design_uah > 0) {
|
||||
/* calculate remaining capacity */
|
||||
val->intval = cw_bat->battery.charge_full_design_uah;
|
||||
val->intval = cw_bat->battery->charge_full_design_uah;
|
||||
val->intval = val->intval * cw_bat->soc / 100;
|
||||
|
||||
/* estimate current based on time to empty */
|
||||
@ -687,6 +687,12 @@ static int cw_bat_probe(struct i2c_client *client)
|
||||
|
||||
ret = power_supply_get_battery_info(cw_bat->rk_bat, &cw_bat->battery);
|
||||
if (ret) {
|
||||
/* Allocate an empty battery */
|
||||
cw_bat->battery = devm_kzalloc(&client->dev,
|
||||
sizeof(cw_bat->battery),
|
||||
GFP_KERNEL);
|
||||
if (!cw_bat->battery)
|
||||
return -ENOMEM;
|
||||
dev_warn(cw_bat->dev,
|
||||
"No monitored battery, some properties will be missing\n");
|
||||
}
|
||||
@ -724,7 +730,7 @@ static int cw_bat_remove(struct i2c_client *client)
|
||||
struct cw_battery *cw_bat = i2c_get_clientdata(client);
|
||||
|
||||
cancel_delayed_work_sync(&cw_bat->battery_delay_work);
|
||||
power_supply_put_battery_info(cw_bat->rk_bat, &cw_bat->battery);
|
||||
power_supply_put_battery_info(cw_bat->rk_bat, cw_bat->battery);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ struct ingenic_battery {
|
||||
struct iio_channel *channel;
|
||||
struct power_supply_desc desc;
|
||||
struct power_supply *battery;
|
||||
struct power_supply_battery_info info;
|
||||
struct power_supply_battery_info *info;
|
||||
};
|
||||
|
||||
static int ingenic_battery_get_property(struct power_supply *psy,
|
||||
@ -26,7 +26,7 @@ static int ingenic_battery_get_property(struct power_supply *psy,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct ingenic_battery *bat = power_supply_get_drvdata(psy);
|
||||
struct power_supply_battery_info *info = &bat->info;
|
||||
struct power_supply_battery_info *info = bat->info;
|
||||
int ret;
|
||||
|
||||
switch (psp) {
|
||||
@ -80,7 +80,7 @@ static int ingenic_battery_set_scale(struct ingenic_battery *bat)
|
||||
if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2)
|
||||
return -EINVAL;
|
||||
|
||||
max_mV = bat->info.voltage_max_design_uv / 1000;
|
||||
max_mV = bat->info->voltage_max_design_uv / 1000;
|
||||
|
||||
for (i = 0; i < scale_len; i += 2) {
|
||||
u64 scale_mV = (max_raw * scale_raw[i]) >> scale_raw[i + 1];
|
||||
@ -156,13 +156,13 @@ static int ingenic_battery_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "Unable to get battery info: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (bat->info.voltage_min_design_uv < 0) {
|
||||
if (bat->info->voltage_min_design_uv < 0) {
|
||||
dev_err(dev, "Unable to get voltage min design\n");
|
||||
return bat->info.voltage_min_design_uv;
|
||||
return bat->info->voltage_min_design_uv;
|
||||
}
|
||||
if (bat->info.voltage_max_design_uv < 0) {
|
||||
if (bat->info->voltage_max_design_uv < 0) {
|
||||
dev_err(dev, "Unable to get voltage max design\n");
|
||||
return bat->info.voltage_max_design_uv;
|
||||
return bat->info->voltage_max_design_uv;
|
||||
}
|
||||
|
||||
return ingenic_battery_set_scale(bat);
|
||||
|
509
drivers/power/supply/max77976_charger.c
Normal file
509
drivers/power/supply/max77976_charger.c
Normal file
@ -0,0 +1,509 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* max77976_charger.c - Driver for the Maxim MAX77976 battery charger
|
||||
*
|
||||
* Copyright (C) 2021 Luca Ceresoli
|
||||
* Author: Luca Ceresoli <luca@lucaceresoli.net>
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MAX77976_DRIVER_NAME "max77976-charger"
|
||||
#define MAX77976_CHIP_ID 0x76
|
||||
|
||||
static const char *max77976_manufacturer = "Maxim Integrated";
|
||||
static const char *max77976_model = "MAX77976";
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Register map
|
||||
*/
|
||||
|
||||
#define MAX77976_REG_CHIP_ID 0x00
|
||||
#define MAX77976_REG_CHIP_REVISION 0x01
|
||||
#define MAX77976_REG_CHG_INT_OK 0x12
|
||||
#define MAX77976_REG_CHG_DETAILS_01 0x14
|
||||
#define MAX77976_REG_CHG_CNFG_00 0x16
|
||||
#define MAX77976_REG_CHG_CNFG_02 0x18
|
||||
#define MAX77976_REG_CHG_CNFG_06 0x1c
|
||||
#define MAX77976_REG_CHG_CNFG_09 0x1f
|
||||
|
||||
/* CHG_DETAILS_01.CHG_DTLS values */
|
||||
enum max77976_charging_state {
|
||||
MAX77976_CHARGING_PREQUALIFICATION = 0x0,
|
||||
MAX77976_CHARGING_FAST_CONST_CURRENT,
|
||||
MAX77976_CHARGING_FAST_CONST_VOLTAGE,
|
||||
MAX77976_CHARGING_TOP_OFF,
|
||||
MAX77976_CHARGING_DONE,
|
||||
MAX77976_CHARGING_RESERVED_05,
|
||||
MAX77976_CHARGING_TIMER_FAULT,
|
||||
MAX77976_CHARGING_SUSPENDED_QBATT_OFF,
|
||||
MAX77976_CHARGING_OFF,
|
||||
MAX77976_CHARGING_RESERVED_09,
|
||||
MAX77976_CHARGING_THERMAL_SHUTDOWN,
|
||||
MAX77976_CHARGING_WATCHDOG_EXPIRED,
|
||||
MAX77976_CHARGING_SUSPENDED_JEITA,
|
||||
MAX77976_CHARGING_SUSPENDED_THM_REMOVAL,
|
||||
MAX77976_CHARGING_SUSPENDED_PIN,
|
||||
MAX77976_CHARGING_RESERVED_0F,
|
||||
};
|
||||
|
||||
/* CHG_DETAILS_01.BAT_DTLS values */
|
||||
enum max77976_battery_state {
|
||||
MAX77976_BATTERY_BATTERY_REMOVAL = 0x0,
|
||||
MAX77976_BATTERY_PREQUALIFICATION,
|
||||
MAX77976_BATTERY_TIMER_FAULT,
|
||||
MAX77976_BATTERY_REGULAR_VOLTAGE,
|
||||
MAX77976_BATTERY_LOW_VOLTAGE,
|
||||
MAX77976_BATTERY_OVERVOLTAGE,
|
||||
MAX77976_BATTERY_RESERVED,
|
||||
MAX77976_BATTERY_BATTERY_ONLY, // No valid adapter is present
|
||||
};
|
||||
|
||||
/* CHG_CNFG_00.MODE values */
|
||||
enum max77976_mode {
|
||||
MAX77976_MODE_CHARGER_BUCK = 0x5,
|
||||
MAX77976_MODE_BOOST = 0x9,
|
||||
};
|
||||
|
||||
/* CHG_CNFG_02.CHG_CC: charge current limit, 100..5500 mA, 50 mA steps */
|
||||
#define MAX77976_CHG_CC_STEP 50000U
|
||||
#define MAX77976_CHG_CC_MIN 100000U
|
||||
#define MAX77976_CHG_CC_MAX 5500000U
|
||||
|
||||
/* CHG_CNFG_09.CHGIN_ILIM: input current limit, 100..3200 mA, 100 mA steps */
|
||||
#define MAX77976_CHGIN_ILIM_STEP 100000U
|
||||
#define MAX77976_CHGIN_ILIM_MIN 100000U
|
||||
#define MAX77976_CHGIN_ILIM_MAX 3200000U
|
||||
|
||||
enum max77976_field_idx {
|
||||
VERSION, REVISION, /* CHIP_REVISION */
|
||||
CHGIN_OK, /* CHG_INT_OK */
|
||||
BAT_DTLS, CHG_DTLS, /* CHG_DETAILS_01 */
|
||||
MODE, /* CHG_CNFG_00 */
|
||||
CHG_CC, /* CHG_CNFG_02 */
|
||||
CHGPROT, /* CHG_CNFG_06 */
|
||||
CHGIN_ILIM, /* CHG_CNFG_09 */
|
||||
MAX77976_N_REGMAP_FIELDS
|
||||
};
|
||||
|
||||
static const struct reg_field max77976_reg_field[MAX77976_N_REGMAP_FIELDS] = {
|
||||
[VERSION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 4, 7),
|
||||
[REVISION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 0, 3),
|
||||
[CHGIN_OK] = REG_FIELD(MAX77976_REG_CHG_INT_OK, 6, 6),
|
||||
[CHG_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 0, 3),
|
||||
[BAT_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 4, 6),
|
||||
[MODE] = REG_FIELD(MAX77976_REG_CHG_CNFG_00, 0, 3),
|
||||
[CHG_CC] = REG_FIELD(MAX77976_REG_CHG_CNFG_02, 0, 6),
|
||||
[CHGPROT] = REG_FIELD(MAX77976_REG_CHG_CNFG_06, 2, 3),
|
||||
[CHGIN_ILIM] = REG_FIELD(MAX77976_REG_CHG_CNFG_09, 0, 5),
|
||||
};
|
||||
|
||||
static const struct regmap_config max77976_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x24,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Data structures
|
||||
*/
|
||||
|
||||
struct max77976 {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct regmap_field *rfield[MAX77976_N_REGMAP_FIELDS];
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* power_supply properties
|
||||
*/
|
||||
|
||||
static int max77976_get_status(struct max77976 *chg, int *val)
|
||||
{
|
||||
unsigned int regval;
|
||||
int err;
|
||||
|
||||
err = regmap_field_read(chg->rfield[CHG_DTLS], ®val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
switch (regval) {
|
||||
case MAX77976_CHARGING_PREQUALIFICATION:
|
||||
case MAX77976_CHARGING_FAST_CONST_CURRENT:
|
||||
case MAX77976_CHARGING_FAST_CONST_VOLTAGE:
|
||||
case MAX77976_CHARGING_TOP_OFF:
|
||||
*val = POWER_SUPPLY_STATUS_CHARGING;
|
||||
break;
|
||||
case MAX77976_CHARGING_DONE:
|
||||
*val = POWER_SUPPLY_STATUS_FULL;
|
||||
break;
|
||||
case MAX77976_CHARGING_TIMER_FAULT:
|
||||
case MAX77976_CHARGING_SUSPENDED_QBATT_OFF:
|
||||
case MAX77976_CHARGING_SUSPENDED_JEITA:
|
||||
case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL:
|
||||
case MAX77976_CHARGING_SUSPENDED_PIN:
|
||||
*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
break;
|
||||
case MAX77976_CHARGING_OFF:
|
||||
case MAX77976_CHARGING_THERMAL_SHUTDOWN:
|
||||
case MAX77976_CHARGING_WATCHDOG_EXPIRED:
|
||||
*val = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
break;
|
||||
default:
|
||||
*val = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77976_get_charge_type(struct max77976 *chg, int *val)
|
||||
{
|
||||
unsigned int regval;
|
||||
int err;
|
||||
|
||||
err = regmap_field_read(chg->rfield[CHG_DTLS], ®val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
switch (regval) {
|
||||
case MAX77976_CHARGING_PREQUALIFICATION:
|
||||
*val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
|
||||
break;
|
||||
case MAX77976_CHARGING_FAST_CONST_CURRENT:
|
||||
case MAX77976_CHARGING_FAST_CONST_VOLTAGE:
|
||||
*val = POWER_SUPPLY_CHARGE_TYPE_FAST;
|
||||
break;
|
||||
case MAX77976_CHARGING_TOP_OFF:
|
||||
*val = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
|
||||
break;
|
||||
case MAX77976_CHARGING_DONE:
|
||||
case MAX77976_CHARGING_TIMER_FAULT:
|
||||
case MAX77976_CHARGING_SUSPENDED_QBATT_OFF:
|
||||
case MAX77976_CHARGING_OFF:
|
||||
case MAX77976_CHARGING_THERMAL_SHUTDOWN:
|
||||
case MAX77976_CHARGING_WATCHDOG_EXPIRED:
|
||||
case MAX77976_CHARGING_SUSPENDED_JEITA:
|
||||
case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL:
|
||||
case MAX77976_CHARGING_SUSPENDED_PIN:
|
||||
*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
||||
break;
|
||||
default:
|
||||
*val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77976_get_health(struct max77976 *chg, int *val)
|
||||
{
|
||||
unsigned int regval;
|
||||
int err;
|
||||
|
||||
err = regmap_field_read(chg->rfield[BAT_DTLS], ®val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
switch (regval) {
|
||||
case MAX77976_BATTERY_BATTERY_REMOVAL:
|
||||
*val = POWER_SUPPLY_HEALTH_NO_BATTERY;
|
||||
break;
|
||||
case MAX77976_BATTERY_LOW_VOLTAGE:
|
||||
case MAX77976_BATTERY_REGULAR_VOLTAGE:
|
||||
*val = POWER_SUPPLY_HEALTH_GOOD;
|
||||
break;
|
||||
case MAX77976_BATTERY_TIMER_FAULT:
|
||||
*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
|
||||
break;
|
||||
case MAX77976_BATTERY_OVERVOLTAGE:
|
||||
*val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
|
||||
break;
|
||||
case MAX77976_BATTERY_PREQUALIFICATION:
|
||||
case MAX77976_BATTERY_BATTERY_ONLY:
|
||||
*val = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
*val = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77976_get_online(struct max77976 *chg, int *val)
|
||||
{
|
||||
unsigned int regval;
|
||||
int err;
|
||||
|
||||
err = regmap_field_read(chg->rfield[CHGIN_OK], ®val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*val = (regval ? 1 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77976_get_integer(struct max77976 *chg, enum max77976_field_idx fidx,
|
||||
unsigned int clamp_min, unsigned int clamp_max,
|
||||
unsigned int mult, int *val)
|
||||
{
|
||||
unsigned int regval;
|
||||
int err;
|
||||
|
||||
err = regmap_field_read(chg->rfield[fidx], ®val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*val = clamp_val(regval * mult, clamp_min, clamp_max);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77976_set_integer(struct max77976 *chg, enum max77976_field_idx fidx,
|
||||
unsigned int clamp_min, unsigned int clamp_max,
|
||||
unsigned int div, int val)
|
||||
{
|
||||
unsigned int regval;
|
||||
|
||||
regval = clamp_val(val, clamp_min, clamp_max) / div;
|
||||
|
||||
return regmap_field_write(chg->rfield[fidx], regval);
|
||||
}
|
||||
|
||||
static int max77976_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct max77976 *chg = power_supply_get_drvdata(psy);
|
||||
int err = 0;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
err = max77976_get_status(chg, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
err = max77976_get_charge_type(chg, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
err = max77976_get_health(chg, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
err = max77976_get_online(chg, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
|
||||
val->intval = MAX77976_CHG_CC_MAX;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
||||
err = max77976_get_integer(chg, CHG_CC,
|
||||
MAX77976_CHG_CC_MIN,
|
||||
MAX77976_CHG_CC_MAX,
|
||||
MAX77976_CHG_CC_STEP,
|
||||
&val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
err = max77976_get_integer(chg, CHGIN_ILIM,
|
||||
MAX77976_CHGIN_ILIM_MIN,
|
||||
MAX77976_CHGIN_ILIM_MAX,
|
||||
MAX77976_CHGIN_ILIM_STEP,
|
||||
&val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
val->strval = max77976_model;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
val->strval = max77976_manufacturer;
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int max77976_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct max77976 *chg = power_supply_get_drvdata(psy);
|
||||
int err = 0;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
||||
err = max77976_set_integer(chg, CHG_CC,
|
||||
MAX77976_CHG_CC_MIN,
|
||||
MAX77976_CHG_CC_MAX,
|
||||
MAX77976_CHG_CC_STEP,
|
||||
val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
err = max77976_set_integer(chg, CHGIN_ILIM,
|
||||
MAX77976_CHGIN_ILIM_MIN,
|
||||
MAX77976_CHGIN_ILIM_MAX,
|
||||
MAX77976_CHGIN_ILIM_STEP,
|
||||
val->intval);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
static int max77976_property_is_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static enum power_supply_property max77976_psy_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_CHARGE_TYPE,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc max77976_psy_desc = {
|
||||
.name = MAX77976_DRIVER_NAME,
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.properties = max77976_psy_props,
|
||||
.num_properties = ARRAY_SIZE(max77976_psy_props),
|
||||
.get_property = max77976_get_property,
|
||||
.set_property = max77976_set_property,
|
||||
.property_is_writeable = max77976_property_is_writeable,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Entry point
|
||||
*/
|
||||
|
||||
static int max77976_detect(struct max77976 *chg)
|
||||
{
|
||||
struct device *dev = &chg->client->dev;
|
||||
unsigned int id, ver, rev;
|
||||
int err;
|
||||
|
||||
err = regmap_read(chg->regmap, MAX77976_REG_CHIP_ID, &id);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "cannot read chip ID\n");
|
||||
|
||||
if (id != MAX77976_CHIP_ID)
|
||||
return dev_err_probe(dev, -ENXIO, "unknown model ID 0x%02x\n", id);
|
||||
|
||||
err = regmap_field_read(chg->rfield[VERSION], &ver);
|
||||
if (!err)
|
||||
err = regmap_field_read(chg->rfield[REVISION], &rev);
|
||||
if (err)
|
||||
return dev_err_probe(dev, -ENXIO, "cannot read version/revision\n");
|
||||
|
||||
dev_info(dev, "detected model MAX779%02x ver %u rev %u", id, ver, rev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77976_configure(struct max77976 *chg)
|
||||
{
|
||||
struct device *dev = &chg->client->dev;
|
||||
int err;
|
||||
|
||||
/* Magic value to unlock writing to some registers */
|
||||
err = regmap_field_write(chg->rfield[CHGPROT], 0x3);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Mode 5 = Charger ON, OTG OFF, buck ON, boost OFF.
|
||||
* Other modes are not implemented by this driver.
|
||||
*/
|
||||
err = regmap_field_write(chg->rfield[MODE], MAX77976_MODE_CHARGER_BUCK);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return dev_err_probe(dev, err, "error while configuring");
|
||||
}
|
||||
|
||||
static int max77976_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct power_supply *psy;
|
||||
struct max77976 *chg;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
|
||||
if (!chg)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, chg);
|
||||
psy_cfg.drv_data = chg;
|
||||
chg->client = client;
|
||||
|
||||
chg->regmap = devm_regmap_init_i2c(client, &max77976_regmap_config);
|
||||
if (IS_ERR(chg->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(chg->regmap),
|
||||
"cannot allocate regmap\n");
|
||||
|
||||
for (i = 0; i < MAX77976_N_REGMAP_FIELDS; i++) {
|
||||
chg->rfield[i] = devm_regmap_field_alloc(dev, chg->regmap,
|
||||
max77976_reg_field[i]);
|
||||
if (IS_ERR(chg->rfield[i]))
|
||||
return dev_err_probe(dev, PTR_ERR(chg->rfield[i]),
|
||||
"cannot allocate regmap field\n");
|
||||
}
|
||||
|
||||
err = max77976_detect(chg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = max77976_configure(chg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
psy = devm_power_supply_register_no_ws(dev, &max77976_psy_desc, &psy_cfg);
|
||||
if (IS_ERR(psy))
|
||||
return dev_err_probe(dev, PTR_ERR(psy), "cannot register\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max77976_i2c_id[] = {
|
||||
{ MAX77976_DRIVER_NAME, 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max77976_i2c_id);
|
||||
|
||||
static const struct of_device_id max77976_of_id[] = {
|
||||
{ .compatible = "maxim,max77976" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max77976_of_id);
|
||||
|
||||
static struct i2c_driver max77976_driver = {
|
||||
.driver = {
|
||||
.name = MAX77976_DRIVER_NAME,
|
||||
.of_match_table = max77976_of_id,
|
||||
},
|
||||
.probe_new = max77976_probe,
|
||||
.id_table = max77976_i2c_id,
|
||||
};
|
||||
module_i2c_driver(max77976_driver);
|
||||
|
||||
MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
|
||||
MODULE_DESCRIPTION("Maxim MAX77976 charger driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -21,6 +21,7 @@
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/fixp-arith.h>
|
||||
#include "power_supply.h"
|
||||
|
||||
/* exported for the APM Power driver, APM emulation */
|
||||
@ -563,14 +564,19 @@ EXPORT_SYMBOL_GPL(devm_power_supply_get_by_phandle);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
int power_supply_get_battery_info(struct power_supply *psy,
|
||||
struct power_supply_battery_info *info)
|
||||
struct power_supply_battery_info **info_out)
|
||||
{
|
||||
struct power_supply_resistance_temp_table *resist_table;
|
||||
struct power_supply_battery_info *info;
|
||||
struct device_node *battery_np;
|
||||
const char *value;
|
||||
int err, len, index;
|
||||
const __be32 *list;
|
||||
|
||||
info = devm_kmalloc(&psy->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
|
||||
info->energy_full_design_uwh = -EINVAL;
|
||||
info->charge_full_design_uah = -EINVAL;
|
||||
@ -580,6 +586,10 @@ 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->tricklecharge_current_ua = -EINVAL;
|
||||
info->precharge_voltage_max_uv = -EINVAL;
|
||||
info->charge_restart_voltage_uv = -EINVAL;
|
||||
info->overvoltage_limit_uv = -EINVAL;
|
||||
info->temp_ambient_alert_min = INT_MIN;
|
||||
info->temp_ambient_alert_max = INT_MAX;
|
||||
info->temp_alert_min = INT_MIN;
|
||||
@ -727,7 +737,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
||||
|
||||
list = of_get_property(battery_np, "resistance-temp-table", &len);
|
||||
if (!list || !len)
|
||||
goto out_put_node;
|
||||
goto out_ret_pointer;
|
||||
|
||||
info->resist_table_size = len / (2 * sizeof(__be32));
|
||||
resist_table = info->resist_table = devm_kcalloc(&psy->dev,
|
||||
@ -745,6 +755,10 @@ int power_supply_get_battery_info(struct power_supply *psy,
|
||||
resist_table[index].resistance = be32_to_cpu(*list++);
|
||||
}
|
||||
|
||||
out_ret_pointer:
|
||||
/* Finally return the whole thing */
|
||||
*info_out = info;
|
||||
|
||||
out_put_node:
|
||||
of_node_put(battery_np);
|
||||
return err;
|
||||
@ -763,6 +777,8 @@ void power_supply_put_battery_info(struct power_supply *psy,
|
||||
|
||||
if (info->resist_table)
|
||||
devm_kfree(&psy->dev, info->resist_table);
|
||||
|
||||
devm_kfree(&psy->dev, info);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
|
||||
|
||||
@ -783,26 +799,25 @@ EXPORT_SYMBOL_GPL(power_supply_put_battery_info);
|
||||
int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table,
|
||||
int table_len, int temp)
|
||||
{
|
||||
int i, resist;
|
||||
int i, high, low;
|
||||
|
||||
for (i = 0; i < table_len; i++)
|
||||
/* Break loop at table_len - 1 because that is the highest index */
|
||||
for (i = 0; i < table_len - 1; i++)
|
||||
if (temp > table[i].temp)
|
||||
break;
|
||||
|
||||
if (i > 0 && i < table_len) {
|
||||
int tmp;
|
||||
/* The library function will deal with high == low */
|
||||
if ((i == 0) || (i == (table_len - 1)))
|
||||
high = i;
|
||||
else
|
||||
high = i - 1;
|
||||
low = i;
|
||||
|
||||
tmp = (table[i - 1].resistance - table[i].resistance) *
|
||||
(temp - table[i].temp);
|
||||
tmp /= table[i - 1].temp - table[i].temp;
|
||||
resist = tmp + table[i].resistance;
|
||||
} else if (i == 0) {
|
||||
resist = table[0].resistance;
|
||||
} else {
|
||||
resist = table[table_len - 1].resistance;
|
||||
}
|
||||
|
||||
return resist;
|
||||
return fixp_linear_interpolate(table[low].temp,
|
||||
table[low].resistance,
|
||||
table[high].temp,
|
||||
table[high].resistance,
|
||||
temp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple);
|
||||
|
||||
@ -821,24 +836,25 @@ EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple);
|
||||
int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
|
||||
int table_len, int ocv)
|
||||
{
|
||||
int i, cap, tmp;
|
||||
int i, high, low;
|
||||
|
||||
for (i = 0; i < table_len; i++)
|
||||
/* Break loop at table_len - 1 because that is the highest index */
|
||||
for (i = 0; i < table_len - 1; i++)
|
||||
if (ocv > table[i].ocv)
|
||||
break;
|
||||
|
||||
if (i > 0 && i < table_len) {
|
||||
tmp = (table[i - 1].capacity - table[i].capacity) *
|
||||
(ocv - table[i].ocv);
|
||||
tmp /= table[i - 1].ocv - table[i].ocv;
|
||||
cap = tmp + table[i].capacity;
|
||||
} else if (i == 0) {
|
||||
cap = table[0].capacity;
|
||||
} else {
|
||||
cap = table[table_len - 1].capacity;
|
||||
}
|
||||
/* The library function will deal with high == low */
|
||||
if ((i == 0) || (i == (table_len - 1)))
|
||||
high = i - 1;
|
||||
else
|
||||
high = i; /* i.e. i == 0 */
|
||||
low = i;
|
||||
|
||||
return cap;
|
||||
return fixp_linear_interpolate(table[low].ocv,
|
||||
table[low].capacity,
|
||||
table[high].ocv,
|
||||
table[high].capacity,
|
||||
ocv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple);
|
||||
|
||||
|
@ -106,6 +106,7 @@ static const char * const POWER_SUPPLY_HEALTH_TEXT[] = {
|
||||
[POWER_SUPPLY_HEALTH_WARM] = "Warm",
|
||||
[POWER_SUPPLY_HEALTH_COOL] = "Cool",
|
||||
[POWER_SUPPLY_HEALTH_HOT] = "Hot",
|
||||
[POWER_SUPPLY_HEALTH_NO_BATTERY] = "No battery",
|
||||
};
|
||||
|
||||
static const char * const POWER_SUPPLY_TECHNOLOGY_TEXT[] = {
|
||||
|
@ -863,8 +863,8 @@ static int smbb_charger_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
chg->revision += 1;
|
||||
if (chg->revision != 2 && chg->revision != 3) {
|
||||
dev_err(&pdev->dev, "v1 hardware not supported\n");
|
||||
if (chg->revision != 1 && chg->revision != 2 && chg->revision != 3) {
|
||||
dev_err(&pdev->dev, "v%d hardware not supported\n", chg->revision);
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision);
|
||||
@ -1012,6 +1012,7 @@ static int smbb_charger_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id smbb_charger_id_table[] = {
|
||||
{ .compatible = "qcom,pm8226-charger" },
|
||||
{ .compatible = "qcom,pm8941-charger" },
|
||||
{ }
|
||||
};
|
||||
|
@ -368,7 +368,7 @@ static int sc2731_charger_usb_change(struct notifier_block *nb,
|
||||
|
||||
static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
|
||||
{
|
||||
struct power_supply_battery_info bat_info = { };
|
||||
struct power_supply_battery_info *bat_info;
|
||||
u32 term_currrent, term_voltage, cur_val, vol_val;
|
||||
int ret;
|
||||
|
||||
@ -390,7 +390,7 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
|
||||
cur_val = 0x2;
|
||||
vol_val = 0x1;
|
||||
} else {
|
||||
term_currrent = bat_info.charge_term_current_ua / 1000;
|
||||
term_currrent = bat_info->charge_term_current_ua / 1000;
|
||||
|
||||
if (term_currrent <= 90)
|
||||
cur_val = 0;
|
||||
@ -399,7 +399,7 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
|
||||
else
|
||||
cur_val = ((term_currrent - 90) / 25) + 1;
|
||||
|
||||
term_voltage = bat_info.constant_charge_voltage_max_uv / 1000;
|
||||
term_voltage = bat_info->constant_charge_voltage_max_uv / 1000;
|
||||
|
||||
if (term_voltage > 4500)
|
||||
term_voltage = 4500;
|
||||
@ -409,7 +409,7 @@ static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
|
||||
else
|
||||
vol_val = 0;
|
||||
|
||||
power_supply_put_battery_info(info->psy_usb, &bat_info);
|
||||
power_supply_put_battery_info(info->psy_usb, bat_info);
|
||||
}
|
||||
|
||||
/* Set charge termination current */
|
||||
|
@ -998,7 +998,7 @@ static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data)
|
||||
|
||||
static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data)
|
||||
{
|
||||
struct power_supply_battery_info info = { };
|
||||
struct power_supply_battery_info *info;
|
||||
struct power_supply_battery_ocv_table *table;
|
||||
int ret, delta_clbcnt, alarm_adc;
|
||||
|
||||
@ -1008,16 +1008,16 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->total_cap = info.charge_full_design_uah / 1000;
|
||||
data->max_volt = info.constant_charge_voltage_max_uv / 1000;
|
||||
data->internal_resist = info.factory_internal_resistance_uohm / 1000;
|
||||
data->min_volt = info.voltage_min_design_uv;
|
||||
data->total_cap = info->charge_full_design_uah / 1000;
|
||||
data->max_volt = info->constant_charge_voltage_max_uv / 1000;
|
||||
data->internal_resist = info->factory_internal_resistance_uohm / 1000;
|
||||
data->min_volt = info->voltage_min_design_uv;
|
||||
|
||||
/*
|
||||
* For SC27XX fuel gauge device, we only use one ocv-capacity
|
||||
* table in normal temperature 20 Celsius.
|
||||
*/
|
||||
table = power_supply_find_ocv2cap_table(&info, 20, &data->table_len);
|
||||
table = power_supply_find_ocv2cap_table(info, 20, &data->table_len);
|
||||
if (!table)
|
||||
return -EINVAL;
|
||||
|
||||
@ -1025,7 +1025,7 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data)
|
||||
data->table_len * sizeof(*table),
|
||||
GFP_KERNEL);
|
||||
if (!data->cap_table) {
|
||||
power_supply_put_battery_info(data->battery, &info);
|
||||
power_supply_put_battery_info(data->battery, info);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -1035,19 +1035,19 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data)
|
||||
if (!data->alarm_cap)
|
||||
data->alarm_cap += 1;
|
||||
|
||||
data->resist_table_len = info.resist_table_size;
|
||||
data->resist_table_len = info->resist_table_size;
|
||||
if (data->resist_table_len > 0) {
|
||||
data->resist_table = devm_kmemdup(data->dev, info.resist_table,
|
||||
data->resist_table = devm_kmemdup(data->dev, info->resist_table,
|
||||
data->resist_table_len *
|
||||
sizeof(struct power_supply_resistance_temp_table),
|
||||
GFP_KERNEL);
|
||||
if (!data->resist_table) {
|
||||
power_supply_put_battery_info(data->battery, &info);
|
||||
power_supply_put_battery_info(data->battery, info);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
power_supply_put_battery_info(data->battery, &info);
|
||||
power_supply_put_battery_info(data->battery, info);
|
||||
|
||||
ret = sc27xx_fgu_calibration(data);
|
||||
if (ret)
|
||||
|
@ -1281,7 +1281,7 @@ static void smb347_dt_parse_dev_info(struct smb347_charger *smb)
|
||||
|
||||
static int smb347_get_battery_info(struct smb347_charger *smb)
|
||||
{
|
||||
struct power_supply_battery_info info = {};
|
||||
struct power_supply_battery_info *info;
|
||||
struct power_supply *supply;
|
||||
int err;
|
||||
|
||||
@ -1296,29 +1296,29 @@ static int smb347_get_battery_info(struct smb347_charger *smb)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (info.constant_charge_current_max_ua != -EINVAL)
|
||||
smb->max_charge_current = info.constant_charge_current_max_ua;
|
||||
if (info->constant_charge_current_max_ua != -EINVAL)
|
||||
smb->max_charge_current = info->constant_charge_current_max_ua;
|
||||
|
||||
if (info.constant_charge_voltage_max_uv != -EINVAL)
|
||||
smb->max_charge_voltage = info.constant_charge_voltage_max_uv;
|
||||
if (info->constant_charge_voltage_max_uv != -EINVAL)
|
||||
smb->max_charge_voltage = info->constant_charge_voltage_max_uv;
|
||||
|
||||
if (info.precharge_current_ua != -EINVAL)
|
||||
smb->pre_charge_current = info.precharge_current_ua;
|
||||
if (info->precharge_current_ua != -EINVAL)
|
||||
smb->pre_charge_current = info->precharge_current_ua;
|
||||
|
||||
if (info.charge_term_current_ua != -EINVAL)
|
||||
smb->termination_current = info.charge_term_current_ua;
|
||||
if (info->charge_term_current_ua != -EINVAL)
|
||||
smb->termination_current = info->charge_term_current_ua;
|
||||
|
||||
if (info.temp_alert_min != INT_MIN)
|
||||
smb->soft_cold_temp_limit = info.temp_alert_min;
|
||||
if (info->temp_alert_min != INT_MIN)
|
||||
smb->soft_cold_temp_limit = info->temp_alert_min;
|
||||
|
||||
if (info.temp_alert_max != INT_MAX)
|
||||
smb->soft_hot_temp_limit = info.temp_alert_max;
|
||||
if (info->temp_alert_max != INT_MAX)
|
||||
smb->soft_hot_temp_limit = info->temp_alert_max;
|
||||
|
||||
if (info.temp_min != INT_MIN)
|
||||
smb->hard_cold_temp_limit = info.temp_min;
|
||||
if (info->temp_min != INT_MIN)
|
||||
smb->hard_cold_temp_limit = info->temp_min;
|
||||
|
||||
if (info.temp_max != INT_MAX)
|
||||
smb->hard_hot_temp_limit = info.temp_max;
|
||||
if (info->temp_max != INT_MAX)
|
||||
smb->hard_hot_temp_limit = info->temp_max;
|
||||
|
||||
/* Suspend when battery temperature is outside hard limits */
|
||||
if (smb->hard_cold_temp_limit != SMB3XX_TEMP_USE_DEFAULT ||
|
||||
|
@ -66,6 +66,7 @@ enum {
|
||||
POWER_SUPPLY_HEALTH_WARM,
|
||||
POWER_SUPPLY_HEALTH_COOL,
|
||||
POWER_SUPPLY_HEALTH_HOT,
|
||||
POWER_SUPPLY_HEALTH_NO_BATTERY,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -342,37 +343,206 @@ struct power_supply_resistance_temp_table {
|
||||
|
||||
#define POWER_SUPPLY_OCV_TEMP_MAX 20
|
||||
|
||||
/*
|
||||
/**
|
||||
* struct power_supply_battery_info - information about batteries
|
||||
* @technology: from the POWER_SUPPLY_TECHNOLOGY_* enum
|
||||
* @energy_full_design_uwh: energy content when fully charged in microwatt
|
||||
* hours
|
||||
* @charge_full_design_uah: charge content when fully charged in microampere
|
||||
* hours
|
||||
* @voltage_min_design_uv: minimum voltage across the poles when the battery
|
||||
* is at minimum voltage level in microvolts. If the voltage drops below this
|
||||
* level the battery will need precharging when using CC/CV charging.
|
||||
* @voltage_max_design_uv: voltage across the poles when the battery is fully
|
||||
* charged in microvolts. This is the "nominal voltage" i.e. the voltage
|
||||
* printed on the label of the battery.
|
||||
* @tricklecharge_current_ua: the tricklecharge current used when trickle
|
||||
* charging the battery in microamperes. This is the charging phase when the
|
||||
* battery is completely empty and we need to carefully trickle in some
|
||||
* charge until we reach the precharging voltage.
|
||||
* @precharge_current_ua: current to use in the precharge phase in microamperes,
|
||||
* the precharge rate is limited by limiting the current to this value.
|
||||
* @precharge_voltage_max_uv: the maximum voltage allowed when precharging in
|
||||
* microvolts. When we pass this voltage we will nominally switch over to the
|
||||
* CC (constant current) charging phase defined by constant_charge_current_ua
|
||||
* and constant_charge_voltage_max_uv.
|
||||
* @charge_term_current_ua: when the current in the CV (constant voltage)
|
||||
* charging phase drops below this value in microamperes the charging will
|
||||
* terminate completely and not restart until the voltage over the battery
|
||||
* poles reach charge_restart_voltage_uv unless we use maintenance charging.
|
||||
* @charge_restart_voltage_uv: when the battery has been fully charged by
|
||||
* CC/CV charging and charging has been disabled, and the voltage subsequently
|
||||
* drops below this value in microvolts, the charging will be restarted
|
||||
* (typically using CV charging).
|
||||
* @overvoltage_limit_uv: If the voltage exceeds the nominal voltage
|
||||
* voltage_max_design_uv and we reach this voltage level, all charging must
|
||||
* stop and emergency procedures take place, such as shutting down the system
|
||||
* in some cases.
|
||||
* @constant_charge_current_max_ua: current in microamperes to use in the CC
|
||||
* (constant current) charging phase. The charging rate is limited
|
||||
* by this current. This is the main charging phase and as the current is
|
||||
* constant into the battery the voltage slowly ascends to
|
||||
* constant_charge_voltage_max_uv.
|
||||
* @constant_charge_voltage_max_uv: voltage in microvolts signifying the end of
|
||||
* the CC (constant current) charging phase and the beginning of the CV
|
||||
* (constant voltage) charging phase.
|
||||
* @factory_internal_resistance_uohm: the internal resistance of the battery
|
||||
* at fabrication time, expressed in microohms. This resistance will vary
|
||||
* depending on the lifetime and charge of the battery, so this is just a
|
||||
* nominal ballpark figure.
|
||||
* @ocv_temp: array indicating the open circuit voltage (OCV) capacity
|
||||
* temperature indices. This is an array of temperatures in degrees Celsius
|
||||
* indicating which capacity table to use for a certain temperature, since
|
||||
* the capacity for reasons of chemistry will be different at different
|
||||
* temperatures. Determining capacity is a multivariate problem and the
|
||||
* temperature is the first variable we determine.
|
||||
* @temp_ambient_alert_min: the battery will go outside of operating conditions
|
||||
* when the ambient temperature goes below this temperature in degrees
|
||||
* Celsius.
|
||||
* @temp_ambient_alert_max: the battery will go outside of operating conditions
|
||||
* when the ambient temperature goes above this temperature in degrees
|
||||
* Celsius.
|
||||
* @temp_alert_min: the battery should issue an alert if the internal
|
||||
* temperature goes below this temperature in degrees Celsius.
|
||||
* @temp_alert_max: the battery should issue an alert if the internal
|
||||
* temperature goes above this temperature in degrees Celsius.
|
||||
* @temp_min: the battery will go outside of operating conditions when
|
||||
* the internal temperature goes below this temperature in degrees Celsius.
|
||||
* Normally this means the system should shut down.
|
||||
* @temp_max: the battery will go outside of operating conditions when
|
||||
* the internal temperature goes above this temperature in degrees Celsius.
|
||||
* Normally this means the system should shut down.
|
||||
* @ocv_table: for each entry in ocv_temp there is a corresponding entry in
|
||||
* ocv_table and a size for each entry in ocv_table_size. These arrays
|
||||
* determine the capacity in percent in relation to the voltage in microvolts
|
||||
* at the indexed temperature.
|
||||
* @ocv_table_size: for each entry in ocv_temp this array is giving the size of
|
||||
* each entry in the array of capacity arrays in ocv_table.
|
||||
* @resist_table: this is a table that correlates a battery temperature to the
|
||||
* expected internal resistance at this temperature. The resistance is given
|
||||
* as a percentage of factory_internal_resistance_uohm. Knowing the
|
||||
* resistance of the battery is usually necessary for calculating the open
|
||||
* circuit voltage (OCV) that is then used with the ocv_table to calculate
|
||||
* the capacity of the battery. The resist_table must be ordered descending
|
||||
* by temperature: highest temperature with lowest resistance first, lowest
|
||||
* temperature with highest resistance last.
|
||||
* @resist_table_size: the number of items in the resist_table.
|
||||
*
|
||||
* This is the recommended struct to manage static battery parameters,
|
||||
* populated by power_supply_get_battery_info(). Most platform drivers should
|
||||
* use these for consistency.
|
||||
*
|
||||
* Its field names must correspond to elements in enum power_supply_property.
|
||||
* The default field value is -EINVAL.
|
||||
* Power supply class itself doesn't use this.
|
||||
*
|
||||
* The charging parameters here assume a CC/CV charging scheme. This method
|
||||
* is most common with Lithium Ion batteries (other methods are possible) and
|
||||
* looks as follows:
|
||||
*
|
||||
* ^ Battery voltage
|
||||
* | --- overvoltage_limit_uv
|
||||
* |
|
||||
* | ...................................................
|
||||
* | .. constant_charge_voltage_max_uv
|
||||
* | ..
|
||||
* | .
|
||||
* | .
|
||||
* | .
|
||||
* | .
|
||||
* | .
|
||||
* | .. precharge_voltage_max_uv
|
||||
* | ..
|
||||
* |. (trickle charging)
|
||||
* +------------------------------------------------------------------> time
|
||||
*
|
||||
* ^ Current into the battery
|
||||
* |
|
||||
* | ............. constant_charge_current_max_ua
|
||||
* | . .
|
||||
* | . .
|
||||
* | . .
|
||||
* | . .
|
||||
* | . ..
|
||||
* | . ....
|
||||
* | . .....
|
||||
* | ... precharge_current_ua ....... charge_term_current_ua
|
||||
* | . .
|
||||
* | . .
|
||||
* |.... tricklecharge_current_ua .
|
||||
* | .
|
||||
* +-----------------------------------------------------------------> time
|
||||
*
|
||||
* These diagrams are synchronized on time and the voltage and current
|
||||
* follow each other.
|
||||
*
|
||||
* With CC/CV charging commence over time like this for an empty battery:
|
||||
*
|
||||
* 1. When the battery is completely empty it may need to be charged with
|
||||
* an especially small current so that electrons just "trickle in",
|
||||
* this is the tricklecharge_current_ua.
|
||||
*
|
||||
* 2. Next a small initial pre-charge current (precharge_current_ua)
|
||||
* is applied if the voltage is below precharge_voltage_max_uv until we
|
||||
* reach precharge_voltage_max_uv. CAUTION: in some texts this is referred
|
||||
* to as "trickle charging" but the use in the Linux kernel is different
|
||||
* see below!
|
||||
*
|
||||
* 3. Then the main charging current is applied, which is called the constant
|
||||
* current (CC) phase. A current regulator is set up to allow
|
||||
* constant_charge_current_max_ua of current to flow into the battery.
|
||||
* The chemical reaction in the battery will make the voltage go up as
|
||||
* charge goes into the battery. This current is applied until we reach
|
||||
* the constant_charge_voltage_max_uv voltage.
|
||||
*
|
||||
* 4. At this voltage we switch over to the constant voltage (CV) phase. This
|
||||
* means we allow current to go into the battery, but we keep the voltage
|
||||
* fixed. This current will continue to charge the battery while keeping
|
||||
* the voltage the same. A chemical reaction in the battery goes on
|
||||
* storing energy without affecting the voltage. Over time the current
|
||||
* will slowly drop and when we reach charge_term_current_ua we will
|
||||
* end the constant voltage phase.
|
||||
*
|
||||
* After this the battery is fully charged, and if we do not support maintenance
|
||||
* charging, the charging will not restart until power dissipation makes the
|
||||
* voltage fall so that we reach charge_restart_voltage_uv and at this point
|
||||
* we restart charging at the appropriate phase, usually this will be inside
|
||||
* the CV phase.
|
||||
*
|
||||
* If we support maintenance charging the voltage is however kept high after
|
||||
* the CV phase with a very low current. This is meant to let the same charge
|
||||
* go in for usage while the charger is still connected, mainly for
|
||||
* dissipation for the power consuming entity while connected to the
|
||||
* charger.
|
||||
*
|
||||
* All charging MUST terminate if the overvoltage_limit_uv is ever reached.
|
||||
* Overcharging Lithium Ion cells can be DANGEROUS and lead to fire or
|
||||
* explosions.
|
||||
*
|
||||
* The power supply class itself doesn't use this struct as of now.
|
||||
*/
|
||||
|
||||
struct power_supply_battery_info {
|
||||
unsigned int technology; /* from the enum above */
|
||||
int energy_full_design_uwh; /* microWatt-hours */
|
||||
int charge_full_design_uah; /* microAmp-hours */
|
||||
int voltage_min_design_uv; /* microVolts */
|
||||
int voltage_max_design_uv; /* microVolts */
|
||||
int tricklecharge_current_ua; /* microAmps */
|
||||
int precharge_current_ua; /* microAmps */
|
||||
int precharge_voltage_max_uv; /* microVolts */
|
||||
int charge_term_current_ua; /* microAmps */
|
||||
int charge_restart_voltage_uv; /* microVolts */
|
||||
int overvoltage_limit_uv; /* microVolts */
|
||||
int constant_charge_current_max_ua; /* microAmps */
|
||||
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 */
|
||||
unsigned int technology;
|
||||
int energy_full_design_uwh;
|
||||
int charge_full_design_uah;
|
||||
int voltage_min_design_uv;
|
||||
int voltage_max_design_uv;
|
||||
int tricklecharge_current_ua;
|
||||
int precharge_current_ua;
|
||||
int precharge_voltage_max_uv;
|
||||
int charge_term_current_ua;
|
||||
int charge_restart_voltage_uv;
|
||||
int overvoltage_limit_uv;
|
||||
int constant_charge_current_max_ua;
|
||||
int constant_charge_voltage_max_uv;
|
||||
int factory_internal_resistance_uohm;
|
||||
int ocv_temp[POWER_SUPPLY_OCV_TEMP_MAX];
|
||||
int temp_ambient_alert_min;
|
||||
int temp_ambient_alert_max;
|
||||
int temp_alert_min;
|
||||
int temp_alert_max;
|
||||
int temp_min;
|
||||
int temp_max;
|
||||
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;
|
||||
@ -405,7 +575,7 @@ devm_power_supply_get_by_phandle(struct device *dev, const char *property)
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
extern int power_supply_get_battery_info(struct power_supply *psy,
|
||||
struct power_supply_battery_info *info);
|
||||
struct power_supply_battery_info **info_out);
|
||||
extern void power_supply_put_battery_info(struct power_supply *psy,
|
||||
struct power_supply_battery_info *info);
|
||||
extern int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
|
||||
|
Loading…
Reference in New Issue
Block a user