Highlights:
- Two new drivers from Pali Rohár and N900 hackers: rx51_battery and bq2415x_charger. The drivers are a part of a solution to replace the proprietary Nokia BME stack; - Power supply core now registers devices with a thermal cooling subsystem, so we can now automatically throttle charging. Thanks to Ramakrishna Pallala! - Device tree support for ab8500 and max8925_power drivers; - Random fixups and enhancements for a bunch of drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJQyFGdAAoJEGgI9fZJve1bYy8P/iu4XRL2kNwmPD7fMO+bZSao xCSi8zRCnOtDutB48MQXIDTi1+I64+Qqq5xTuHW5n/T0zJ88biGBZfmJLjM88oQ4 ZqfO/axT6/MNFXTQtxEvXtn/AoM6lp9ZLmIbs7mkSpcnuG8iY5eovKfeyyNiAoGh W6ISc9d1zZl8JYZXkkX4y5uxsH/t34rPjWJqygMulJrVdePpC9fNWwDYnul6T7iF /bbqIH/j88HSYNDN518dv/ot+OfPn0vuxD4WzGAqC7ddHICtuaw8TBfXHmr6j4Mf o9ytC/dH+AQ6Tcs+h7mbz/dfL4Gs9JK2LgRX2z1DtFa6uTw5jwEtZSuDF4DKovEg 71T67dsHDKJkQgGMDfDw1BrlLjQr8hkaWroF8CdmbRO0rRsfKamLQANG7mGkSu8B l1W0ZzWEbHDteNB/wCkjoncXlcqoA8YiplyVSqf38aP8YuaeHMR3LRGLFwgXK3pB lELh3cYSYLVpcqUgkRWcPrCUnLA2CkQy2B4INj5jFZilux7DzyIHMhWI2OuUs2rH 1rwTYO91gTVONuagZn8+lmsjs+Yq1n2BcyrGMG2+ZYzruFaQ+brQsCbQR0hdRuaU zWLENqwGJ/++XrFgw3/5orMZIZQzL/yq+MbIXtrgKcFRWwoxyzJuH63RMQf3S6yy hxi7pYQmb9if+HPJZVVg =Bb5O -----END PGP SIGNATURE----- Merge tag 'for-v3.8-merged' of git://git.infradead.org/battery-2.6 Pull battery subsystem updates from Anton Vorontsov: "Highlights: - Two new drivers from Pali Rohár and N900 hackers: rx51_battery and bq2415x_charger. The drivers are a part of a solution to replace the proprietary Nokia BME stack - Power supply core now registers devices with a thermal cooling subsystem, so we can now automatically throttle charging. Thanks to Ramakrishna Pallala! - Device tree support for ab8500 and max8925_power drivers - Random fixups and enhancements for a bunch of drivers." * tag 'for-v3.8-merged' of git://git.infradead.org/battery-2.6: (22 commits) max8925_power: Add support for device-tree initialization ab8500: Add devicetree support for chargalg ab8500: Add devicetree support for charger ab8500: Add devicetree support for btemp ab8500: Add devicetree support for fuelgauge twl4030_charger: Change TWL4030_MODULE_* ids to TWL_MODULE_* jz4740-battery: Use devm_request_and_ioremap jz4740-battery: Use devm_kzalloc bq27x00_battery: Fixup nominal available capacity reporting bq2415x_charger: Fix style issues bq2415x_charger: Add Kconfig/Makefile entries power_supply: Add bq2415x charger driver power_supply: Add new Nokia RX-51 (N900) power supply battery driver max17042_battery: Fix missing verify_model_lock() return value check ds2782_battery: Fix signedness bug in ds278x_read_reg16() lp8788-charger: Fix ADC channel names lp8788-charger: Fix wrong ADC conversion lp8788-charger: Use consumer device name on setting IIO channels power_supply: Register power supply for thermal cooling device power_supply: Add support for CHARGE_CONTROL_* attributes ...
This commit is contained in:
commit
7313264b89
|
@ -24,7 +24,32 @@ ab8500-bm : : : Battery Manager
|
|||
ab8500-btemp : : : Battery Temperature
|
||||
ab8500-charger : : : Battery Charger
|
||||
ab8500-codec : : : Audio Codec
|
||||
ab8500-fg : : : Fuel Gauge
|
||||
ab8500-fg : : vddadc : Fuel Gauge
|
||||
: NCONV_ACCU : : Accumulate N Sample Conversion
|
||||
: BATT_OVV : : Battery Over Voltage
|
||||
: LOW_BAT_F : : LOW threshold battery voltage
|
||||
: CC_INT_CALIB : : Coulomb Counter Internal Calibration
|
||||
: CCEOC : : Coulomb Counter End of Conversion
|
||||
ab8500-btemp : : vtvout : Battery Temperature
|
||||
: BAT_CTRL_INDB : : Battery Removal Indicator
|
||||
: BTEMP_LOW : : Btemp < BtempLow, if battery temperature is lower than -10°C
|
||||
: BTEMP_LOW_MEDIUM : : BtempLow < Btemp < BtempMedium,if battery temperature is between -10 and 0°C
|
||||
: BTEMP_MEDIUM_HIGH : : BtempMedium < Btemp < BtempHigh,if battery temperature is between 0°C and“MaxTemp
|
||||
: BTEMP_HIGH : : Btemp > BtempHigh, if battery temperature is higher than “MaxTemp
|
||||
ab8500-charger : : vddadc : Charger interface
|
||||
: MAIN_CH_UNPLUG_DET : : main charger unplug detection management (not in 8505)
|
||||
: MAIN_CHARGE_PLUG_DET : : main charger plug detection management (not in 8505)
|
||||
: MAIN_EXT_CH_NOT_OK : : main charger not OK
|
||||
: MAIN_CH_TH_PROT_R : : Die temp is above main charger
|
||||
: MAIN_CH_TH_PROT_F : : Die temp is below main charger
|
||||
: VBUS_DET_F : : VBUS falling detected
|
||||
: VBUS_DET_R : : VBUS rising detected
|
||||
: USB_LINK_STATUS : : USB link status has changed
|
||||
: USB_CH_TH_PROT_R : : Die temp is above usb charger
|
||||
: USB_CH_TH_PROT_F : : Die temp is below usb charger
|
||||
: USB_CHARGER_NOT_OKR : : allowed USB charger not ok detection
|
||||
: VBUS_OVV : : Overvoltage on Vbus ball detected (USB charge is stopped)
|
||||
: CH_WD_EXP : : Charger watchdog detected
|
||||
ab8500-gpadc : HW_CONV_END : vddadc : Analogue to Digital Converter
|
||||
SW_CONV_END : :
|
||||
ab8500-gpio : : : GPIO Controller
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
=== AB8500 Battery Temperature Monitor Driver ===
|
||||
|
||||
The properties below describes the node for btemp driver.
|
||||
|
||||
Required Properties:
|
||||
- compatible = Shall be: "stericsson,ab8500-btemp"
|
||||
- battery = Shall be battery specific information
|
||||
|
||||
Example:
|
||||
ab8500_btemp {
|
||||
compatible = "stericsson,ab8500-btemp";
|
||||
battery = <&ab8500_battery>;
|
||||
};
|
||||
|
||||
For information on battery specific node, Ref:
|
||||
Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
|
|
@ -0,0 +1,16 @@
|
|||
=== AB8500 Charging Algorithm Driver ===
|
||||
|
||||
The properties below describes the node for chargalg driver.
|
||||
|
||||
Required Properties:
|
||||
- compatible = Shall be: "stericsson,ab8500-chargalg"
|
||||
- battery = Shall be battery specific information
|
||||
|
||||
Example:
|
||||
ab8500_chargalg {
|
||||
compatible = "stericsson,ab8500-chargalg";
|
||||
battery = <&ab8500_battery>;
|
||||
};
|
||||
|
||||
For information on battery specific node, Ref:
|
||||
Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
|
|
@ -0,0 +1,25 @@
|
|||
=== AB8500 Charger Driver ===
|
||||
|
||||
Required Properties:
|
||||
- compatible = Shall be "stericsson,ab8500-charger"
|
||||
- battery = Shall be battery specific information
|
||||
Example:
|
||||
ab8500_charger {
|
||||
compatible = "stericsson,ab8500-charger";
|
||||
battery = <&ab8500_battery>;
|
||||
};
|
||||
|
||||
- vddadc-supply: Supply for USB and Main charger
|
||||
Example:
|
||||
ab8500-charger {
|
||||
vddadc-supply = <&ab8500_ldo_tvout_reg>;
|
||||
}
|
||||
- autopower_cfg:
|
||||
Boolean value depicting the presence of 'automatic poweron after powerloss'
|
||||
Example:
|
||||
ab8500-charger {
|
||||
autopower_cfg;
|
||||
};
|
||||
|
||||
For information on battery specific node, Ref:
|
||||
Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
|
|
@ -0,0 +1,58 @@
|
|||
=== AB8500 Fuel Gauge Driver ===
|
||||
|
||||
AB8500 is a mixed signal multimedia and power management
|
||||
device comprising: power and energy-management-module,
|
||||
wall-charger, usb-charger, audio codec, general purpose adc,
|
||||
tvout, clock management and sim card interface.
|
||||
|
||||
Fuelgauge support is part of energy-management-modules, other
|
||||
components of this module are:
|
||||
main-charger, usb-combo-charger and battery-temperature-monitoring.
|
||||
|
||||
The properties below describes the node for fuelgauge driver.
|
||||
|
||||
Required Properties:
|
||||
- compatible = This shall be: "stericsson,ab8500-fg"
|
||||
- battery = Shall be battery specific information
|
||||
Example:
|
||||
ab8500_fg {
|
||||
compatible = "stericsson,ab8500-fg";
|
||||
battery = <&ab8500_battery>;
|
||||
};
|
||||
|
||||
dependent node:
|
||||
ab8500_battery: ab8500_battery {
|
||||
};
|
||||
This node will provide information on 'thermistor interface' and
|
||||
'battery technology type' used.
|
||||
|
||||
Properties of this node are:
|
||||
thermistor-on-batctrl:
|
||||
A boolean value indicating thermistor interface to battery
|
||||
|
||||
Note:
|
||||
'btemp' and 'batctrl' are the pins interfaced for battery temperature
|
||||
measurement, 'btemp' signal is used when NTC(negative temperature
|
||||
coefficient) resister is interfaced external to battery whereas
|
||||
'batctrl' pin is used when NTC resister is internal to battery.
|
||||
|
||||
Example:
|
||||
ab8500_battery: ab8500_battery {
|
||||
thermistor-on-batctrl;
|
||||
};
|
||||
indicates: NTC resister is internal to battery, 'batctrl' is used
|
||||
for thermal measurement.
|
||||
|
||||
The absence of property 'thermal-on-batctrl' indicates
|
||||
NTC resister is external to battery and 'btemp' signal is used
|
||||
for thermal measurement.
|
||||
|
||||
battery-type:
|
||||
This shall be the battery manufacturing technology type,
|
||||
allowed types are:
|
||||
"UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn"
|
||||
Example:
|
||||
ab8500_battery: ab8500_battery {
|
||||
stericsson,battery-type = "LIPO";
|
||||
}
|
||||
|
|
@ -123,6 +123,9 @@ CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
|
|||
CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the
|
||||
power supply object.
|
||||
|
||||
CHARGE_CONTROL_LIMIT - current charge control limit setting
|
||||
CHARGE_CONTROL_LIMIT_MAX - maximum charge control limit setting
|
||||
|
||||
ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
|
||||
|
||||
CAPACITY - capacity in percents.
|
||||
|
|
|
@ -340,7 +340,33 @@
|
|||
vddadc-supply = <&ab8500_ldo_tvout_reg>;
|
||||
};
|
||||
|
||||
ab8500-usb {
|
||||
ab8500_battery: ab8500_battery {
|
||||
stericsson,battery-type = "LIPO";
|
||||
thermistor-on-batctrl;
|
||||
};
|
||||
|
||||
ab8500_fg {
|
||||
compatible = "stericsson,ab8500-fg";
|
||||
battery = <&ab8500_battery>;
|
||||
};
|
||||
|
||||
ab8500_btemp {
|
||||
compatible = "stericsson,ab8500-btemp";
|
||||
battery = <&ab8500_battery>;
|
||||
};
|
||||
|
||||
ab8500_charger {
|
||||
compatible = "stericsson,ab8500-charger";
|
||||
battery = <&ab8500_battery>;
|
||||
vddadc-supply = <&ab8500_ldo_tvout_reg>;
|
||||
};
|
||||
|
||||
ab8500_chargalg {
|
||||
compatible = "stericsson,ab8500-chargalg";
|
||||
battery = <&ab8500_battery>;
|
||||
};
|
||||
|
||||
ab8500_usb {
|
||||
compatible = "stericsson,ab8500-usb";
|
||||
interrupts = < 90 0x4
|
||||
96 0x4
|
||||
|
|
|
@ -1036,23 +1036,43 @@ static struct mfd_cell abx500_common_devs[] = {
|
|||
static struct mfd_cell ab8500_bm_devs[] = {
|
||||
{
|
||||
.name = "ab8500-charger",
|
||||
.of_compatible = "stericsson,ab8500-charger",
|
||||
.num_resources = ARRAY_SIZE(ab8500_charger_resources),
|
||||
.resources = ab8500_charger_resources,
|
||||
#ifndef CONFIG_OF
|
||||
.platform_data = &ab8500_bm_data,
|
||||
.pdata_size = sizeof(ab8500_bm_data),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "ab8500-btemp",
|
||||
.of_compatible = "stericsson,ab8500-btemp",
|
||||
.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
|
||||
.resources = ab8500_btemp_resources,
|
||||
#ifndef CONFIG_OF
|
||||
.platform_data = &ab8500_bm_data,
|
||||
.pdata_size = sizeof(ab8500_bm_data),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "ab8500-fg",
|
||||
.of_compatible = "stericsson,ab8500-fg",
|
||||
.num_resources = ARRAY_SIZE(ab8500_fg_resources),
|
||||
.resources = ab8500_fg_resources,
|
||||
#ifndef CONFIG_OF
|
||||
.platform_data = &ab8500_bm_data,
|
||||
.pdata_size = sizeof(ab8500_bm_data),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.name = "ab8500-chargalg",
|
||||
.of_compatible = "stericsson,ab8500-chargalg",
|
||||
.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
|
||||
.resources = ab8500_chargalg_resources,
|
||||
#ifndef CONFIG_OF
|
||||
.platform_data = &ab8500_bm_data,
|
||||
.pdata_size = sizeof(ab8500_bm_data),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -245,6 +245,13 @@ config BATTERY_INTEL_MID
|
|||
Say Y here to enable the battery driver on Intel MID
|
||||
platforms.
|
||||
|
||||
config BATTERY_RX51
|
||||
tristate "Nokia RX-51 (N900) battery driver"
|
||||
depends on TWL4030_MADC
|
||||
help
|
||||
Say Y here to enable support for battery information on Nokia
|
||||
RX-51, also known as N900 tablet.
|
||||
|
||||
config CHARGER_ISP1704
|
||||
tristate "ISP1704 USB Charger Detection"
|
||||
depends on USB_OTG_UTILS
|
||||
|
@ -315,6 +322,16 @@ config CHARGER_MAX8998
|
|||
Say Y to enable support for the battery charger control sysfs and
|
||||
platform data of MAX8998/LP3974 PMICs.
|
||||
|
||||
config CHARGER_BQ2415X
|
||||
tristate "TI BQ2415x battery charger driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y to enable support for the TI BQ2415x battery charger
|
||||
PMICs.
|
||||
|
||||
You'll need this driver to charge batteries on e.g. Nokia
|
||||
RX-51/N900.
|
||||
|
||||
config CHARGER_SMB347
|
||||
tristate "Summit Microelectronics SMB347 Battery Charger"
|
||||
depends on I2C
|
||||
|
@ -329,13 +346,6 @@ config AB8500_BM
|
|||
help
|
||||
Say Y to include support for AB8500 battery management.
|
||||
|
||||
config AB8500_BATTERY_THERM_ON_BATCTRL
|
||||
bool "Thermistor connected on BATCTRL ADC"
|
||||
depends on AB8500_BM
|
||||
help
|
||||
Say Y to enable battery temperature measurements using
|
||||
thermistor connected on BATCTRL ADC.
|
||||
|
||||
source "drivers/power/reset/Kconfig"
|
||||
|
||||
endif # POWER_SUPPLY
|
||||
|
|
|
@ -37,7 +37,8 @@ obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
|
|||
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
|
||||
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
|
||||
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
|
||||
obj-$(CONFIG_AB8500_BM) += ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
|
||||
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
|
||||
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
|
||||
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
|
||||
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
|
||||
|
@ -47,6 +48,7 @@ obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
|
|||
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
|
||||
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
|
||||
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
|
||||
obj-$(CONFIG_POWER_AVS) += avs/
|
||||
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
|
||||
obj-$(CONFIG_POWER_RESET) += reset/
|
||||
|
|
|
@ -0,0 +1,521 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/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.
|
||||
*/
|
||||
static struct abx500_res_to_temp 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},
|
||||
};
|
||||
|
||||
static struct abx500_res_to_temp 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},
|
||||
};
|
||||
|
||||
static struct abx500_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 struct abx500_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 struct abx500_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},
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that the res_to_temp table must be strictly sorted by falling
|
||||
* resistance values to work.
|
||||
*/
|
||||
static struct abx500_res_to_temp temp_tbl[] = {
|
||||
{-5, 214834},
|
||||
{ 0, 162943},
|
||||
{ 5, 124820},
|
||||
{10, 96520},
|
||||
{15, 75306},
|
||||
{20, 59254},
|
||||
{25, 47000},
|
||||
{30, 37566},
|
||||
{35, 30245},
|
||||
{40, 24520},
|
||||
{45, 20010},
|
||||
{50, 16432},
|
||||
{55, 13576},
|
||||
{60, 11280},
|
||||
{65, 9425},
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that the batres_vs_temp table must be strictly sorted by falling
|
||||
* temperature values to work.
|
||||
*/
|
||||
static struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
|
||||
{ 40, 120},
|
||||
{ 30, 135},
|
||||
{ 20, 165},
|
||||
{ 10, 230},
|
||||
{ 00, 325},
|
||||
{-10, 445},
|
||||
{-20, 595},
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that the batres_vs_temp table must be strictly sorted by falling
|
||||
* temperature values to work.
|
||||
*/
|
||||
static 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 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 abx500_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_vol = 3990,
|
||||
.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_vol = 4130,
|
||||
.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_A_thermistor),
|
||||
.r_to_t_tbl = 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_vol = 4130,
|
||||
.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_B_thermistor),
|
||||
.r_to_t_tbl = 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 abx500_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_vol = 3990,
|
||||
.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_vol = 4130,
|
||||
.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_vol = 4130,
|
||||
.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_vol = 4130,
|
||||
.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,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct abx500_bm_capacity_levels cap_levels = {
|
||||
.critical = 2,
|
||||
.low = 10,
|
||||
.normal = 70,
|
||||
.high = 95,
|
||||
.full = 100,
|
||||
};
|
||||
|
||||
static const struct abx500_fg_parameters fg = {
|
||||
.recovery_sleep_timer = 10,
|
||||
.recovery_total_time = 100,
|
||||
.init_timer = 1,
|
||||
.init_discard_time = 5,
|
||||
.init_total_time = 40,
|
||||
.high_curr_time = 60,
|
||||
.accu_charging = 30,
|
||||
.accu_high_curr = 30,
|
||||
.high_curr_threshold = 50,
|
||||
.lowbat_threshold = 3100,
|
||||
.battok_falling_th_sel0 = 2860,
|
||||
.battok_raising_th_sel1 = 2860,
|
||||
.user_cap_limit = 15,
|
||||
.maint_thres = 97,
|
||||
};
|
||||
|
||||
static const struct abx500_maxim_parameters maxi_params = {
|
||||
.ena_maxi = true,
|
||||
.chg_curr = 910,
|
||||
.wait_cycles = 10,
|
||||
.charger_curr_step = 100,
|
||||
};
|
||||
|
||||
static const struct abx500_bm_charger_parameters chg = {
|
||||
.usb_volt_max = 5500,
|
||||
.usb_curr_max = 1500,
|
||||
.ac_volt_max = 7500,
|
||||
.ac_curr_max = 1500,
|
||||
};
|
||||
|
||||
struct abx500_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,
|
||||
.usb_safety_tmr_h = 4,
|
||||
.bkup_bat_v = BUP_VCH_SEL_2P6V,
|
||||
.bkup_bat_i = BUP_ICH_SEL_150UA,
|
||||
.no_maintenance = false,
|
||||
.adc_therm = ABx500_ADC_THERM_BATCTRL,
|
||||
.chg_unknown_bat = false,
|
||||
.enable_overshoot = false,
|
||||
.fg_res = 100,
|
||||
.cap_levels = &cap_levels,
|
||||
.bat_type = bat_type_thermistor,
|
||||
.n_btypes = 3,
|
||||
.batt_id = 0,
|
||||
.interval_charging = 5,
|
||||
.interval_not_charging = 120,
|
||||
.temp_hysteresis = 3,
|
||||
.gnd_lift_resistance = 34,
|
||||
.maxi = &maxi_params,
|
||||
.chg_params = &chg,
|
||||
.fg_params = &fg,
|
||||
};
|
||||
|
||||
int __devinit
|
||||
bmdevs_of_probe(struct device *dev,
|
||||
struct device_node *np,
|
||||
struct abx500_bm_data **battery)
|
||||
{
|
||||
struct abx500_battery_type *btype;
|
||||
struct device_node *np_bat_supply;
|
||||
struct abx500_bm_data *bat;
|
||||
const char *btech;
|
||||
char bat_tech[8];
|
||||
int i, thermistor;
|
||||
|
||||
*battery = &ab8500_bm_data;
|
||||
|
||||
/* get phandle to 'battery-info' node */
|
||||
np_bat_supply = of_parse_phandle(np, "battery", 0);
|
||||
if (!np_bat_supply) {
|
||||
dev_err(dev, "missing property battery\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (of_property_read_bool(np_bat_supply,
|
||||
"thermistor-on-batctrl"))
|
||||
thermistor = NTC_INTERNAL;
|
||||
else
|
||||
thermistor = NTC_EXTERNAL;
|
||||
|
||||
bat = *battery;
|
||||
if (thermistor == NTC_EXTERNAL) {
|
||||
bat->n_btypes = 4;
|
||||
bat->bat_type = bat_type_ext_thermistor;
|
||||
bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
|
||||
}
|
||||
btech = of_get_property(np_bat_supply,
|
||||
"stericsson,battery-type", NULL);
|
||||
if (!btech) {
|
||||
dev_warn(dev, "missing property battery-name/type\n");
|
||||
strcpy(bat_tech, "UNKNOWN");
|
||||
} else {
|
||||
strcpy(bat_tech, btech);
|
||||
}
|
||||
|
||||
if (strncmp(bat_tech, "LION", 4) == 0) {
|
||||
bat->no_maintenance = true;
|
||||
bat->chg_unknown_bat = true;
|
||||
bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
|
||||
bat->bat_type[BATTERY_UNKNOWN].termination_vol = 4150;
|
||||
bat->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130;
|
||||
bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520;
|
||||
bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200;
|
||||
}
|
||||
/* select the battery resolution table */
|
||||
for (i = 0; i < bat->n_btypes; ++i) {
|
||||
btype = (bat->bat_type + i);
|
||||
if (thermistor == NTC_EXTERNAL) {
|
||||
btype->batres_tbl =
|
||||
temp_to_batres_tbl_ext_thermistor;
|
||||
} else if (strncmp(bat_tech, "LION", 4) == 0) {
|
||||
btype->batres_tbl =
|
||||
temp_to_batres_tbl_9100;
|
||||
} else {
|
||||
btype->batres_tbl =
|
||||
temp_to_batres_tbl_thermistor;
|
||||
}
|
||||
}
|
||||
of_node_put(np_bat_supply);
|
||||
return 0;
|
||||
}
|
|
@ -20,11 +20,13 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#define VTVOUT_V 1800
|
||||
|
||||
|
@ -76,7 +78,6 @@ struct ab8500_btemp_ranges {
|
|||
* @parent: Pointer to the struct ab8500
|
||||
* @gpadc: Pointer to the struct gpadc
|
||||
* @fg: Pointer to the struct fg
|
||||
* @pdata: Pointer to the abx500_btemp platform data
|
||||
* @bat: Pointer to the abx500_bm platform data
|
||||
* @btemp_psy: Structure for BTEMP specific battery properties
|
||||
* @events: Structure for information about events triggered
|
||||
|
@ -93,7 +94,6 @@ struct ab8500_btemp {
|
|||
struct ab8500 *parent;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct ab8500_fg *fg;
|
||||
struct abx500_btemp_platform_data *pdata;
|
||||
struct abx500_bm_data *bat;
|
||||
struct power_supply btemp_psy;
|
||||
struct ab8500_btemp_events events;
|
||||
|
@ -955,56 +955,57 @@ static int ab8500_btemp_remove(struct platform_device *pdev)
|
|||
flush_scheduled_work();
|
||||
power_supply_unregister(&di->btemp_psy);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *supply_interface[] = {
|
||||
"ab8500_chargalg",
|
||||
"ab8500_fg",
|
||||
};
|
||||
|
||||
static int ab8500_btemp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ab8500_btemp *di;
|
||||
int irq, i, ret = 0;
|
||||
u8 val;
|
||||
struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
|
||||
struct ab8500_btemp *di;
|
||||
|
||||
if (!plat_data) {
|
||||
dev_err(&pdev->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
di->bat = pdev->mfd_cell->platform_data;
|
||||
if (!di->bat) {
|
||||
if (np) {
|
||||
ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get battery information\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "missing dt node for ab8500_btemp\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
dev_info(&pdev->dev, "falling back to legacy platform data\n");
|
||||
}
|
||||
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
|
||||
/* get btemp specific platform data */
|
||||
di->pdata = plat_data->btemp;
|
||||
if (!di->pdata) {
|
||||
dev_err(di->dev, "no btemp platform data supplied\n");
|
||||
ret = -EINVAL;
|
||||
goto free_device_info;
|
||||
}
|
||||
|
||||
/* get battery specific platform data */
|
||||
di->bat = plat_data->battery;
|
||||
if (!di->bat) {
|
||||
dev_err(di->dev, "no battery platform data supplied\n");
|
||||
ret = -EINVAL;
|
||||
goto free_device_info;
|
||||
}
|
||||
|
||||
/* BTEMP supply */
|
||||
di->btemp_psy.name = "ab8500_btemp";
|
||||
di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
di->btemp_psy.properties = ab8500_btemp_props;
|
||||
di->btemp_psy.num_properties = ARRAY_SIZE(ab8500_btemp_props);
|
||||
di->btemp_psy.get_property = ab8500_btemp_get_property;
|
||||
di->btemp_psy.supplied_to = di->pdata->supplied_to;
|
||||
di->btemp_psy.num_supplicants = di->pdata->num_supplicants;
|
||||
di->btemp_psy.supplied_to = supply_interface;
|
||||
di->btemp_psy.num_supplicants = ARRAY_SIZE(supply_interface);
|
||||
di->btemp_psy.external_power_changed =
|
||||
ab8500_btemp_external_power_changed;
|
||||
|
||||
|
@ -1014,8 +1015,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
|
|||
create_singlethread_workqueue("ab8500_btemp_wq");
|
||||
if (di->btemp_wq == NULL) {
|
||||
dev_err(di->dev, "failed to create work queue\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_device_info;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Init work for measuring temperature periodically */
|
||||
|
@ -1093,12 +1093,14 @@ free_irq:
|
|||
}
|
||||
free_btemp_wq:
|
||||
destroy_workqueue(di->btemp_wq);
|
||||
free_device_info:
|
||||
kfree(di);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id ab8500_btemp_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-btemp", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver ab8500_btemp_driver = {
|
||||
.probe = ab8500_btemp_probe,
|
||||
.remove = ab8500_btemp_remove,
|
||||
|
@ -1107,6 +1109,7 @@ static struct platform_driver ab8500_btemp_driver = {
|
|||
.driver = {
|
||||
.name = "ab8500-btemp",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ab8500_btemp_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
|
@ -181,9 +183,9 @@ struct ab8500_charger_usb_state {
|
|||
* @vbat Battery voltage
|
||||
* @old_vbat Previously measured battery voltage
|
||||
* @autopower Indicate if we should have automatic pwron after pwrloss
|
||||
* @autopower_cfg platform specific power config support for "pwron after pwrloss"
|
||||
* @parent: Pointer to the struct ab8500
|
||||
* @gpadc: Pointer to the struct gpadc
|
||||
* @pdata: Pointer to the abx500_charger platform data
|
||||
* @bat: Pointer to the abx500_bm platform data
|
||||
* @flags: Structure for information about events triggered
|
||||
* @usb_state: Structure for usb stack information
|
||||
|
@ -218,9 +220,9 @@ struct ab8500_charger {
|
|||
int vbat;
|
||||
int old_vbat;
|
||||
bool autopower;
|
||||
bool autopower_cfg;
|
||||
struct ab8500 *parent;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct abx500_charger_platform_data *pdata;
|
||||
struct abx500_bm_data *bat;
|
||||
struct ab8500_charger_event_flags flags;
|
||||
struct ab8500_charger_usb_state usb_state;
|
||||
|
@ -322,7 +324,7 @@ static void ab8500_power_loss_handling(struct ab8500_charger *di)
|
|||
static void ab8500_power_supply_changed(struct ab8500_charger *di,
|
||||
struct power_supply *psy)
|
||||
{
|
||||
if (di->pdata->autopower_cfg) {
|
||||
if (di->autopower_cfg) {
|
||||
if (!di->usb.charger_connected &&
|
||||
!di->ac.charger_connected &&
|
||||
di->autopower) {
|
||||
|
@ -2526,25 +2528,45 @@ static int ab8500_charger_remove(struct platform_device *pdev)
|
|||
power_supply_unregister(&di->usb_chg.psy);
|
||||
power_supply_unregister(&di->ac_chg.psy);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *supply_interface[] = {
|
||||
"ab8500_chargalg",
|
||||
"ab8500_fg",
|
||||
"ab8500_btemp",
|
||||
};
|
||||
|
||||
static int ab8500_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
int irq, i, charger_status, ret = 0;
|
||||
struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ab8500_charger *di;
|
||||
int irq, i, charger_status, ret = 0;
|
||||
|
||||
if (!plat_data) {
|
||||
dev_err(&pdev->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
di->bat = pdev->mfd_cell->platform_data;
|
||||
if (!di->bat) {
|
||||
if (np) {
|
||||
ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get battery information\n");
|
||||
return ret;
|
||||
}
|
||||
di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
|
||||
} else {
|
||||
dev_err(&pdev->dev, "missing dt node for ab8500_charger\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
dev_info(&pdev->dev, "falling back to legacy platform data\n");
|
||||
di->autopower_cfg = false;
|
||||
}
|
||||
|
||||
/* get parent data */
|
||||
di->dev = &pdev->dev;
|
||||
|
@ -2554,22 +2576,6 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
/* initialize lock */
|
||||
spin_lock_init(&di->usb_state.usb_lock);
|
||||
|
||||
/* get charger specific platform data */
|
||||
di->pdata = plat_data->charger;
|
||||
if (!di->pdata) {
|
||||
dev_err(di->dev, "no charger platform data supplied\n");
|
||||
ret = -EINVAL;
|
||||
goto free_device_info;
|
||||
}
|
||||
|
||||
/* get battery specific platform data */
|
||||
di->bat = plat_data->battery;
|
||||
if (!di->bat) {
|
||||
dev_err(di->dev, "no battery platform data supplied\n");
|
||||
ret = -EINVAL;
|
||||
goto free_device_info;
|
||||
}
|
||||
|
||||
di->autopower = false;
|
||||
|
||||
/* AC supply */
|
||||
|
@ -2579,8 +2585,8 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
di->ac_chg.psy.properties = ab8500_charger_ac_props;
|
||||
di->ac_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_ac_props);
|
||||
di->ac_chg.psy.get_property = ab8500_charger_ac_get_property;
|
||||
di->ac_chg.psy.supplied_to = di->pdata->supplied_to;
|
||||
di->ac_chg.psy.num_supplicants = di->pdata->num_supplicants;
|
||||
di->ac_chg.psy.supplied_to = supply_interface;
|
||||
di->ac_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
|
||||
/* ux500_charger sub-class */
|
||||
di->ac_chg.ops.enable = &ab8500_charger_ac_en;
|
||||
di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
|
||||
|
@ -2597,8 +2603,8 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
di->usb_chg.psy.properties = ab8500_charger_usb_props;
|
||||
di->usb_chg.psy.num_properties = ARRAY_SIZE(ab8500_charger_usb_props);
|
||||
di->usb_chg.psy.get_property = ab8500_charger_usb_get_property;
|
||||
di->usb_chg.psy.supplied_to = di->pdata->supplied_to;
|
||||
di->usb_chg.psy.num_supplicants = di->pdata->num_supplicants;
|
||||
di->usb_chg.psy.supplied_to = supply_interface;
|
||||
di->usb_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
|
||||
/* ux500_charger sub-class */
|
||||
di->usb_chg.ops.enable = &ab8500_charger_usb_en;
|
||||
di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
|
||||
|
@ -2614,8 +2620,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
|
|||
create_singlethread_workqueue("ab8500_charger_wq");
|
||||
if (di->charger_wq == NULL) {
|
||||
dev_err(di->dev, "failed to create work queue\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_device_info;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Init work for HW failure check */
|
||||
|
@ -2757,12 +2762,14 @@ free_regulator:
|
|||
regulator_put(di->regu);
|
||||
free_charger_wq:
|
||||
destroy_workqueue(di->charger_wq);
|
||||
free_device_info:
|
||||
kfree(di);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id ab8500_charger_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-charger", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver ab8500_charger_driver = {
|
||||
.probe = ab8500_charger_probe,
|
||||
.remove = ab8500_charger_remove,
|
||||
|
@ -2771,6 +2778,7 @@ static struct platform_driver ab8500_charger_driver = {
|
|||
.driver = {
|
||||
.name = "ab8500-charger",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ab8500_charger_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -22,15 +22,16 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
|
||||
#define MILLI_TO_MICRO 1000
|
||||
#define FG_LSB_IN_MA 1627
|
||||
|
@ -172,7 +173,6 @@ struct inst_curr_result_list {
|
|||
* @avg_cap: Average capacity filter
|
||||
* @parent: Pointer to the struct ab8500
|
||||
* @gpadc: Pointer to the struct gpadc
|
||||
* @pdata: Pointer to the abx500_fg platform data
|
||||
* @bat: Pointer to the abx500_bm platform data
|
||||
* @fg_psy: Structure that holds the FG specific battery properties
|
||||
* @fg_wq: Work queue for running the FG algorithm
|
||||
|
@ -212,7 +212,6 @@ struct ab8500_fg {
|
|||
struct ab8500_fg_avg_cap avg_cap;
|
||||
struct ab8500 *parent;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct abx500_fg_platform_data *pdata;
|
||||
struct abx500_bm_data *bat;
|
||||
struct power_supply fg_psy;
|
||||
struct workqueue_struct *fg_wq;
|
||||
|
@ -2429,7 +2428,6 @@ static int ab8500_fg_remove(struct platform_device *pdev)
|
|||
flush_scheduled_work();
|
||||
power_supply_unregister(&di->fg_psy);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(di);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2442,21 +2440,39 @@ static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
|
|||
{"CCEOC", ab8500_fg_cc_data_end_handler},
|
||||
};
|
||||
|
||||
static char *supply_interface[] = {
|
||||
"ab8500_chargalg",
|
||||
"ab8500_usb",
|
||||
};
|
||||
|
||||
static int ab8500_fg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ab8500_fg *di;
|
||||
int i, irq;
|
||||
int ret = 0;
|
||||
struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
|
||||
struct ab8500_fg *di;
|
||||
|
||||
if (!plat_data) {
|
||||
dev_err(&pdev->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
di->bat = pdev->mfd_cell->platform_data;
|
||||
if (!di->bat) {
|
||||
if (np) {
|
||||
ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get battery information\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "missing dt node for ab8500_fg\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
dev_info(&pdev->dev, "falling back to legacy platform data\n");
|
||||
}
|
||||
|
||||
mutex_init(&di->cc_lock);
|
||||
|
||||
|
@ -2465,29 +2481,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
di->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
|
||||
/* get fg specific platform data */
|
||||
di->pdata = plat_data->fg;
|
||||
if (!di->pdata) {
|
||||
dev_err(di->dev, "no fg platform data supplied\n");
|
||||
ret = -EINVAL;
|
||||
goto free_device_info;
|
||||
}
|
||||
|
||||
/* get battery specific platform data */
|
||||
di->bat = plat_data->battery;
|
||||
if (!di->bat) {
|
||||
dev_err(di->dev, "no battery platform data supplied\n");
|
||||
ret = -EINVAL;
|
||||
goto free_device_info;
|
||||
}
|
||||
|
||||
di->fg_psy.name = "ab8500_fg";
|
||||
di->fg_psy.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
di->fg_psy.properties = ab8500_fg_props;
|
||||
di->fg_psy.num_properties = ARRAY_SIZE(ab8500_fg_props);
|
||||
di->fg_psy.get_property = ab8500_fg_get_property;
|
||||
di->fg_psy.supplied_to = di->pdata->supplied_to;
|
||||
di->fg_psy.num_supplicants = di->pdata->num_supplicants;
|
||||
di->fg_psy.supplied_to = supply_interface;
|
||||
di->fg_psy.num_supplicants = ARRAY_SIZE(supply_interface),
|
||||
di->fg_psy.external_power_changed = ab8500_fg_external_power_changed;
|
||||
|
||||
di->bat_cap.max_mah_design = MILLI_TO_MICRO *
|
||||
|
@ -2506,8 +2506,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
|
|||
di->fg_wq = create_singlethread_workqueue("ab8500_fg_wq");
|
||||
if (di->fg_wq == NULL) {
|
||||
dev_err(di->dev, "failed to create work queue\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_device_info;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Init work for running the fg algorithm instantly */
|
||||
|
@ -2606,12 +2605,14 @@ free_irq:
|
|||
}
|
||||
free_inst_curr_wq:
|
||||
destroy_workqueue(di->fg_wq);
|
||||
free_device_info:
|
||||
kfree(di);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id ab8500_fg_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-fg", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver ab8500_fg_driver = {
|
||||
.probe = ab8500_fg_probe,
|
||||
.remove = ab8500_fg_remove,
|
||||
|
@ -2620,6 +2621,7 @@ static struct platform_driver ab8500_fg_driver = {
|
|||
.driver = {
|
||||
.name = "ab8500-fg",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ab8500_fg_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <linux/completion.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ux500_chargalg.h>
|
||||
#include <linux/mfd/abx500/ab8500-bm.h>
|
||||
|
@ -205,7 +207,6 @@ enum maxim_ret {
|
|||
* @chg_info: information about connected charger types
|
||||
* @batt_data: data of the battery
|
||||
* @susp_status: current charger suspension status
|
||||
* @pdata: pointer to the abx500_chargalg platform data
|
||||
* @bat: pointer to the abx500_bm platform data
|
||||
* @chargalg_psy: structure that holds the battery properties exposed by
|
||||
* the charging algorithm
|
||||
|
@ -231,7 +232,6 @@ struct abx500_chargalg {
|
|||
struct abx500_chargalg_charger_info chg_info;
|
||||
struct abx500_chargalg_battery_data batt_data;
|
||||
struct abx500_chargalg_suspension_status susp_status;
|
||||
struct abx500_chargalg_platform_data *pdata;
|
||||
struct abx500_bm_data *bat;
|
||||
struct power_supply chargalg_psy;
|
||||
struct ux500_charger *ac_chg;
|
||||
|
@ -1795,36 +1795,53 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
|
|||
flush_scheduled_work();
|
||||
power_supply_unregister(&di->chargalg_psy);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *supply_interface[] = {
|
||||
"ab8500_fg",
|
||||
};
|
||||
|
||||
static int abx500_chargalg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct abx500_bm_plat_data *plat_data;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct abx500_chargalg *di;
|
||||
int ret = 0;
|
||||
|
||||
struct abx500_chargalg *di =
|
||||
kzalloc(sizeof(struct abx500_chargalg), GFP_KERNEL);
|
||||
if (!di)
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di) {
|
||||
dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
di->bat = pdev->mfd_cell->platform_data;
|
||||
if (!di->bat) {
|
||||
if (np) {
|
||||
ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get battery information\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "missing dt node for ab8500_chargalg\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
dev_info(&pdev->dev, "falling back to legacy platform data\n");
|
||||
}
|
||||
|
||||
/* get device struct */
|
||||
di->dev = &pdev->dev;
|
||||
|
||||
plat_data = pdev->dev.platform_data;
|
||||
di->pdata = plat_data->chargalg;
|
||||
di->bat = plat_data->battery;
|
||||
|
||||
/* chargalg supply */
|
||||
di->chargalg_psy.name = "abx500_chargalg";
|
||||
di->chargalg_psy.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
di->chargalg_psy.properties = abx500_chargalg_props;
|
||||
di->chargalg_psy.num_properties = ARRAY_SIZE(abx500_chargalg_props);
|
||||
di->chargalg_psy.get_property = abx500_chargalg_get_property;
|
||||
di->chargalg_psy.supplied_to = di->pdata->supplied_to;
|
||||
di->chargalg_psy.num_supplicants = di->pdata->num_supplicants;
|
||||
di->chargalg_psy.supplied_to = supply_interface;
|
||||
di->chargalg_psy.num_supplicants = ARRAY_SIZE(supply_interface),
|
||||
di->chargalg_psy.external_power_changed =
|
||||
abx500_chargalg_external_power_changed;
|
||||
|
||||
|
@ -1844,7 +1861,7 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
|
|||
create_singlethread_workqueue("abx500_chargalg_wq");
|
||||
if (di->chargalg_wq == NULL) {
|
||||
dev_err(di->dev, "failed to create work queue\n");
|
||||
goto free_device_info;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Init work for chargalg */
|
||||
|
@ -1885,20 +1902,23 @@ free_psy:
|
|||
power_supply_unregister(&di->chargalg_psy);
|
||||
free_chargalg_wq:
|
||||
destroy_workqueue(di->chargalg_wq);
|
||||
free_device_info:
|
||||
kfree(di);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id ab8500_chargalg_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-chargalg", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver abx500_chargalg_driver = {
|
||||
.probe = abx500_chargalg_probe,
|
||||
.remove = abx500_chargalg_remove,
|
||||
.suspend = abx500_chargalg_suspend,
|
||||
.resume = abx500_chargalg_resume,
|
||||
.driver = {
|
||||
.name = "abx500-chargalg",
|
||||
.name = "ab8500-chargalg",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ab8500_chargalg_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -230,6 +230,14 @@ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg)
|
|||
*/
|
||||
static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di)
|
||||
{
|
||||
int flags;
|
||||
bool is_bq27500 = di->chip == BQ27500;
|
||||
bool is_higher = bq27xxx_is_chip_version_higher(di);
|
||||
|
||||
flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500);
|
||||
if (flags >= 0 && !is_higher && (flags & BQ27000_FLAG_CI))
|
||||
return -ENODATA;
|
||||
|
||||
return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,13 +80,13 @@ static inline int ds278x_read_reg16(struct ds278x_info *info, int reg_msb,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = swab16(i2c_smbus_read_word_data(info->client, reg_msb));
|
||||
ret = i2c_smbus_read_word_data(info->client, reg_msb);
|
||||
if (ret < 0) {
|
||||
dev_err(&info->client->dev, "register read failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = ret;
|
||||
*val = swab16(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -279,7 +279,8 @@ static int gab_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
memcpy(psy->properties, gab_props, sizeof(gab_props));
|
||||
properties = psy->properties + sizeof(gab_props);
|
||||
properties = (enum power_supply_property *)
|
||||
((char *)psy->properties + sizeof(gab_props));
|
||||
|
||||
/*
|
||||
* getting channel from iio and copying the battery properties
|
||||
|
@ -327,7 +328,7 @@ static int gab_probe(struct platform_device *pdev)
|
|||
ret = request_any_context_irq(irq, gab_charged,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"battery charged", adc_bat);
|
||||
if (ret)
|
||||
if (ret < 0)
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ struct jz_battery {
|
|||
struct jz_battery_platform_data *pdata;
|
||||
struct platform_device *pdev;
|
||||
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
|
||||
int irq;
|
||||
|
@ -244,13 +243,14 @@ static int jz_battery_probe(struct platform_device *pdev)
|
|||
struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data;
|
||||
struct jz_battery *jz_battery;
|
||||
struct power_supply *battery;
|
||||
struct resource *mem;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform_data supplied\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
|
||||
jz_battery = devm_kzalloc(&pdev->dev, sizeof(*jz_battery), GFP_KERNEL);
|
||||
if (!jz_battery) {
|
||||
dev_err(&pdev->dev, "Failed to allocate driver structure\n");
|
||||
return -ENOMEM;
|
||||
|
@ -260,33 +260,15 @@ static int jz_battery_probe(struct platform_device *pdev)
|
|||
|
||||
jz_battery->irq = platform_get_irq(pdev, 0);
|
||||
if (jz_battery->irq < 0) {
|
||||
ret = jz_battery->irq;
|
||||
dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
|
||||
goto err_free;
|
||||
return jz_battery->irq;
|
||||
}
|
||||
|
||||
jz_battery->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!jz_battery->mem) {
|
||||
ret = -ENOENT;
|
||||
dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
|
||||
goto err_free;
|
||||
}
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
jz_battery->mem = request_mem_region(jz_battery->mem->start,
|
||||
resource_size(jz_battery->mem), pdev->name);
|
||||
if (!jz_battery->mem) {
|
||||
ret = -EBUSY;
|
||||
dev_err(&pdev->dev, "Failed to request mmio memory region\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
jz_battery->base = ioremap_nocache(jz_battery->mem->start,
|
||||
resource_size(jz_battery->mem));
|
||||
if (!jz_battery->base) {
|
||||
ret = -EBUSY;
|
||||
dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
|
||||
goto err_release_mem_region;
|
||||
}
|
||||
jz_battery->base = devm_request_and_ioremap(&pdev->dev, mem);
|
||||
if (!jz_battery->base)
|
||||
return -EBUSY;
|
||||
|
||||
battery = &jz_battery->battery;
|
||||
battery->name = pdata->info.name;
|
||||
|
@ -309,7 +291,7 @@ static int jz_battery_probe(struct platform_device *pdev)
|
|||
jz_battery);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
|
||||
goto err_iounmap;
|
||||
goto err;
|
||||
}
|
||||
disable_irq(jz_battery->irq);
|
||||
|
||||
|
@ -366,13 +348,8 @@ err_free_gpio:
|
|||
gpio_free(jz_battery->pdata->gpio_charge);
|
||||
err_free_irq:
|
||||
free_irq(jz_battery->irq, jz_battery);
|
||||
err_iounmap:
|
||||
err:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
iounmap(jz_battery->base);
|
||||
err_release_mem_region:
|
||||
release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
|
||||
err_free:
|
||||
kfree(jz_battery);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -392,10 +369,6 @@ static int jz_battery_remove(struct platform_device *pdev)
|
|||
|
||||
free_irq(jz_battery->irq, jz_battery);
|
||||
|
||||
iounmap(jz_battery->base);
|
||||
release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
|
||||
kfree(jz_battery);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -235,25 +235,14 @@ static int lp8788_get_battery_present(struct lp8788_charger *pchg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_get_vbatt_adc(struct lp8788_charger *pchg,
|
||||
unsigned int *result)
|
||||
static int lp8788_get_vbatt_adc(struct lp8788_charger *pchg, int *result)
|
||||
{
|
||||
struct iio_channel *channel = pchg->chan[LP8788_VBATT];
|
||||
int scaleint;
|
||||
int scalepart;
|
||||
int ret;
|
||||
|
||||
if (!channel)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_read_channel_scale(channel, &scaleint, &scalepart);
|
||||
if (ret != IIO_VAL_INT_PLUS_MICRO)
|
||||
return -EINVAL;
|
||||
|
||||
/* unit: mV */
|
||||
*result = (scaleint + scalepart * 1000000) / 1000;
|
||||
|
||||
return 0;
|
||||
return iio_read_channel_processed(channel, result);
|
||||
}
|
||||
|
||||
static int lp8788_get_battery_voltage(struct lp8788_charger *pchg,
|
||||
|
@ -268,7 +257,7 @@ static int lp8788_get_battery_capacity(struct lp8788_charger *pchg,
|
|||
struct lp8788 *lp = pchg->lp;
|
||||
struct lp8788_charger_platform_data *pdata = pchg->pdata;
|
||||
unsigned int max_vbatt;
|
||||
unsigned int vbatt;
|
||||
int vbatt;
|
||||
enum lp8788_charging_state state;
|
||||
u8 data;
|
||||
int ret;
|
||||
|
@ -304,19 +293,18 @@ static int lp8788_get_battery_temperature(struct lp8788_charger *pchg,
|
|||
union power_supply_propval *val)
|
||||
{
|
||||
struct iio_channel *channel = pchg->chan[LP8788_BATT_TEMP];
|
||||
int scaleint;
|
||||
int scalepart;
|
||||
int result;
|
||||
int ret;
|
||||
|
||||
if (!channel)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_read_channel_scale(channel, &scaleint, &scalepart);
|
||||
if (ret != IIO_VAL_INT_PLUS_MICRO)
|
||||
ret = iio_read_channel_processed(channel, &result);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* unit: 0.1 'C */
|
||||
val->intval = (scaleint + scalepart * 1000000) / 100;
|
||||
val->intval = result * 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -592,53 +580,22 @@ static void lp8788_irq_unregister(struct platform_device *pdev,
|
|||
}
|
||||
}
|
||||
|
||||
static void lp8788_setup_adc_channel(struct lp8788_charger *pchg)
|
||||
static void lp8788_setup_adc_channel(const char *consumer_name,
|
||||
struct lp8788_charger *pchg)
|
||||
{
|
||||
struct lp8788_charger_platform_data *pdata = pchg->pdata;
|
||||
struct device *dev = pchg->lp->dev;
|
||||
struct iio_channel *chan;
|
||||
enum lp8788_adc_id id;
|
||||
const char *chan_name[LPADC_MAX] = {
|
||||
[LPADC_VBATT_5P5] = "vbatt-5p5",
|
||||
[LPADC_VBATT_6P0] = "vbatt-6p0",
|
||||
[LPADC_VBATT_5P0] = "vbatt-5p0",
|
||||
[LPADC_ADC1] = "adc1",
|
||||
[LPADC_ADC2] = "adc2",
|
||||
[LPADC_ADC3] = "adc3",
|
||||
[LPADC_ADC4] = "adc4",
|
||||
};
|
||||
|
||||
if (!pdata)
|
||||
return;
|
||||
|
||||
id = pdata->vbatt_adc;
|
||||
switch (id) {
|
||||
case LPADC_VBATT_5P5:
|
||||
case LPADC_VBATT_6P0:
|
||||
case LPADC_VBATT_5P0:
|
||||
chan = iio_channel_get(NULL, chan_name[id]);
|
||||
pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid ADC id for VBATT: %d\n", id);
|
||||
pchg->chan[LP8788_VBATT] = NULL;
|
||||
break;
|
||||
}
|
||||
/* ADC channel for battery voltage */
|
||||
chan = iio_channel_get(consumer_name, pdata->adc_vbatt);
|
||||
pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan;
|
||||
|
||||
id = pdata->batt_temp_adc;
|
||||
switch (id) {
|
||||
case LPADC_ADC1:
|
||||
case LPADC_ADC2:
|
||||
case LPADC_ADC3:
|
||||
case LPADC_ADC4:
|
||||
chan = iio_channel_get(NULL, chan_name[id]);
|
||||
pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid ADC id for BATT_TEMP : %d\n", id);
|
||||
pchg->chan[LP8788_BATT_TEMP] = NULL;
|
||||
break;
|
||||
}
|
||||
/* ADC channel for battery temperature */
|
||||
chan = iio_channel_get(consumer_name, pdata->adc_batt_temp);
|
||||
pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan;
|
||||
}
|
||||
|
||||
static void lp8788_release_adc_channel(struct lp8788_charger *pchg)
|
||||
|
@ -747,7 +704,7 @@ static int lp8788_charger_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
lp8788_setup_adc_channel(pchg);
|
||||
lp8788_setup_adc_channel(pdev->name, pchg);
|
||||
|
||||
ret = lp8788_psy_register(pdev, pchg);
|
||||
if (ret)
|
||||
|
|
|
@ -572,7 +572,8 @@ static int max17042_init_chip(struct max17042_chip *chip)
|
|||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
max17042_verify_model_lock(chip);
|
||||
|
||||
ret = max17042_verify_model_lock(chip);
|
||||
if (ret) {
|
||||
dev_err(&chip->client->dev, "%s lock verify failed\n",
|
||||
__func__);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -426,6 +427,54 @@ static int max8925_deinit_charger(struct max8925_power_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct max8925_power_pdata *
|
||||
max8925_power_dt_init(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *nproot = pdev->dev.parent->of_node;
|
||||
struct device_node *np;
|
||||
int batt_detect;
|
||||
int topoff_threshold;
|
||||
int fast_charge;
|
||||
int no_temp_support;
|
||||
int no_insert_detect;
|
||||
struct max8925_power_pdata *pdata;
|
||||
|
||||
if (!nproot)
|
||||
return pdev->dev.platform_data;
|
||||
|
||||
np = of_find_node_by_name(nproot, "charger");
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "failed to find charger node\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct max8925_power_pdata),
|
||||
GFP_KERNEL);
|
||||
|
||||
of_property_read_u32(np, "topoff-threshold", &topoff_threshold);
|
||||
of_property_read_u32(np, "batt-detect", &batt_detect);
|
||||
of_property_read_u32(np, "fast-charge", &fast_charge);
|
||||
of_property_read_u32(np, "no-insert-detect", &no_insert_detect);
|
||||
of_property_read_u32(np, "no-temp-support", &no_temp_support);
|
||||
|
||||
pdata->batt_detect = batt_detect;
|
||||
pdata->fast_charge = fast_charge;
|
||||
pdata->topoff_threshold = topoff_threshold;
|
||||
pdata->no_insert_detect = no_insert_detect;
|
||||
pdata->no_temp_support = no_temp_support;
|
||||
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
static struct max8925_power_pdata *
|
||||
max8925_power_dt_init(struct platform_device *pdev)
|
||||
{
|
||||
return pdev->dev.platform_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int max8925_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -433,7 +482,7 @@ static int max8925_power_probe(struct platform_device *pdev)
|
|||
struct max8925_power_info *info;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
pdata = max8925_power_dt_init(pdev);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "platform data isn't assigned to "
|
||||
"power supply\n");
|
||||
|
|
|
@ -216,6 +216,86 @@ static void psy_unregister_thermal(struct power_supply *psy)
|
|||
return;
|
||||
thermal_zone_device_unregister(psy->tzd);
|
||||
}
|
||||
|
||||
/* thermal cooling device callbacks */
|
||||
static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct power_supply *psy;
|
||||
union power_supply_propval val;
|
||||
int ret;
|
||||
|
||||
psy = tcd->devdata;
|
||||
ret = psy->get_property(psy,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
|
||||
if (!ret)
|
||||
*state = val.intval;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct power_supply *psy;
|
||||
union power_supply_propval val;
|
||||
int ret;
|
||||
|
||||
psy = tcd->devdata;
|
||||
ret = psy->get_property(psy,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
|
||||
if (!ret)
|
||||
*state = val.intval;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
|
||||
unsigned long state)
|
||||
{
|
||||
struct power_supply *psy;
|
||||
union power_supply_propval val;
|
||||
int ret;
|
||||
|
||||
psy = tcd->devdata;
|
||||
val.intval = state;
|
||||
ret = psy->set_property(psy,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device_ops psy_tcd_ops = {
|
||||
.get_max_state = ps_get_max_charge_cntl_limit,
|
||||
.get_cur_state = ps_get_cur_chrage_cntl_limit,
|
||||
.set_cur_state = ps_set_cur_charge_cntl_limit,
|
||||
};
|
||||
|
||||
static int psy_register_cooler(struct power_supply *psy)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Register for cooling device if psy can control charging */
|
||||
for (i = 0; i < psy->num_properties; i++) {
|
||||
if (psy->properties[i] ==
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) {
|
||||
psy->tcd = thermal_cooling_device_register(
|
||||
(char *)psy->name,
|
||||
psy, &psy_tcd_ops);
|
||||
if (IS_ERR(psy->tcd))
|
||||
return PTR_ERR(psy->tcd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psy_unregister_cooler(struct power_supply *psy)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(psy->tcd))
|
||||
return;
|
||||
thermal_cooling_device_unregister(psy->tcd);
|
||||
}
|
||||
#else
|
||||
static int psy_register_thermal(struct power_supply *psy)
|
||||
{
|
||||
|
@ -225,6 +305,15 @@ static int psy_register_thermal(struct power_supply *psy)
|
|||
static void psy_unregister_thermal(struct power_supply *psy)
|
||||
{
|
||||
}
|
||||
|
||||
static int psy_register_cooler(struct power_supply *psy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psy_unregister_cooler(struct power_supply *psy)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int power_supply_register(struct device *parent, struct power_supply *psy)
|
||||
|
@ -259,6 +348,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
|
|||
if (rc)
|
||||
goto register_thermal_failed;
|
||||
|
||||
rc = psy_register_cooler(psy);
|
||||
if (rc)
|
||||
goto register_cooler_failed;
|
||||
|
||||
rc = power_supply_create_triggers(psy);
|
||||
if (rc)
|
||||
goto create_triggers_failed;
|
||||
|
@ -268,6 +361,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
|
|||
goto success;
|
||||
|
||||
create_triggers_failed:
|
||||
psy_unregister_cooler(psy);
|
||||
register_cooler_failed:
|
||||
psy_unregister_thermal(psy);
|
||||
register_thermal_failed:
|
||||
device_del(dev);
|
||||
|
@ -284,6 +379,7 @@ void power_supply_unregister(struct power_supply *psy)
|
|||
cancel_work_sync(&psy->changed_work);
|
||||
sysfs_remove_link(&psy->dev->kobj, "powers");
|
||||
power_supply_remove_triggers(psy);
|
||||
psy_unregister_cooler(psy);
|
||||
psy_unregister_thermal(psy);
|
||||
device_unregister(psy->dev);
|
||||
}
|
||||
|
|
|
@ -164,6 +164,8 @@ static struct device_attribute power_supply_attrs[] = {
|
|||
POWER_SUPPLY_ATTR(constant_charge_current_max),
|
||||
POWER_SUPPLY_ATTR(constant_charge_voltage),
|
||||
POWER_SUPPLY_ATTR(constant_charge_voltage_max),
|
||||
POWER_SUPPLY_ATTR(charge_control_limit),
|
||||
POWER_SUPPLY_ATTR(charge_control_limit_max),
|
||||
POWER_SUPPLY_ATTR(energy_full_design),
|
||||
POWER_SUPPLY_ATTR(energy_empty_design),
|
||||
POWER_SUPPLY_ATTR(energy_full),
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Nokia RX-51 battery driver
|
||||
*
|
||||
* Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c/twl4030-madc.h>
|
||||
|
||||
struct rx51_device_info {
|
||||
struct device *dev;
|
||||
struct power_supply bat;
|
||||
};
|
||||
|
||||
/*
|
||||
* Read ADCIN channel value, code copied from maemo kernel
|
||||
*/
|
||||
static int rx51_battery_read_adc(int channel)
|
||||
{
|
||||
struct twl4030_madc_request req;
|
||||
|
||||
req.channels = 1 << channel;
|
||||
req.do_avg = 1;
|
||||
req.method = TWL4030_MADC_SW1;
|
||||
req.func_cb = NULL;
|
||||
req.type = TWL4030_MADC_WAIT;
|
||||
|
||||
if (twl4030_madc_conversion(&req) <= 0)
|
||||
return -ENODATA;
|
||||
|
||||
return req.rbuf[channel];
|
||||
}
|
||||
|
||||
/*
|
||||
* Read ADCIN channel 12 (voltage) and convert RAW value to micro voltage
|
||||
* This conversion formula was extracted from maemo program bsi-read
|
||||
*/
|
||||
static int rx51_battery_read_voltage(struct rx51_device_info *di)
|
||||
{
|
||||
int voltage = rx51_battery_read_adc(12);
|
||||
|
||||
if (voltage < 0)
|
||||
return voltage;
|
||||
|
||||
return 1000 * (10000 * voltage / 1705);
|
||||
}
|
||||
|
||||
/*
|
||||
* Temperature look-up tables
|
||||
* TEMP = (1/(t1 + 1/298) - 273.15)
|
||||
* Where t1 = (1/B) * ln((RAW_ADC_U * 2.5)/(R * I * 255))
|
||||
* Formula is based on experimental data, RX-51 CAL data, maemo program bme
|
||||
* and formula from da9052 driver with values R = 100, B = 3380, I = 0.00671
|
||||
*/
|
||||
|
||||
/*
|
||||
* Table1 (temperature for first 25 RAW values)
|
||||
* Usage: TEMP = rx51_temp_table1[RAW]
|
||||
* RAW is between 1 and 24
|
||||
* TEMP is between 201 C and 55 C
|
||||
*/
|
||||
static u8 rx51_temp_table1[] = {
|
||||
255, 201, 159, 138, 124, 114, 106, 99, 94, 89, 85, 82, 78, 75,
|
||||
73, 70, 68, 66, 64, 62, 61, 59, 57, 56, 55
|
||||
};
|
||||
|
||||
/*
|
||||
* Table2 (lowest RAW value for temperature)
|
||||
* Usage: RAW = rx51_temp_table2[TEMP-rx51_temp_table2_first]
|
||||
* TEMP is between 53 C and -32 C
|
||||
* RAW is between 25 and 993
|
||||
*/
|
||||
#define rx51_temp_table2_first 53
|
||||
static u16 rx51_temp_table2[] = {
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39,
|
||||
40, 41, 43, 44, 46, 48, 49, 51, 53, 55, 57, 59, 61, 64,
|
||||
66, 69, 71, 74, 77, 80, 83, 86, 90, 94, 97, 101, 106, 110,
|
||||
115, 119, 125, 130, 136, 141, 148, 154, 161, 168, 176, 184, 202, 211,
|
||||
221, 231, 242, 254, 266, 279, 293, 308, 323, 340, 357, 375, 395, 415,
|
||||
437, 460, 485, 511, 539, 568, 600, 633, 669, 706, 747, 790, 836, 885,
|
||||
937, 993, 1024
|
||||
};
|
||||
|
||||
/*
|
||||
* Read ADCIN channel 0 (battery temp) and convert value to tenths of Celsius
|
||||
* Use Temperature look-up tables for conversation
|
||||
*/
|
||||
static int rx51_battery_read_temperature(struct rx51_device_info *di)
|
||||
{
|
||||
int min = 0;
|
||||
int max = ARRAY_SIZE(rx51_temp_table2) - 1;
|
||||
int raw = rx51_battery_read_adc(0);
|
||||
|
||||
/* Zero and negative values are undefined */
|
||||
if (raw <= 0)
|
||||
return INT_MAX;
|
||||
|
||||
/* ADC channels are 10 bit, higher value are undefined */
|
||||
if (raw >= (1 << 10))
|
||||
return INT_MIN;
|
||||
|
||||
/* First check for temperature in first direct table */
|
||||
if (raw < ARRAY_SIZE(rx51_temp_table1))
|
||||
return rx51_temp_table1[raw] * 100;
|
||||
|
||||
/* Binary search RAW value in second inverse table */
|
||||
while (max - min > 1) {
|
||||
int mid = (max + min) / 2;
|
||||
if (rx51_temp_table2[mid] <= raw)
|
||||
min = mid;
|
||||
else if (rx51_temp_table2[mid] > raw)
|
||||
max = mid;
|
||||
if (rx51_temp_table2[mid] == raw)
|
||||
break;
|
||||
}
|
||||
|
||||
return (rx51_temp_table2_first - min) * 100;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read ADCIN channel 4 (BSI) and convert RAW value to micro Ah
|
||||
* This conversion formula was extracted from maemo program bsi-read
|
||||
*/
|
||||
static int rx51_battery_read_capacity(struct rx51_device_info *di)
|
||||
{
|
||||
int capacity = rx51_battery_read_adc(4);
|
||||
|
||||
if (capacity < 0)
|
||||
return capacity;
|
||||
|
||||
return 1280 * (1200 * capacity)/(1024 - capacity);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return power_supply property
|
||||
*/
|
||||
static int rx51_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct rx51_device_info *di = container_of((psy),
|
||||
struct rx51_device_info, bat);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
|
||||
val->intval = 4200000;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = rx51_battery_read_voltage(di) ? 1 : 0;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = rx51_battery_read_voltage(di);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
val->intval = rx51_battery_read_temperature(di);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
|
||||
val->intval = rx51_battery_read_capacity(di);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (val->intval == INT_MAX || val->intval == INT_MIN)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum power_supply_property rx51_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
};
|
||||
|
||||
static int __devinit rx51_battery_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rx51_device_info *di;
|
||||
int ret;
|
||||
|
||||
di = kzalloc(sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, di);
|
||||
|
||||
di->bat.name = dev_name(&pdev->dev);
|
||||
di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
di->bat.properties = rx51_battery_props;
|
||||
di->bat.num_properties = ARRAY_SIZE(rx51_battery_props);
|
||||
di->bat.get_property = rx51_battery_get_property;
|
||||
|
||||
ret = power_supply_register(di->dev, &di->bat);
|
||||
if (ret) {
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(di);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit rx51_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rx51_device_info *di = platform_get_drvdata(pdev);
|
||||
|
||||
power_supply_unregister(&di->bat);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rx51_battery_driver = {
|
||||
.probe = rx51_battery_probe,
|
||||
.remove = __devexit_p(rx51_battery_remove),
|
||||
.driver = {
|
||||
.name = "rx51-battery",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
module_platform_driver(rx51_battery_driver);
|
||||
|
||||
MODULE_ALIAS("platform:rx51-battery");
|
||||
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
|
||||
MODULE_DESCRIPTION("Nokia RX-51 battery driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -114,12 +114,12 @@ static int twl4030_clear_set(u8 mod_no, u8 clear, u8 set, u8 reg)
|
|||
|
||||
static int twl4030_bci_read(u8 reg, u8 *val)
|
||||
{
|
||||
return twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, val, reg);
|
||||
return twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, val, reg);
|
||||
}
|
||||
|
||||
static int twl4030_clear_set_boot_bci(u8 clear, u8 set)
|
||||
{
|
||||
return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, clear,
|
||||
return twl4030_clear_set(TWL_MODULE_PM_MASTER, clear,
|
||||
TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set,
|
||||
TWL4030_PM_MASTER_BOOT_BCI);
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
|
|||
int ret;
|
||||
u8 hwsts;
|
||||
|
||||
ret = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
|
||||
ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &hwsts,
|
||||
TWL4030_PM_MASTER_STS_HW_CONDITIONS);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
@ -199,7 +199,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
|
|||
return ret;
|
||||
|
||||
/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
|
||||
ret = twl4030_clear_set(TWL4030_MODULE_MAIN_CHARGE, 0,
|
||||
ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
|
||||
TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
|
||||
} else {
|
||||
ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
|
||||
|
@ -238,7 +238,7 @@ static int twl4030_charger_enable_backup(int uvolt, int uamp)
|
|||
if (uvolt < 2500000 ||
|
||||
uamp < 25) {
|
||||
/* disable charging of backup battery */
|
||||
ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
|
||||
ret = twl4030_clear_set(TWL_MODULE_PM_RECEIVER,
|
||||
TWL4030_BBCHEN, 0, TWL4030_BB_CFG);
|
||||
return ret;
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ static int twl4030_charger_enable_backup(int uvolt, int uamp)
|
|||
else
|
||||
flags |= TWL4030_BBISEL_25uA;
|
||||
|
||||
ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
|
||||
ret = twl4030_clear_set(TWL_MODULE_PM_RECEIVER,
|
||||
TWL4030_BBSEL_MASK | TWL4030_BBISEL_MASK,
|
||||
flags,
|
||||
TWL4030_BB_CFG);
|
||||
|
|
|
@ -267,39 +267,21 @@ struct abx500_bm_data {
|
|||
int gnd_lift_resistance;
|
||||
const struct abx500_maxim_parameters *maxi;
|
||||
const struct abx500_bm_capacity_levels *cap_levels;
|
||||
const struct abx500_battery_type *bat_type;
|
||||
struct abx500_battery_type *bat_type;
|
||||
const struct abx500_bm_charger_parameters *chg_params;
|
||||
const struct abx500_fg_parameters *fg_params;
|
||||
};
|
||||
|
||||
struct abx500_chargalg_platform_data {
|
||||
char **supplied_to;
|
||||
size_t num_supplicants;
|
||||
extern struct abx500_bm_data ab8500_bm_data;
|
||||
|
||||
enum {
|
||||
NTC_EXTERNAL = 0,
|
||||
NTC_INTERNAL,
|
||||
};
|
||||
|
||||
struct abx500_charger_platform_data {
|
||||
char **supplied_to;
|
||||
size_t num_supplicants;
|
||||
bool autopower_cfg;
|
||||
};
|
||||
|
||||
struct abx500_btemp_platform_data {
|
||||
char **supplied_to;
|
||||
size_t num_supplicants;
|
||||
};
|
||||
|
||||
struct abx500_fg_platform_data {
|
||||
char **supplied_to;
|
||||
size_t num_supplicants;
|
||||
};
|
||||
|
||||
struct abx500_bm_plat_data {
|
||||
struct abx500_bm_data *battery;
|
||||
struct abx500_charger_platform_data *charger;
|
||||
struct abx500_btemp_platform_data *btemp;
|
||||
struct abx500_fg_platform_data *fg;
|
||||
struct abx500_chargalg_platform_data *chargalg;
|
||||
};
|
||||
int bmdevs_of_probe(struct device *dev,
|
||||
struct device_node *np,
|
||||
struct abx500_bm_data **battery);
|
||||
|
||||
int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
|
||||
u8 value);
|
||||
|
|
|
@ -211,16 +211,16 @@ struct lp8788_chg_param {
|
|||
|
||||
/*
|
||||
* struct lp8788_charger_platform_data
|
||||
* @vbatt_adc : adc selection id for battery voltage
|
||||
* @batt_temp_adc : adc selection id for battery temperature
|
||||
* @adc_vbatt : adc channel name for battery voltage
|
||||
* @adc_batt_temp : adc channel name for battery temperature
|
||||
* @max_vbatt_mv : used for calculating battery capacity
|
||||
* @chg_params : initial charging parameters
|
||||
* @num_chg_params : numbers of charging parameters
|
||||
* @charger_event : the charger event can be reported to the platform side
|
||||
*/
|
||||
struct lp8788_charger_platform_data {
|
||||
enum lp8788_adc_id vbatt_adc;
|
||||
enum lp8788_adc_id batt_temp_adc;
|
||||
const char *adc_vbatt;
|
||||
const char *adc_batt_temp;
|
||||
unsigned int max_vbatt_mv;
|
||||
struct lp8788_chg_param *chg_params;
|
||||
int num_chg_params;
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* bq2415x charger driver
|
||||
*
|
||||
* Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef BQ2415X_CHARGER_H
|
||||
#define BQ2415X_CHARGER_H
|
||||
|
||||
/*
|
||||
* This is platform data for bq2415x chip. It contains default board
|
||||
* voltages and currents which can be also later configured via sysfs. If
|
||||
* value is -1 then default chip value (specified in datasheet) will be
|
||||
* used.
|
||||
*
|
||||
* Value resistor_sense is needed for for configuring charge and
|
||||
* termination current. It it is less or equal to zero, configuring charge
|
||||
* and termination current will not be possible.
|
||||
*
|
||||
* Function set_mode_hook is needed for automode (setting correct current
|
||||
* limit when charger is connected/disconnected or setting boost mode).
|
||||
* When is NULL, automode function is disabled. When is not NULL, it must
|
||||
* have this prototype:
|
||||
*
|
||||
* int (*set_mode_hook)(
|
||||
* void (*hook)(enum bq2415x_mode mode, void *data),
|
||||
* void *data)
|
||||
*
|
||||
* hook is hook function (see below) and data is pointer to driver private
|
||||
* data
|
||||
*
|
||||
* bq2415x driver will call it as:
|
||||
*
|
||||
* platform_data->set_mode_hook(bq2415x_hook_function, bq2415x_device);
|
||||
*
|
||||
* Board/platform function set_mode_hook return non zero value when hook
|
||||
* function was successful registered. Platform code should call that hook
|
||||
* function (which get from pointer, with data) every time when charger
|
||||
* was connected/disconnected or require to enable boost mode. bq2415x
|
||||
* driver then will set correct current limit, enable/disable charger or
|
||||
* boost mode.
|
||||
*
|
||||
* Hook function has this prototype:
|
||||
*
|
||||
* void hook(enum bq2415x_mode mode, void *data);
|
||||
*
|
||||
* mode is bq2415x mode (charger or boost)
|
||||
* data is pointer to driver private data (which get from
|
||||
* set_charger_type_hook)
|
||||
*
|
||||
* When bq driver is being unloaded, it call function:
|
||||
*
|
||||
* platform_data->set_mode_hook(NULL, NULL);
|
||||
*
|
||||
* (hook function and driver private data are NULL)
|
||||
*
|
||||
* After that board/platform code must not call driver hook function! It
|
||||
* is possible that pointer to hook function will not be valid and calling
|
||||
* will cause undefined result.
|
||||
*/
|
||||
|
||||
/* Supported modes with maximal current limit */
|
||||
enum bq2415x_mode {
|
||||
BQ2415X_MODE_NONE, /* unknown or no charger (100mA) */
|
||||
BQ2415X_MODE_HOST_CHARGER, /* usb host/hub charger (500mA) */
|
||||
BQ2415X_MODE_DEDICATED_CHARGER, /* dedicated charger (unlimited) */
|
||||
BQ2415X_MODE_BOOST, /* boost mode (charging disabled) */
|
||||
};
|
||||
|
||||
struct bq2415x_platform_data {
|
||||
int current_limit; /* mA */
|
||||
int weak_battery_voltage; /* mV */
|
||||
int battery_regulation_voltage; /* mV */
|
||||
int charge_current; /* mA */
|
||||
int termination_current; /* mA */
|
||||
int resistor_sense; /* m ohm */
|
||||
int (*set_mode_hook)(void (*hook)(enum bq2415x_mode mode, void *data),
|
||||
void *data);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -114,6 +114,8 @@ enum power_supply_property {
|
|||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
|
||||
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL,
|
||||
|
@ -186,6 +188,7 @@ struct power_supply {
|
|||
struct work_struct changed_work;
|
||||
#ifdef CONFIG_THERMAL
|
||||
struct thermal_zone_device *tzd;
|
||||
struct thermal_cooling_device *tcd;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
|
|
Loading…
Reference in New Issue