mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6: (68 commits) power_supply: Mark da9052 driver as broken power_supply: Drop usage of nowarn variant of sysfs_create_link() s3c_adc_battery: Average over more than one adc sample power_supply: Add DA9052 battery driver isp1704_charger: Fix missing check jz4740-battery: Fix signedness bug power_supply: Assume mains power by default sbs-battery: Fix devicetree match table ARM: rx51: Add bq27200 i2c board info sbs-battery: Change power supply name devicetree-bindings: Propagate bq20z75->sbs rename to dt bindings devicetree-bindings: Add vendor entry for Smart Battery Systems sbs-battery: Rename internals to new name bq20z75: Rename to sbs-battery wm97xx_battery: Use DEFINE_MUTEX() for work_lock max8997_charger: Remove duplicate module.h lp8727_charger: Some minor fixes for the header lp8727_charger: Add header file power_supply: Convert drivers/power/* to use module_platform_driver() power_supply: Add "unknown" in power supply type ...
This commit is contained in:
commit
b24ca57e76
@ -0,0 +1,5 @@
|
||||
OLPC battery
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Required properties:
|
||||
- compatible : "olpc,xo1-battery"
|
@ -0,0 +1,23 @@
|
||||
SBS sbs-battery
|
||||
~~~~~~~~~~
|
||||
|
||||
Required properties :
|
||||
- compatible : "sbs,sbs-battery"
|
||||
|
||||
Optional properties :
|
||||
- sbs,i2c-retry-count : The number of times to retry i2c transactions on i2c
|
||||
IO failure.
|
||||
- sbs,poll-retry-count : The number of times to try looking for new status
|
||||
after an external change notification.
|
||||
- sbs,battery-detect-gpios : The gpio which signals battery detection and
|
||||
a flag specifying its polarity.
|
||||
|
||||
Example:
|
||||
|
||||
bq20z75@b {
|
||||
compatible = "sbs,sbs-battery";
|
||||
reg = < 0xb >;
|
||||
sbs,i2c-retry-count = <2>;
|
||||
sbs,poll-retry-count = <10>;
|
||||
sbs,battery-detect-gpios = <&gpio-controller 122 1>;
|
||||
}
|
@ -34,6 +34,7 @@ powervr Imagination Technologies
|
||||
qcom Qualcomm, Inc.
|
||||
ramtron Ramtron International
|
||||
samsung Samsung Semiconductor
|
||||
sbs Smart Battery System
|
||||
schindler Schindler
|
||||
sil Silicon Image
|
||||
simtek
|
||||
|
163
Documentation/power/charger-manager.txt
Normal file
163
Documentation/power/charger-manager.txt
Normal file
@ -0,0 +1,163 @@
|
||||
Charger Manager
|
||||
(C) 2011 MyungJoo Ham <myungjoo.ham@samsung.com>, GPL
|
||||
|
||||
Charger Manager provides in-kernel battery charger management that
|
||||
requires temperature monitoring during suspend-to-RAM state
|
||||
and where each battery may have multiple chargers attached and the userland
|
||||
wants to look at the aggregated information of the multiple chargers.
|
||||
|
||||
Charger Manager is a platform_driver with power-supply-class entries.
|
||||
An instance of Charger Manager (a platform-device created with Charger-Manager)
|
||||
represents an independent battery with chargers. If there are multiple
|
||||
batteries with their own chargers acting independently in a system,
|
||||
the system may need multiple instances of Charger Manager.
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
Charger Manager supports the following:
|
||||
|
||||
* Support for multiple chargers (e.g., a device with USB, AC, and solar panels)
|
||||
A system may have multiple chargers (or power sources) and some of
|
||||
they may be activated at the same time. Each charger may have its
|
||||
own power-supply-class and each power-supply-class can provide
|
||||
different information about the battery status. This framework
|
||||
aggregates charger-related information from multiple sources and
|
||||
shows combined information as a single power-supply-class.
|
||||
|
||||
* Support for in suspend-to-RAM polling (with suspend_again callback)
|
||||
While the battery is being charged and the system is in suspend-to-RAM,
|
||||
we may need to monitor the battery health by looking at the ambient or
|
||||
battery temperature. We can accomplish this by waking up the system
|
||||
periodically. However, such a method wakes up devices unncessary for
|
||||
monitoring the battery health and tasks, and user processes that are
|
||||
supposed to be kept suspended. That, in turn, incurs unnecessary power
|
||||
consumption and slow down charging process. Or even, such peak power
|
||||
consumption can stop chargers in the middle of charging
|
||||
(external power input < device power consumption), which not
|
||||
only affects the charging time, but the lifespan of the battery.
|
||||
|
||||
Charger Manager provides a function "cm_suspend_again" that can be
|
||||
used as suspend_again callback of platform_suspend_ops. If the platform
|
||||
requires tasks other than cm_suspend_again, it may implement its own
|
||||
suspend_again callback that calls cm_suspend_again in the middle.
|
||||
Normally, the platform will need to resume and suspend some devices
|
||||
that are used by Charger Manager.
|
||||
|
||||
2. Global Charger-Manager Data related with suspend_again
|
||||
========================================================
|
||||
In order to setup Charger Manager with suspend-again feature
|
||||
(in-suspend monitoring), the user should provide charger_global_desc
|
||||
with setup_charger_manager(struct charger_global_desc *).
|
||||
This charger_global_desc data for in-suspend monitoring is global
|
||||
as the name suggests. Thus, the user needs to provide only once even
|
||||
if there are multiple batteries. If there are multiple batteries, the
|
||||
multiple instances of Charger Manager share the same charger_global_desc
|
||||
and it will manage in-suspend monitoring for all instances of Charger Manager.
|
||||
|
||||
The user needs to provide all the two entries properly in order to activate
|
||||
in-suspend monitoring:
|
||||
|
||||
struct charger_global_desc {
|
||||
|
||||
char *rtc_name;
|
||||
: The name of rtc (e.g., "rtc0") used to wakeup the system from
|
||||
suspend for Charger Manager. The alarm interrupt (AIE) of the rtc
|
||||
should be able to wake up the system from suspend. Charger Manager
|
||||
saves and restores the alarm value and use the previously-defined
|
||||
alarm if it is going to go off earlier than Charger Manager so that
|
||||
Charger Manager does not interfere with previously-defined alarms.
|
||||
|
||||
bool (*rtc_only_wakeup)(void);
|
||||
: This callback should let CM know whether
|
||||
the wakeup-from-suspend is caused only by the alarm of "rtc" in the
|
||||
same struct. If there is any other wakeup source triggered the
|
||||
wakeup, it should return false. If the "rtc" is the only wakeup
|
||||
reason, it should return true.
|
||||
};
|
||||
|
||||
3. How to setup suspend_again
|
||||
=============================
|
||||
Charger Manager provides a function "extern bool cm_suspend_again(void)".
|
||||
When cm_suspend_again is called, it monitors every battery. The suspend_ops
|
||||
callback of the system's platform_suspend_ops can call cm_suspend_again
|
||||
function to know whether Charger Manager wants to suspend again or not.
|
||||
If there are no other devices or tasks that want to use suspend_again
|
||||
feature, the platform_suspend_ops may directly refer to cm_suspend_again
|
||||
for its suspend_again callback.
|
||||
|
||||
The cm_suspend_again() returns true (meaning "I want to suspend again")
|
||||
if the system was woken up by Charger Manager and the polling
|
||||
(in-suspend monitoring) results in "normal".
|
||||
|
||||
4. Charger-Manager Data (struct charger_desc)
|
||||
=============================================
|
||||
For each battery charged independently from other batteries (if a series of
|
||||
batteries are charged by a single charger, they are counted as one independent
|
||||
battery), an instance of Charger Manager is attached to it.
|
||||
|
||||
struct charger_desc {
|
||||
|
||||
char *psy_name;
|
||||
: The power-supply-class name of the battery. Default is
|
||||
"battery" if psy_name is NULL. Users can access the psy entries
|
||||
at "/sys/class/power_supply/[psy_name]/".
|
||||
|
||||
enum polling_modes polling_mode;
|
||||
: CM_POLL_DISABLE: do not poll this battery.
|
||||
CM_POLL_ALWAYS: always poll this battery.
|
||||
CM_POLL_EXTERNAL_POWER_ONLY: poll this battery if and only if
|
||||
an external power source is attached.
|
||||
CM_POLL_CHARGING_ONLY: poll this battery if and only if the
|
||||
battery is being charged.
|
||||
|
||||
unsigned int fullbatt_uV;
|
||||
: If specified with a non-zero value, Charger Manager assumes
|
||||
that the battery is full (capacity = 100) if the battery is not being
|
||||
charged and the battery voltage is equal to or greater than
|
||||
fullbatt_uV.
|
||||
|
||||
unsigned int polling_interval_ms;
|
||||
: Required polling interval in ms. Charger Manager will poll
|
||||
this battery every polling_interval_ms or more frequently.
|
||||
|
||||
enum data_source battery_present;
|
||||
CM_FUEL_GAUGE: get battery presence information from fuel gauge.
|
||||
CM_CHARGER_STAT: get battery presence from chargers.
|
||||
|
||||
char **psy_charger_stat;
|
||||
: An array ending with NULL that has power-supply-class names of
|
||||
chargers. Each power-supply-class should provide "PRESENT" (if
|
||||
battery_present is "CM_CHARGER_STAT"), "ONLINE" (shows whether an
|
||||
external power source is attached or not), and "STATUS" (shows whether
|
||||
the battery is {"FULL" or not FULL} or {"FULL", "Charging",
|
||||
"Discharging", "NotCharging"}).
|
||||
|
||||
int num_charger_regulators;
|
||||
struct regulator_bulk_data *charger_regulators;
|
||||
: Regulators representing the chargers in the form for
|
||||
regulator framework's bulk functions.
|
||||
|
||||
char *psy_fuel_gauge;
|
||||
: Power-supply-class name of the fuel gauge.
|
||||
|
||||
int (*temperature_out_of_range)(int *mC);
|
||||
bool measure_battery_temp;
|
||||
: This callback returns 0 if the temperature is safe for charging,
|
||||
a positive number if it is too hot to charge, and a negative number
|
||||
if it is too cold to charge. With the variable mC, the callback returns
|
||||
the temperature in 1/1000 of centigrade.
|
||||
The source of temperature can be battery or ambient one according to
|
||||
the value of measure_battery_temp.
|
||||
};
|
||||
|
||||
5. Other Considerations
|
||||
=======================
|
||||
|
||||
At the charger/battery-related events such as battery-pulled-out,
|
||||
charger-pulled-out, charger-inserted, DCIN-over/under-voltage, charger-stopped,
|
||||
and others critical to chargers, the system should be configured to wake up.
|
||||
At least the following should wake up the system from a suspend:
|
||||
a) charger-on/off b) external-power-in/out c) battery-in/out (while charging)
|
||||
|
||||
It is usually accomplished by configuring the PMIC as a wakeup source.
|
@ -944,6 +944,9 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
|
||||
.platform_data = &rx51_lp5523_platform_data,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
I2C_BOARD_INFO("bq27200", 0x55),
|
||||
},
|
||||
{
|
||||
I2C_BOARD_INFO("tpa6130a2", 0x60),
|
||||
.platform_data = &rx51_tpa6130a2_data,
|
||||
|
@ -49,12 +49,14 @@ static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
|
||||
|
||||
static enum power_supply_property wacom_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_CAPACITY
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
};
|
||||
|
||||
static enum power_supply_property wacom_ac_props[] = {
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_ONLINE
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
};
|
||||
|
||||
static int wacom_battery_get_property(struct power_supply *psy,
|
||||
@ -70,6 +72,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = 1;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SCOPE:
|
||||
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
/* show 100% battery capacity when charging */
|
||||
if (power_state == 0)
|
||||
@ -101,6 +106,9 @@ static int wacom_ac_get_property(struct power_supply *psy,
|
||||
else
|
||||
val->intval = 0;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SCOPE:
|
||||
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
@ -523,6 +531,8 @@ static int wacom_probe(struct hid_device *hdev,
|
||||
wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
wdata->battery.use_for_apm = 0;
|
||||
|
||||
power_supply_powers(&wdata->battery, &hdev->dev);
|
||||
|
||||
ret = power_supply_register(&hdev->dev, &wdata->battery);
|
||||
if (ret) {
|
||||
hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
|
||||
@ -537,6 +547,8 @@ static int wacom_probe(struct hid_device *hdev,
|
||||
wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
|
||||
wdata->ac.use_for_apm = 0;
|
||||
|
||||
power_supply_powers(&wdata->battery, &hdev->dev);
|
||||
|
||||
ret = power_supply_register(&hdev->dev, &wdata->ac);
|
||||
if (ret) {
|
||||
hid_warn(hdev,
|
||||
|
@ -52,7 +52,8 @@ static __u16 wiiproto_keymap[] = {
|
||||
};
|
||||
|
||||
static enum power_supply_property wiimote_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_CAPACITY
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
};
|
||||
|
||||
static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
|
||||
@ -402,6 +403,11 @@ static int wiimote_battery_get_property(struct power_supply *psy,
|
||||
int ret = 0, state;
|
||||
unsigned long flags;
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_SCOPE) {
|
||||
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = wiimote_cmd_acquire(wdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1220,6 +1226,8 @@ static int wiimote_hid_probe(struct hid_device *hdev,
|
||||
wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
wdata->battery.use_for_apm = 0;
|
||||
|
||||
power_supply_powers(&wdata->battery, &hdev->dev);
|
||||
|
||||
ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Cannot register battery device\n");
|
||||
|
@ -210,21 +210,6 @@ static struct max8925_irq_data max8925_irqs[] = {
|
||||
.mask_reg = MAX8925_CHG_IRQ1_MASK,
|
||||
.offs = 1 << 2,
|
||||
},
|
||||
[MAX8925_IRQ_VCHG_USB_OVP] = {
|
||||
.reg = MAX8925_CHG_IRQ1,
|
||||
.mask_reg = MAX8925_CHG_IRQ1_MASK,
|
||||
.offs = 1 << 3,
|
||||
},
|
||||
[MAX8925_IRQ_VCHG_USB_F] = {
|
||||
.reg = MAX8925_CHG_IRQ1,
|
||||
.mask_reg = MAX8925_CHG_IRQ1_MASK,
|
||||
.offs = 1 << 4,
|
||||
},
|
||||
[MAX8925_IRQ_VCHG_USB_R] = {
|
||||
.reg = MAX8925_CHG_IRQ1,
|
||||
.mask_reg = MAX8925_CHG_IRQ1_MASK,
|
||||
.offs = 1 << 5,
|
||||
},
|
||||
[MAX8925_IRQ_VCHG_THM_OK_R] = {
|
||||
.reg = MAX8925_CHG_IRQ2,
|
||||
.mask_reg = MAX8925_CHG_IRQ2_MASK,
|
||||
|
@ -116,12 +116,12 @@ config BATTERY_WM97XX
|
||||
help
|
||||
Say Y to enable support for battery measured by WM97xx aux port.
|
||||
|
||||
config BATTERY_BQ20Z75
|
||||
tristate "TI BQ20z75 gas gauge"
|
||||
config BATTERY_SBS
|
||||
tristate "SBS Compliant gas gauge"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y to include support for TI BQ20z75 SBS-compliant
|
||||
gas gauge and protection IC.
|
||||
Say Y to include support for SBS battery driver for SBS-compliant
|
||||
gas gauges.
|
||||
|
||||
config BATTERY_BQ27x00
|
||||
tristate "BQ27x00 battery driver"
|
||||
@ -150,6 +150,14 @@ config BATTERY_DA9030
|
||||
Say Y here to enable support for batteries charger integrated into
|
||||
DA9030 PMIC.
|
||||
|
||||
config BATTERY_DA9052
|
||||
tristate "Dialog DA9052 Battery"
|
||||
depends on PMIC_DA9052
|
||||
depends on BROKEN
|
||||
help
|
||||
Say Y here to enable support for batteries charger integrated into
|
||||
DA9052 PMIC.
|
||||
|
||||
config BATTERY_MAX17040
|
||||
tristate "Maxim MAX17040 Fuel Gauge"
|
||||
depends on I2C
|
||||
@ -226,6 +234,12 @@ config CHARGER_TWL4030
|
||||
help
|
||||
Say Y here to enable support for TWL4030 Battery Charge Interface.
|
||||
|
||||
config CHARGER_LP8727
|
||||
tristate "National Semiconductor LP8727 charger driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to enable support for LP8727 Charger Driver.
|
||||
|
||||
config CHARGER_GPIO
|
||||
tristate "GPIO charger"
|
||||
depends on GPIOLIB
|
||||
@ -236,6 +250,16 @@ config CHARGER_GPIO
|
||||
This driver can be build as a module. If so, the module will be
|
||||
called gpio-charger.
|
||||
|
||||
config CHARGER_MANAGER
|
||||
bool "Battery charger manager for multiple chargers"
|
||||
depends on REGULATOR && RTC_CLASS
|
||||
help
|
||||
Say Y to enable charger-manager support, which allows multiple
|
||||
chargers attached to a battery and multiple batteries attached to a
|
||||
system. The charger-manager also can monitor charging status in
|
||||
runtime and in suspend-to-RAM by waking up the system periodically
|
||||
with help of suspend_again support.
|
||||
|
||||
config CHARGER_MAX8997
|
||||
tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
|
||||
depends on MFD_MAX8997 && REGULATOR_MAX8997
|
||||
|
@ -22,9 +22,10 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
|
||||
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
|
||||
obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
|
||||
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
|
||||
obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
|
||||
obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
|
||||
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
|
||||
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
|
||||
obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
|
||||
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
|
||||
@ -35,6 +36,8 @@ obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
|
||||
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
|
||||
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
|
||||
obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
|
||||
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
|
||||
|
@ -54,13 +54,19 @@
|
||||
|
||||
#define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */
|
||||
#define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */
|
||||
#define BQ27000_FLAG_CHGS BIT(7)
|
||||
#define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */
|
||||
#define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */
|
||||
#define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */
|
||||
#define BQ27000_FLAG_FC BIT(5)
|
||||
#define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */
|
||||
|
||||
#define BQ27500_REG_SOC 0x2C
|
||||
#define BQ27500_REG_DCAP 0x3C /* Design capacity */
|
||||
#define BQ27500_FLAG_DSC BIT(0)
|
||||
#define BQ27500_FLAG_FC BIT(9)
|
||||
#define BQ27500_FLAG_DSG BIT(0) /* Discharging */
|
||||
#define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */
|
||||
#define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */
|
||||
#define BQ27500_FLAG_CHG BIT(8) /* Charging */
|
||||
#define BQ27500_FLAG_FC BIT(9) /* Fully charged */
|
||||
|
||||
#define BQ27000_RS 20 /* Resistor sense */
|
||||
|
||||
@ -79,9 +85,8 @@ struct bq27x00_reg_cache {
|
||||
int charge_full;
|
||||
int cycle_count;
|
||||
int capacity;
|
||||
int energy;
|
||||
int flags;
|
||||
|
||||
int current_now;
|
||||
};
|
||||
|
||||
struct bq27x00_device_info {
|
||||
@ -108,6 +113,7 @@ static enum power_supply_property bq27x00_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
|
||||
@ -149,7 +155,7 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di)
|
||||
rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
|
||||
|
||||
if (rsoc < 0)
|
||||
dev_err(di->dev, "error reading relative State-of-Charge\n");
|
||||
dev_dbg(di->dev, "error reading relative State-of-Charge\n");
|
||||
|
||||
return rsoc;
|
||||
}
|
||||
@ -164,7 +170,8 @@ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg)
|
||||
|
||||
charge = bq27x00_read(di, reg, false);
|
||||
if (charge < 0) {
|
||||
dev_err(di->dev, "error reading nominal available capacity\n");
|
||||
dev_dbg(di->dev, "error reading charge register %02x: %d\n",
|
||||
reg, charge);
|
||||
return charge;
|
||||
}
|
||||
|
||||
@ -208,7 +215,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
|
||||
ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
|
||||
|
||||
if (ilmd < 0) {
|
||||
dev_err(di->dev, "error reading initial last measured discharge\n");
|
||||
dev_dbg(di->dev, "error reading initial last measured discharge\n");
|
||||
return ilmd;
|
||||
}
|
||||
|
||||
@ -220,6 +227,50 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
|
||||
return ilmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the battery Available energy in µWh
|
||||
* Or < 0 if something fails.
|
||||
*/
|
||||
static int bq27x00_battery_read_energy(struct bq27x00_device_info *di)
|
||||
{
|
||||
int ae;
|
||||
|
||||
ae = bq27x00_read(di, BQ27x00_REG_AE, false);
|
||||
if (ae < 0) {
|
||||
dev_dbg(di->dev, "error reading available energy\n");
|
||||
return ae;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27500)
|
||||
ae *= 1000;
|
||||
else
|
||||
ae = ae * 29200 / BQ27000_RS;
|
||||
|
||||
return ae;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the battery temperature in tenths of degree Celsius
|
||||
* Or < 0 if something fails.
|
||||
*/
|
||||
static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
|
||||
if (temp < 0) {
|
||||
dev_err(di->dev, "error reading temperature\n");
|
||||
return temp;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27500)
|
||||
temp -= 2731;
|
||||
else
|
||||
temp = ((temp * 5) - 5463) / 2;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the battery Cycle count total
|
||||
* Or < 0 if something fails.
|
||||
@ -245,7 +296,8 @@ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg)
|
||||
|
||||
tval = bq27x00_read(di, reg, false);
|
||||
if (tval < 0) {
|
||||
dev_err(di->dev, "error reading register %02x: %d\n", reg, tval);
|
||||
dev_dbg(di->dev, "error reading time register %02x: %d\n",
|
||||
reg, tval);
|
||||
return tval;
|
||||
}
|
||||
|
||||
@ -262,25 +314,31 @@ static void bq27x00_update(struct bq27x00_device_info *di)
|
||||
|
||||
cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500);
|
||||
if (cache.flags >= 0) {
|
||||
cache.capacity = bq27x00_battery_read_rsoc(di);
|
||||
cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false);
|
||||
cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
|
||||
cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
|
||||
cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
|
||||
cache.charge_full = bq27x00_battery_read_lmd(di);
|
||||
if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) {
|
||||
dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
|
||||
cache.capacity = -ENODATA;
|
||||
cache.energy = -ENODATA;
|
||||
cache.time_to_empty = -ENODATA;
|
||||
cache.time_to_empty_avg = -ENODATA;
|
||||
cache.time_to_full = -ENODATA;
|
||||
cache.charge_full = -ENODATA;
|
||||
} else {
|
||||
cache.capacity = bq27x00_battery_read_rsoc(di);
|
||||
cache.energy = bq27x00_battery_read_energy(di);
|
||||
cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
|
||||
cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
|
||||
cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
|
||||
cache.charge_full = bq27x00_battery_read_lmd(di);
|
||||
}
|
||||
cache.temperature = bq27x00_battery_read_temperature(di);
|
||||
cache.cycle_count = bq27x00_battery_read_cyct(di);
|
||||
|
||||
if (!is_bq27500)
|
||||
cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false);
|
||||
|
||||
/* We only have to read charge design full once */
|
||||
if (di->charge_design_full <= 0)
|
||||
di->charge_design_full = bq27x00_battery_read_ilmd(di);
|
||||
}
|
||||
|
||||
/* Ignore current_now which is a snapshot of the current battery state
|
||||
* and is likely to be different even between two consecutive reads */
|
||||
if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) {
|
||||
if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
|
||||
di->cache = cache;
|
||||
power_supply_changed(&di->bat);
|
||||
}
|
||||
@ -302,25 +360,6 @@ static void bq27x00_battery_poll(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the battery temperature in tenths of degree Celsius
|
||||
* Or < 0 if something fails.
|
||||
*/
|
||||
static int bq27x00_battery_temperature(struct bq27x00_device_info *di,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
if (di->cache.temperature < 0)
|
||||
return di->cache.temperature;
|
||||
|
||||
if (di->chip == BQ27500)
|
||||
val->intval = di->cache.temperature - 2731;
|
||||
else
|
||||
val->intval = ((di->cache.temperature * 5) - 5463) / 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the battery average current in µA
|
||||
* Note that current can be negative signed as well
|
||||
@ -330,20 +369,20 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int curr;
|
||||
int flags;
|
||||
|
||||
if (di->chip == BQ27500)
|
||||
curr = bq27x00_read(di, BQ27x00_REG_AI, false);
|
||||
else
|
||||
curr = di->cache.current_now;
|
||||
|
||||
if (curr < 0)
|
||||
curr = bq27x00_read(di, BQ27x00_REG_AI, false);
|
||||
if (curr < 0) {
|
||||
dev_err(di->dev, "error reading current\n");
|
||||
return curr;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27500) {
|
||||
/* bq27500 returns signed value */
|
||||
val->intval = (int)((s16)curr) * 1000;
|
||||
} else {
|
||||
if (di->cache.flags & BQ27000_FLAG_CHGS) {
|
||||
flags = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
|
||||
if (flags & BQ27000_FLAG_CHGS) {
|
||||
dev_dbg(di->dev, "negative current!\n");
|
||||
curr = -curr;
|
||||
}
|
||||
@ -362,10 +401,14 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,
|
||||
if (di->chip == BQ27500) {
|
||||
if (di->cache.flags & BQ27500_FLAG_FC)
|
||||
status = POWER_SUPPLY_STATUS_FULL;
|
||||
else if (di->cache.flags & BQ27500_FLAG_DSC)
|
||||
else if (di->cache.flags & BQ27500_FLAG_DSG)
|
||||
status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else
|
||||
else if (di->cache.flags & BQ27500_FLAG_CHG)
|
||||
status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else if (power_supply_am_i_supplied(&di->bat))
|
||||
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
else
|
||||
status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
} else {
|
||||
if (di->cache.flags & BQ27000_FLAG_FC)
|
||||
status = POWER_SUPPLY_STATUS_FULL;
|
||||
@ -382,6 +425,36 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int level;
|
||||
|
||||
if (di->chip == BQ27500) {
|
||||
if (di->cache.flags & BQ27500_FLAG_FC)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
|
||||
else if (di->cache.flags & BQ27500_FLAG_SOC1)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
|
||||
else if (di->cache.flags & BQ27500_FLAG_SOCF)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
|
||||
else
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
|
||||
} else {
|
||||
if (di->cache.flags & BQ27000_FLAG_FC)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
|
||||
else if (di->cache.flags & BQ27000_FLAG_EDV1)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
|
||||
else if (di->cache.flags & BQ27000_FLAG_EDVF)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
|
||||
else
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
|
||||
}
|
||||
|
||||
val->intval = level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the battery Voltage in milivolts
|
||||
* Or < 0 if something fails.
|
||||
@ -392,40 +465,16 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
|
||||
int volt;
|
||||
|
||||
volt = bq27x00_read(di, BQ27x00_REG_VOLT, false);
|
||||
if (volt < 0)
|
||||
if (volt < 0) {
|
||||
dev_err(di->dev, "error reading voltage\n");
|
||||
return volt;
|
||||
}
|
||||
|
||||
val->intval = volt * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the battery Available energy in µWh
|
||||
* Or < 0 if something fails.
|
||||
*/
|
||||
static int bq27x00_battery_energy(struct bq27x00_device_info *di,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int ae;
|
||||
|
||||
ae = bq27x00_read(di, BQ27x00_REG_AE, false);
|
||||
if (ae < 0) {
|
||||
dev_err(di->dev, "error reading available energy\n");
|
||||
return ae;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27500)
|
||||
ae *= 1000;
|
||||
else
|
||||
ae = ae * 29200 / BQ27000_RS;
|
||||
|
||||
val->intval = ae;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int bq27x00_simple_value(int value,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
@ -473,8 +522,11 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = bq27x00_simple_value(di->cache.capacity, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
|
||||
ret = bq27x00_battery_capacity_level(di, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
ret = bq27x00_battery_temperature(di, val);
|
||||
ret = bq27x00_simple_value(di->cache.temperature, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
|
||||
ret = bq27x00_simple_value(di->cache.time_to_empty, val);
|
||||
@ -501,7 +553,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
|
||||
ret = bq27x00_simple_value(di->cache.cycle_count, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
||||
ret = bq27x00_battery_energy(di, val);
|
||||
ret = bq27x00_simple_value(di->cache.energy, val);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -546,6 +598,14 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
|
||||
|
||||
static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di)
|
||||
{
|
||||
/*
|
||||
* power_supply_unregister call bq27x00_battery_get_property which
|
||||
* call bq27x00_battery_poll.
|
||||
* Make sure that bq27x00_battery_poll will not call
|
||||
* schedule_delayed_work again after unregister (which cause OOPS).
|
||||
*/
|
||||
poll_interval = 0;
|
||||
|
||||
cancel_delayed_work_sync(&di->work);
|
||||
|
||||
power_supply_unregister(&di->bat);
|
||||
|
1072
drivers/power/charger-manager.c
Normal file
1072
drivers/power/charger-manager.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -146,7 +146,7 @@ static void collie_bat_external_power_changed(struct power_supply *psy)
|
||||
|
||||
static irqreturn_t collie_bat_gpio_isr(int irq, void *data)
|
||||
{
|
||||
pr_info("collie_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
|
||||
pr_info("collie_bat_gpio irq\n");
|
||||
schedule_work(&bat_work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -277,18 +277,13 @@ static struct collie_bat collie_bat_bu = {
|
||||
.adc_temp_divider = -1,
|
||||
};
|
||||
|
||||
static struct {
|
||||
int gpio;
|
||||
char *name;
|
||||
bool output;
|
||||
int value;
|
||||
} gpios[] = {
|
||||
{ COLLIE_GPIO_CO, "main battery full", 0, 0 },
|
||||
{ COLLIE_GPIO_MAIN_BAT_LOW, "main battery low", 0, 0 },
|
||||
{ COLLIE_GPIO_CHARGE_ON, "main charge on", 1, 0 },
|
||||
{ COLLIE_GPIO_MBAT_ON, "main battery", 1, 0 },
|
||||
{ COLLIE_GPIO_TMP_ON, "main battery temp", 1, 0 },
|
||||
{ COLLIE_GPIO_BBAT_ON, "backup battery", 1, 0 },
|
||||
static struct gpio collie_batt_gpios[] = {
|
||||
{ COLLIE_GPIO_CO, GPIOF_IN, "main battery full" },
|
||||
{ COLLIE_GPIO_MAIN_BAT_LOW, GPIOF_IN, "main battery low" },
|
||||
{ COLLIE_GPIO_CHARGE_ON, GPIOF_OUT_INIT_LOW, "main charge on" },
|
||||
{ COLLIE_GPIO_MBAT_ON, GPIOF_OUT_INIT_LOW, "main battery" },
|
||||
{ COLLIE_GPIO_TMP_ON, GPIOF_OUT_INIT_LOW, "main battery temp" },
|
||||
{ COLLIE_GPIO_BBAT_ON, GPIOF_OUT_INIT_LOW, "backup battery" },
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -313,29 +308,16 @@ static int collie_bat_resume(struct ucb1x00_dev *dev)
|
||||
static int __devinit collie_bat_probe(struct ucb1x00_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!machine_is_collie())
|
||||
return -ENODEV;
|
||||
|
||||
ucb = dev->ucb;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gpios); i++) {
|
||||
ret = gpio_request(gpios[i].gpio, gpios[i].name);
|
||||
if (ret) {
|
||||
i--;
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpios[i].output)
|
||||
ret = gpio_direction_output(gpios[i].gpio,
|
||||
gpios[i].value);
|
||||
else
|
||||
ret = gpio_direction_input(gpios[i].gpio);
|
||||
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
}
|
||||
ret = gpio_request_array(collie_batt_gpios,
|
||||
ARRAY_SIZE(collie_batt_gpios));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&collie_bat_main.work_lock);
|
||||
|
||||
@ -363,19 +345,12 @@ err_psy_reg_main:
|
||||
|
||||
/* see comment in collie_bat_remove */
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
i--;
|
||||
err_gpio:
|
||||
for (; i >= 0; i--)
|
||||
gpio_free(gpios[i].gpio);
|
||||
|
||||
gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
|
||||
|
||||
power_supply_unregister(&collie_bat_bu.psy);
|
||||
@ -387,9 +362,7 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
|
||||
* unregistered now.
|
||||
*/
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
|
||||
gpio_free(gpios[i].gpio);
|
||||
gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
|
||||
}
|
||||
|
||||
static struct ucb1x00_driver collie_bat_driver = {
|
||||
|
@ -588,18 +588,7 @@ static struct platform_driver da903x_battery_driver = {
|
||||
.remove = da9030_battery_remove,
|
||||
};
|
||||
|
||||
static int da903x_battery_init(void)
|
||||
{
|
||||
return platform_driver_register(&da903x_battery_driver);
|
||||
}
|
||||
|
||||
static void da903x_battery_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&da903x_battery_driver);
|
||||
}
|
||||
|
||||
module_init(da903x_battery_init);
|
||||
module_exit(da903x_battery_exit);
|
||||
module_platform_driver(da903x_battery_driver);
|
||||
|
||||
MODULE_DESCRIPTION("DA9030 battery charger driver");
|
||||
MODULE_AUTHOR("Mike Rapoport, CompuLab");
|
||||
|
664
drivers/power/da9052-battery.c
Normal file
664
drivers/power/da9052-battery.c
Normal file
@ -0,0 +1,664 @@
|
||||
/*
|
||||
* Batttery Driver for Dialog DA9052 PMICs
|
||||
*
|
||||
* Copyright(c) 2011 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: David Dajun Chen <dchen@diasemi.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.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
#include <linux/mfd/da9052/da9052.h>
|
||||
#include <linux/mfd/da9052/pdata.h>
|
||||
#include <linux/mfd/da9052/reg.h>
|
||||
|
||||
/* STATIC CONFIGURATION */
|
||||
#define DA9052_BAT_CUTOFF_VOLT 2800
|
||||
#define DA9052_BAT_TSH 62000
|
||||
#define DA9052_BAT_LOW_CAP 4
|
||||
#define DA9052_AVG_SZ 4
|
||||
#define DA9052_VC_TBL_SZ 68
|
||||
#define DA9052_VC_TBL_REF_SZ 3
|
||||
|
||||
#define DA9052_ISET_USB_MASK 0x0F
|
||||
#define DA9052_CHG_USB_ILIM_MASK 0x40
|
||||
#define DA9052_CHG_LIM_COLS 16
|
||||
|
||||
#define DA9052_MEAN(x, y) ((x + y) / 2)
|
||||
|
||||
enum charger_type_enum {
|
||||
DA9052_NOCHARGER = 1,
|
||||
DA9052_CHARGER,
|
||||
};
|
||||
|
||||
static const u16 da9052_chg_current_lim[2][DA9052_CHG_LIM_COLS] = {
|
||||
{70, 80, 90, 100, 110, 120, 400, 450,
|
||||
500, 550, 600, 650, 700, 900, 1100, 1300},
|
||||
{80, 90, 100, 110, 120, 400, 450, 500,
|
||||
550, 600, 800, 1000, 1200, 1400, 1600, 1800},
|
||||
};
|
||||
|
||||
static const u16 vc_tbl_ref[3] = {10, 25, 40};
|
||||
/* Lookup table for voltage vs capacity */
|
||||
static u32 const vc_tbl[3][68][2] = {
|
||||
/* For temperature 10 degree Celsius */
|
||||
{
|
||||
{4082, 100}, {4036, 98},
|
||||
{4020, 96}, {4008, 95},
|
||||
{3997, 93}, {3983, 91},
|
||||
{3964, 90}, {3943, 88},
|
||||
{3926, 87}, {3912, 85},
|
||||
{3900, 84}, {3890, 82},
|
||||
{3881, 80}, {3873, 79},
|
||||
{3865, 77}, {3857, 76},
|
||||
{3848, 74}, {3839, 73},
|
||||
{3829, 71}, {3820, 70},
|
||||
{3811, 68}, {3802, 67},
|
||||
{3794, 65}, {3785, 64},
|
||||
{3778, 62}, {3770, 61},
|
||||
{3763, 59}, {3756, 58},
|
||||
{3750, 56}, {3744, 55},
|
||||
{3738, 53}, {3732, 52},
|
||||
{3727, 50}, {3722, 49},
|
||||
{3717, 47}, {3712, 46},
|
||||
{3708, 44}, {3703, 43},
|
||||
{3700, 41}, {3696, 40},
|
||||
{3693, 38}, {3691, 37},
|
||||
{3688, 35}, {3686, 34},
|
||||
{3683, 32}, {3681, 31},
|
||||
{3678, 29}, {3675, 28},
|
||||
{3672, 26}, {3669, 25},
|
||||
{3665, 23}, {3661, 22},
|
||||
{3656, 21}, {3651, 19},
|
||||
{3645, 18}, {3639, 16},
|
||||
{3631, 15}, {3622, 13},
|
||||
{3611, 12}, {3600, 10},
|
||||
{3587, 9}, {3572, 7},
|
||||
{3548, 6}, {3503, 5},
|
||||
{3420, 3}, {3268, 2},
|
||||
{2992, 1}, {2746, 0}
|
||||
},
|
||||
/* For temperature 25 degree Celsius */
|
||||
{
|
||||
{4102, 100}, {4065, 98},
|
||||
{4048, 96}, {4034, 95},
|
||||
{4021, 93}, {4011, 92},
|
||||
{4001, 90}, {3986, 88},
|
||||
{3968, 87}, {3952, 85},
|
||||
{3938, 84}, {3926, 82},
|
||||
{3916, 81}, {3908, 79},
|
||||
{3900, 77}, {3892, 76},
|
||||
{3883, 74}, {3874, 73},
|
||||
{3864, 71}, {3855, 70},
|
||||
{3846, 68}, {3836, 67},
|
||||
{3827, 65}, {3819, 64},
|
||||
{3810, 62}, {3801, 61},
|
||||
{3793, 59}, {3786, 58},
|
||||
{3778, 56}, {3772, 55},
|
||||
{3765, 53}, {3759, 52},
|
||||
{3754, 50}, {3748, 49},
|
||||
{3743, 47}, {3738, 46},
|
||||
{3733, 44}, {3728, 43},
|
||||
{3724, 41}, {3720, 40},
|
||||
{3716, 38}, {3712, 37},
|
||||
{3709, 35}, {3706, 34},
|
||||
{3703, 33}, {3701, 31},
|
||||
{3698, 30}, {3696, 28},
|
||||
{3693, 27}, {3690, 25},
|
||||
{3687, 24}, {3683, 22},
|
||||
{3680, 21}, {3675, 19},
|
||||
{3671, 18}, {3666, 17},
|
||||
{3660, 15}, {3654, 14},
|
||||
{3647, 12}, {3639, 11},
|
||||
{3630, 9}, {3621, 8},
|
||||
{3613, 6}, {3606, 5},
|
||||
{3597, 4}, {3582, 2},
|
||||
{3546, 1}, {2747, 0}
|
||||
},
|
||||
/* For temperature 40 degree Celsius */
|
||||
{
|
||||
{4114, 100}, {4081, 98},
|
||||
{4065, 96}, {4050, 95},
|
||||
{4036, 93}, {4024, 92},
|
||||
{4013, 90}, {4002, 88},
|
||||
{3990, 87}, {3976, 85},
|
||||
{3962, 84}, {3950, 82},
|
||||
{3939, 81}, {3930, 79},
|
||||
{3921, 77}, {3912, 76},
|
||||
{3902, 74}, {3893, 73},
|
||||
{3883, 71}, {3874, 70},
|
||||
{3865, 68}, {3856, 67},
|
||||
{3847, 65}, {3838, 64},
|
||||
{3829, 62}, {3820, 61},
|
||||
{3812, 59}, {3803, 58},
|
||||
{3795, 56}, {3787, 55},
|
||||
{3780, 53}, {3773, 52},
|
||||
{3767, 50}, {3761, 49},
|
||||
{3756, 47}, {3751, 46},
|
||||
{3746, 44}, {3741, 43},
|
||||
{3736, 41}, {3732, 40},
|
||||
{3728, 38}, {3724, 37},
|
||||
{3720, 35}, {3716, 34},
|
||||
{3713, 33}, {3710, 31},
|
||||
{3707, 30}, {3704, 28},
|
||||
{3701, 27}, {3698, 25},
|
||||
{3695, 24}, {3691, 22},
|
||||
{3686, 21}, {3681, 19},
|
||||
{3676, 18}, {3671, 17},
|
||||
{3666, 15}, {3661, 14},
|
||||
{3655, 12}, {3648, 11},
|
||||
{3640, 9}, {3632, 8},
|
||||
{3622, 6}, {3616, 5},
|
||||
{3611, 4}, {3604, 2},
|
||||
{3594, 1}, {2747, 0}
|
||||
}
|
||||
};
|
||||
|
||||
struct da9052_battery {
|
||||
struct da9052 *da9052;
|
||||
struct power_supply psy;
|
||||
struct notifier_block nb;
|
||||
int charger_type;
|
||||
int status;
|
||||
int health;
|
||||
};
|
||||
|
||||
static inline int volt_reg_to_mV(int value)
|
||||
{
|
||||
return ((value * 1000) / 512) + 2500;
|
||||
}
|
||||
|
||||
static inline int ichg_reg_to_mA(int value)
|
||||
{
|
||||
return (value * 3900) / 1000;
|
||||
}
|
||||
|
||||
static int da9052_read_chgend_current(struct da9052_battery *bat,
|
||||
int *current_mA)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
|
||||
return -EINVAL;
|
||||
|
||||
ret = da9052_reg_read(bat->da9052, DA9052_ICHG_END_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*current_mA = ichg_reg_to_mA(ret & DA9052_ICHGEND_ICHGEND);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da9052_read_chg_current(struct da9052_battery *bat, int *current_mA)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
|
||||
return -EINVAL;
|
||||
|
||||
ret = da9052_reg_read(bat->da9052, DA9052_ICHG_AV_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*current_mA = ichg_reg_to_mA(ret & DA9052_ICHGAV_ICHGAV);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da9052_bat_check_status(struct da9052_battery *bat, int *status)
|
||||
{
|
||||
u8 v[2] = {0, 0};
|
||||
u8 bat_status;
|
||||
u8 chg_end;
|
||||
int ret;
|
||||
int chg_current;
|
||||
int chg_end_current;
|
||||
bool dcinsel;
|
||||
bool dcindet;
|
||||
bool vbussel;
|
||||
bool vbusdet;
|
||||
bool dc;
|
||||
bool vbus;
|
||||
|
||||
ret = da9052_group_read(bat->da9052, DA9052_STATUS_A_REG, 2, v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bat_status = v[0];
|
||||
chg_end = v[1];
|
||||
|
||||
dcinsel = bat_status & DA9052_STATUSA_DCINSEL;
|
||||
dcindet = bat_status & DA9052_STATUSA_DCINDET;
|
||||
vbussel = bat_status & DA9052_STATUSA_VBUSSEL;
|
||||
vbusdet = bat_status & DA9052_STATUSA_VBUSDET;
|
||||
dc = dcinsel && dcindet;
|
||||
vbus = vbussel && vbusdet;
|
||||
|
||||
/* Preference to WALL(DCIN) charger unit */
|
||||
if (dc || vbus) {
|
||||
bat->charger_type = DA9052_CHARGER;
|
||||
|
||||
/* If charging end flag is set and Charging current is greater
|
||||
* than charging end limit then battery is charging
|
||||
*/
|
||||
if ((chg_end & DA9052_STATUSB_CHGEND) != 0) {
|
||||
ret = da9052_read_chg_current(bat, &chg_current);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = da9052_read_chgend_current(bat, &chg_end_current);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (chg_current >= chg_end_current)
|
||||
bat->status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else
|
||||
bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
} else {
|
||||
/* If Charging end flag is cleared then battery is
|
||||
* charging
|
||||
*/
|
||||
bat->status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
} else if (dcindet || vbusdet) {
|
||||
bat->charger_type = DA9052_CHARGER;
|
||||
bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
} else {
|
||||
bat->charger_type = DA9052_NOCHARGER;
|
||||
bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
if (status != NULL)
|
||||
*status = bat->status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da9052_bat_read_volt(struct da9052_battery *bat, int *volt_mV)
|
||||
{
|
||||
int volt;
|
||||
|
||||
volt = da9052_adc_manual_read(bat->da9052, DA9052_ADC_MAN_MUXSEL_VBAT);
|
||||
if (volt < 0)
|
||||
return volt;
|
||||
|
||||
*volt_mV = volt_reg_to_mV(volt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da9052_bat_check_presence(struct da9052_battery *bat, int *illegal)
|
||||
{
|
||||
int bat_temp;
|
||||
|
||||
bat_temp = da9052_adc_read_temp(bat->da9052);
|
||||
if (bat_temp < 0)
|
||||
return bat_temp;
|
||||
|
||||
if (bat_temp > DA9052_BAT_TSH)
|
||||
*illegal = 1;
|
||||
else
|
||||
*illegal = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da9052_bat_interpolate(int vbat_lower, int vbat_upper,
|
||||
int level_lower, int level_upper,
|
||||
int bat_voltage)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
tmp = ((level_upper - level_lower) * 1000) / (vbat_upper - vbat_lower);
|
||||
tmp = level_lower + (((bat_voltage - vbat_lower) * tmp) / 1000);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned char da9052_determine_vc_tbl_index(unsigned char adc_temp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (adc_temp <= vc_tbl_ref[0])
|
||||
return 0;
|
||||
|
||||
if (adc_temp > vc_tbl_ref[DA9052_VC_TBL_REF_SZ - 1])
|
||||
return DA9052_VC_TBL_REF_SZ - 1;
|
||||
|
||||
for (i = 0; i < DA9052_VC_TBL_REF_SZ; i++) {
|
||||
if ((adc_temp > vc_tbl_ref[i]) &&
|
||||
(adc_temp <= DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1])))
|
||||
return i;
|
||||
if ((adc_temp > DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1]))
|
||||
&& (adc_temp <= vc_tbl_ref[i]))
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int da9052_bat_read_capacity(struct da9052_battery *bat, int *capacity)
|
||||
{
|
||||
int adc_temp;
|
||||
int bat_voltage;
|
||||
int vbat_lower;
|
||||
int vbat_upper;
|
||||
int level_upper;
|
||||
int level_lower;
|
||||
int ret;
|
||||
int flag;
|
||||
int i = 0;
|
||||
int j;
|
||||
|
||||
ret = da9052_bat_read_volt(bat, &bat_voltage);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
adc_temp = da9052_adc_read_temp(bat->da9052);
|
||||
if (adc_temp < 0)
|
||||
return adc_temp;
|
||||
|
||||
i = da9052_determine_vc_tbl_index(adc_temp);
|
||||
|
||||
if (bat_voltage >= vc_tbl[i][0][0]) {
|
||||
*capacity = 100;
|
||||
return 0;
|
||||
}
|
||||
if (bat_voltage <= vc_tbl[i][DA9052_VC_TBL_SZ - 1][0]) {
|
||||
*capacity = 0;
|
||||
return 0;
|
||||
}
|
||||
flag = 0;
|
||||
|
||||
for (j = 0; j < (DA9052_VC_TBL_SZ-1); j++) {
|
||||
if ((bat_voltage <= vc_tbl[i][j][0]) &&
|
||||
(bat_voltage >= vc_tbl[i][j + 1][0])) {
|
||||
vbat_upper = vc_tbl[i][j][0];
|
||||
vbat_lower = vc_tbl[i][j + 1][0];
|
||||
level_upper = vc_tbl[i][j][1];
|
||||
level_lower = vc_tbl[i][j + 1][1];
|
||||
flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
return -EIO;
|
||||
|
||||
*capacity = da9052_bat_interpolate(vbat_lower, vbat_upper, level_lower,
|
||||
level_upper, bat_voltage);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int da9052_bat_check_health(struct da9052_battery *bat, int *health)
|
||||
{
|
||||
int ret;
|
||||
int bat_illegal;
|
||||
int capacity;
|
||||
|
||||
ret = da9052_bat_check_presence(bat, &bat_illegal);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (bat_illegal) {
|
||||
bat->health = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bat->health != POWER_SUPPLY_HEALTH_OVERHEAT) {
|
||||
ret = da9052_bat_read_capacity(bat, &capacity);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (capacity < DA9052_BAT_LOW_CAP)
|
||||
bat->health = POWER_SUPPLY_HEALTH_DEAD;
|
||||
else
|
||||
bat->health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
}
|
||||
|
||||
*health = bat->health;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t da9052_bat_irq(int irq, void *data)
|
||||
{
|
||||
struct da9052_battery *bat = data;
|
||||
|
||||
irq -= bat->da9052->irq_base;
|
||||
|
||||
if (irq == DA9052_IRQ_CHGEND)
|
||||
bat->status = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
da9052_bat_check_status(bat, NULL);
|
||||
|
||||
if (irq == DA9052_IRQ_CHGEND || irq == DA9052_IRQ_DCIN ||
|
||||
irq == DA9052_IRQ_VBUS || irq == DA9052_IRQ_TBAT) {
|
||||
power_supply_changed(&bat->psy);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int da9052_USB_current_notifier(struct notifier_block *nb,
|
||||
unsigned long events, void *data)
|
||||
{
|
||||
u8 row;
|
||||
u8 col;
|
||||
int *current_mA = data;
|
||||
int ret;
|
||||
struct da9052_battery *bat = container_of(nb, struct da9052_battery,
|
||||
nb);
|
||||
|
||||
if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
|
||||
return -EPERM;
|
||||
|
||||
ret = da9052_reg_read(bat->da9052, DA9052_CHGBUCK_REG);
|
||||
if (ret & DA9052_CHG_USB_ILIM_MASK)
|
||||
return -EPERM;
|
||||
|
||||
if (bat->da9052->chip_id == DA9052)
|
||||
row = 0;
|
||||
else
|
||||
row = 1;
|
||||
|
||||
if (*current_mA < da9052_chg_current_lim[row][0] ||
|
||||
*current_mA > da9052_chg_current_lim[row][DA9052_CHG_LIM_COLS - 1])
|
||||
return -EINVAL;
|
||||
|
||||
for (col = 0; col <= DA9052_CHG_LIM_COLS - 1 ; col++) {
|
||||
if (*current_mA <= da9052_chg_current_lim[row][col])
|
||||
break;
|
||||
}
|
||||
|
||||
return da9052_reg_update(bat->da9052, DA9052_ISET_REG,
|
||||
DA9052_ISET_USB_MASK, col);
|
||||
}
|
||||
|
||||
static int da9052_bat_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int ret;
|
||||
int illegal;
|
||||
struct da9052_battery *bat = container_of(psy, struct da9052_battery,
|
||||
psy);
|
||||
|
||||
ret = da9052_bat_check_presence(bat, &illegal);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (illegal && psp != POWER_SUPPLY_PROP_PRESENT)
|
||||
return -ENODEV;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
ret = da9052_bat_check_status(bat, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval =
|
||||
(bat->charger_type == DA9052_NOCHARGER) ? 0 : 1;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
ret = da9052_bat_check_presence(bat, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
ret = da9052_bat_check_health(bat, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
|
||||
val->intval = DA9052_BAT_CUTOFF_VOLT * 1000;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
|
||||
ret = da9052_bat_read_volt(bat, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
ret = da9052_read_chg_current(bat, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = da9052_bat_read_capacity(bat, &val->intval);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
val->intval = da9052_adc_read_temp(bat->da9052);
|
||||
ret = val->intval;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum power_supply_property da9052_bat_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_AVG,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
};
|
||||
|
||||
static struct power_supply template_battery = {
|
||||
.name = "da9052-bat",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = da9052_bat_props,
|
||||
.num_properties = ARRAY_SIZE(da9052_bat_props),
|
||||
.get_property = da9052_bat_get_property,
|
||||
};
|
||||
|
||||
static const char *const da9052_bat_irqs[] = {
|
||||
"BATT TEMP",
|
||||
"DCIN DET",
|
||||
"DCIN REM",
|
||||
"VBUS DET",
|
||||
"VBUS REM",
|
||||
"CHG END",
|
||||
};
|
||||
|
||||
static s32 __devinit da9052_bat_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct da9052_pdata *pdata;
|
||||
struct da9052_battery *bat;
|
||||
int ret;
|
||||
int irq;
|
||||
int i;
|
||||
|
||||
bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL);
|
||||
if (!bat)
|
||||
return -ENOMEM;
|
||||
|
||||
bat->da9052 = dev_get_drvdata(pdev->dev.parent);
|
||||
bat->psy = template_battery;
|
||||
bat->charger_type = DA9052_NOCHARGER;
|
||||
bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
bat->health = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
bat->nb.notifier_call = da9052_USB_current_notifier;
|
||||
|
||||
pdata = bat->da9052->dev->platform_data;
|
||||
if (pdata != NULL && pdata->use_for_apm)
|
||||
bat->psy.use_for_apm = pdata->use_for_apm;
|
||||
else
|
||||
bat->psy.use_for_apm = 1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) {
|
||||
irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]);
|
||||
ret = request_threaded_irq(bat->da9052->irq_base + irq,
|
||||
NULL, da9052_bat_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
da9052_bat_irqs[i], bat);
|
||||
if (ret != 0) {
|
||||
dev_err(bat->da9052->dev,
|
||||
"DA9052 failed to request %s IRQ %d: %d\n",
|
||||
da9052_bat_irqs[i], irq, ret);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = power_supply_register(&pdev->dev, &bat->psy);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (; i >= 0; i--) {
|
||||
irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]);
|
||||
free_irq(bat->da9052->irq_base + irq, bat);
|
||||
}
|
||||
kfree(bat);
|
||||
return ret;
|
||||
}
|
||||
static int __devexit da9052_bat_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
int irq;
|
||||
struct da9052_battery *bat = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) {
|
||||
irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]);
|
||||
free_irq(bat->da9052->irq_base + irq, bat);
|
||||
}
|
||||
power_supply_unregister(&bat->psy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da9052_bat_driver = {
|
||||
.probe = da9052_bat_probe,
|
||||
.remove = __devexit_p(da9052_bat_remove),
|
||||
.driver = {
|
||||
.name = "da9052-bat",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init da9052_bat_init(void)
|
||||
{
|
||||
return platform_driver_register(&da9052_bat_driver);
|
||||
}
|
||||
module_init(da9052_bat_init);
|
||||
|
||||
static void __exit da9052_bat_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&da9052_bat_driver);
|
||||
}
|
||||
module_exit(da9052_bat_exit);
|
||||
|
||||
MODULE_DESCRIPTION("DA9052 BAT Device Driver");
|
||||
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:da9052-bat");
|
@ -95,7 +95,11 @@ static int rated_capacities[] = {
|
||||
2880, /* Samsung */
|
||||
2880, /* BYD */
|
||||
2880, /* Lishen */
|
||||
2880 /* NEC */
|
||||
2880, /* NEC */
|
||||
#ifdef CONFIG_MACH_H4700
|
||||
0,
|
||||
3600, /* HP iPAQ hx4700 3.7V 3600mAh (359114-001) */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C
|
||||
@ -637,18 +641,7 @@ static struct platform_driver ds2760_battery_driver = {
|
||||
.resume = ds2760_battery_resume,
|
||||
};
|
||||
|
||||
static int __init ds2760_battery_init(void)
|
||||
{
|
||||
return platform_driver_register(&ds2760_battery_driver);
|
||||
}
|
||||
|
||||
static void __exit ds2760_battery_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ds2760_battery_driver);
|
||||
}
|
||||
|
||||
module_init(ds2760_battery_init);
|
||||
module_exit(ds2760_battery_exit);
|
||||
module_platform_driver(ds2760_battery_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
|
||||
|
@ -841,29 +841,17 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:ds2780-battery");
|
||||
|
||||
static struct platform_driver ds2780_battery_driver = {
|
||||
.driver = {
|
||||
.name = "ds2780-battery",
|
||||
},
|
||||
.probe = ds2780_battery_probe,
|
||||
.remove = ds2780_battery_remove,
|
||||
.remove = __devexit_p(ds2780_battery_remove),
|
||||
};
|
||||
|
||||
static int __init ds2780_battery_init(void)
|
||||
{
|
||||
return platform_driver_register(&ds2780_battery_driver);
|
||||
}
|
||||
|
||||
static void __exit ds2780_battery_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ds2780_battery_driver);
|
||||
}
|
||||
|
||||
module_init(ds2780_battery_init);
|
||||
module_exit(ds2780_battery_exit);
|
||||
module_platform_driver(ds2780_battery_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
|
||||
MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver");
|
||||
MODULE_ALIAS("platform:ds2780-battery");
|
||||
|
@ -185,17 +185,7 @@ static struct platform_driver gpio_charger_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init gpio_charger_init(void)
|
||||
{
|
||||
return platform_driver_register(&gpio_charger_driver);
|
||||
}
|
||||
module_init(gpio_charger_init);
|
||||
|
||||
static void __exit gpio_charger_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&gpio_charger_driver);
|
||||
}
|
||||
module_exit(gpio_charger_exit);
|
||||
module_platform_driver(gpio_charger_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
|
||||
|
@ -779,18 +779,7 @@ static struct platform_driver platform_pmic_battery_driver = {
|
||||
.remove = __devexit_p(platform_pmic_battery_remove),
|
||||
};
|
||||
|
||||
static int __init platform_pmic_battery_module_init(void)
|
||||
{
|
||||
return platform_driver_register(&platform_pmic_battery_driver);
|
||||
}
|
||||
|
||||
static void __exit platform_pmic_battery_module_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&platform_pmic_battery_driver);
|
||||
}
|
||||
|
||||
module_init(platform_pmic_battery_module_init);
|
||||
module_exit(platform_pmic_battery_module_exit);
|
||||
module_platform_driver(platform_pmic_battery_driver);
|
||||
|
||||
MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver");
|
||||
|
@ -79,7 +79,7 @@ static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on)
|
||||
{
|
||||
struct isp1704_charger_data *board = isp->dev->platform_data;
|
||||
|
||||
if (board->set_power)
|
||||
if (board && board->set_power)
|
||||
board->set_power(on);
|
||||
}
|
||||
|
||||
@ -494,17 +494,7 @@ static struct platform_driver isp1704_charger_driver = {
|
||||
.remove = __devexit_p(isp1704_charger_remove),
|
||||
};
|
||||
|
||||
static int __init isp1704_charger_init(void)
|
||||
{
|
||||
return platform_driver_register(&isp1704_charger_driver);
|
||||
}
|
||||
module_init(isp1704_charger_init);
|
||||
|
||||
static void __exit isp1704_charger_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&isp1704_charger_driver);
|
||||
}
|
||||
module_exit(isp1704_charger_exit);
|
||||
module_platform_driver(isp1704_charger_driver);
|
||||
|
||||
MODULE_ALIAS("platform:isp1704_charger");
|
||||
MODULE_AUTHOR("Nokia Corporation");
|
||||
|
@ -67,7 +67,7 @@ static irqreturn_t jz_battery_irq_handler(int irq, void *devid)
|
||||
|
||||
static long jz_battery_read_voltage(struct jz_battery *battery)
|
||||
{
|
||||
unsigned long t;
|
||||
long t;
|
||||
unsigned long val;
|
||||
long voltage;
|
||||
|
||||
@ -441,17 +441,7 @@ static struct platform_driver jz_battery_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init jz_battery_init(void)
|
||||
{
|
||||
return platform_driver_register(&jz_battery_driver);
|
||||
}
|
||||
module_init(jz_battery_init);
|
||||
|
||||
static void __exit jz_battery_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&jz_battery_driver);
|
||||
}
|
||||
module_exit(jz_battery_exit);
|
||||
module_platform_driver(jz_battery_driver);
|
||||
|
||||
MODULE_ALIAS("platform:jz4740-battery");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
494
drivers/power/lp8727_charger.c
Normal file
494
drivers/power/lp8727_charger.c
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Driver for LP8727 Micro/Mini USB IC with intergrated charger
|
||||
*
|
||||
* Copyright (C) 2011 National Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/lp8727.h>
|
||||
|
||||
#define DEBOUNCE_MSEC 270
|
||||
|
||||
/* Registers */
|
||||
#define CTRL1 0x1
|
||||
#define CTRL2 0x2
|
||||
#define SWCTRL 0x3
|
||||
#define INT1 0x4
|
||||
#define INT2 0x5
|
||||
#define STATUS1 0x6
|
||||
#define STATUS2 0x7
|
||||
#define CHGCTRL2 0x9
|
||||
|
||||
/* CTRL1 register */
|
||||
#define CP_EN (1 << 0)
|
||||
#define ADC_EN (1 << 1)
|
||||
#define ID200_EN (1 << 4)
|
||||
|
||||
/* CTRL2 register */
|
||||
#define CHGDET_EN (1 << 1)
|
||||
#define INT_EN (1 << 6)
|
||||
|
||||
/* SWCTRL register */
|
||||
#define SW_DM1_DM (0x0 << 0)
|
||||
#define SW_DM1_U1 (0x1 << 0)
|
||||
#define SW_DM1_HiZ (0x7 << 0)
|
||||
#define SW_DP2_DP (0x0 << 3)
|
||||
#define SW_DP2_U2 (0x1 << 3)
|
||||
#define SW_DP2_HiZ (0x7 << 3)
|
||||
|
||||
/* INT1 register */
|
||||
#define IDNO (0xF << 0)
|
||||
#define VBUS (1 << 4)
|
||||
|
||||
/* STATUS1 register */
|
||||
#define CHGSTAT (3 << 4)
|
||||
#define CHPORT (1 << 6)
|
||||
#define DCPORT (1 << 7)
|
||||
|
||||
/* STATUS2 register */
|
||||
#define TEMP_STAT (3 << 5)
|
||||
|
||||
enum lp8727_dev_id {
|
||||
ID_NONE,
|
||||
ID_TA,
|
||||
ID_DEDICATED_CHG,
|
||||
ID_USB_CHG,
|
||||
ID_USB_DS,
|
||||
ID_MAX,
|
||||
};
|
||||
|
||||
enum lp8727_chg_stat {
|
||||
PRECHG,
|
||||
CC,
|
||||
CV,
|
||||
EOC,
|
||||
};
|
||||
|
||||
struct lp8727_psy {
|
||||
struct power_supply ac;
|
||||
struct power_supply usb;
|
||||
struct power_supply batt;
|
||||
};
|
||||
|
||||
struct lp8727_chg {
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex xfer_lock;
|
||||
struct delayed_work work;
|
||||
struct workqueue_struct *irqthread;
|
||||
struct lp8727_platform_data *pdata;
|
||||
struct lp8727_psy *psy;
|
||||
struct lp8727_chg_param *chg_parm;
|
||||
enum lp8727_dev_id devid;
|
||||
};
|
||||
|
||||
static int lp8727_i2c_read(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
mutex_lock(&pchg->xfer_lock);
|
||||
ret = i2c_smbus_read_i2c_block_data(pchg->client, reg, len, data);
|
||||
mutex_unlock(&pchg->xfer_lock);
|
||||
|
||||
return (ret != len) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int lp8727_i2c_write(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
mutex_lock(&pchg->xfer_lock);
|
||||
ret = i2c_smbus_write_i2c_block_data(pchg->client, reg, len, data);
|
||||
mutex_unlock(&pchg->xfer_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int lp8727_i2c_read_byte(struct lp8727_chg *pchg, u8 reg,
|
||||
u8 *data)
|
||||
{
|
||||
return lp8727_i2c_read(pchg, reg, data, 1);
|
||||
}
|
||||
|
||||
static inline int lp8727_i2c_write_byte(struct lp8727_chg *pchg, u8 reg,
|
||||
u8 *data)
|
||||
{
|
||||
return lp8727_i2c_write(pchg, reg, data, 1);
|
||||
}
|
||||
|
||||
static int lp8727_is_charger_attached(const char *name, int id)
|
||||
{
|
||||
if (name) {
|
||||
if (!strcmp(name, "ac"))
|
||||
return (id == ID_TA || id == ID_DEDICATED_CHG) ? 1 : 0;
|
||||
else if (!strcmp(name, "usb"))
|
||||
return (id == ID_USB_CHG) ? 1 : 0;
|
||||
}
|
||||
|
||||
return (id >= ID_TA && id <= ID_USB_CHG) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void lp8727_init_device(struct lp8727_chg *pchg)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
val = ID200_EN | ADC_EN | CP_EN;
|
||||
if (lp8727_i2c_write_byte(pchg, CTRL1, &val))
|
||||
dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL1);
|
||||
|
||||
val = INT_EN | CHGDET_EN;
|
||||
if (lp8727_i2c_write_byte(pchg, CTRL2, &val))
|
||||
dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL2);
|
||||
}
|
||||
|
||||
static int lp8727_is_dedicated_charger(struct lp8727_chg *pchg)
|
||||
{
|
||||
u8 val;
|
||||
lp8727_i2c_read_byte(pchg, STATUS1, &val);
|
||||
return (val & DCPORT);
|
||||
}
|
||||
|
||||
static int lp8727_is_usb_charger(struct lp8727_chg *pchg)
|
||||
{
|
||||
u8 val;
|
||||
lp8727_i2c_read_byte(pchg, STATUS1, &val);
|
||||
return (val & CHPORT);
|
||||
}
|
||||
|
||||
static void lp8727_ctrl_switch(struct lp8727_chg *pchg, u8 sw)
|
||||
{
|
||||
u8 val = sw;
|
||||
lp8727_i2c_write_byte(pchg, SWCTRL, &val);
|
||||
}
|
||||
|
||||
static void lp8727_id_detection(struct lp8727_chg *pchg, u8 id, int vbusin)
|
||||
{
|
||||
u8 devid = ID_NONE;
|
||||
u8 swctrl = SW_DM1_HiZ | SW_DP2_HiZ;
|
||||
|
||||
switch (id) {
|
||||
case 0x5:
|
||||
devid = ID_TA;
|
||||
pchg->chg_parm = &pchg->pdata->ac;
|
||||
break;
|
||||
case 0xB:
|
||||
if (lp8727_is_dedicated_charger(pchg)) {
|
||||
pchg->chg_parm = &pchg->pdata->ac;
|
||||
devid = ID_DEDICATED_CHG;
|
||||
} else if (lp8727_is_usb_charger(pchg)) {
|
||||
pchg->chg_parm = &pchg->pdata->usb;
|
||||
devid = ID_USB_CHG;
|
||||
swctrl = SW_DM1_DM | SW_DP2_DP;
|
||||
} else if (vbusin) {
|
||||
devid = ID_USB_DS;
|
||||
swctrl = SW_DM1_DM | SW_DP2_DP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
devid = ID_NONE;
|
||||
pchg->chg_parm = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
pchg->devid = devid;
|
||||
lp8727_ctrl_switch(pchg, swctrl);
|
||||
}
|
||||
|
||||
static void lp8727_enable_chgdet(struct lp8727_chg *pchg)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
lp8727_i2c_read_byte(pchg, CTRL2, &val);
|
||||
val |= CHGDET_EN;
|
||||
lp8727_i2c_write_byte(pchg, CTRL2, &val);
|
||||
}
|
||||
|
||||
static void lp8727_delayed_func(struct work_struct *_work)
|
||||
{
|
||||
u8 intstat[2], idno, vbus;
|
||||
struct lp8727_chg *pchg =
|
||||
container_of(_work, struct lp8727_chg, work.work);
|
||||
|
||||
if (lp8727_i2c_read(pchg, INT1, intstat, 2)) {
|
||||
dev_err(pchg->dev, "can not read INT registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
idno = intstat[0] & IDNO;
|
||||
vbus = intstat[0] & VBUS;
|
||||
|
||||
lp8727_id_detection(pchg, idno, vbus);
|
||||
lp8727_enable_chgdet(pchg);
|
||||
|
||||
power_supply_changed(&pchg->psy->ac);
|
||||
power_supply_changed(&pchg->psy->usb);
|
||||
power_supply_changed(&pchg->psy->batt);
|
||||
}
|
||||
|
||||
static irqreturn_t lp8727_isr_func(int irq, void *ptr)
|
||||
{
|
||||
struct lp8727_chg *pchg = ptr;
|
||||
unsigned long delay = msecs_to_jiffies(DEBOUNCE_MSEC);
|
||||
|
||||
queue_delayed_work(pchg->irqthread, &pchg->work, delay);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void lp8727_intr_config(struct lp8727_chg *pchg)
|
||||
{
|
||||
INIT_DELAYED_WORK(&pchg->work, lp8727_delayed_func);
|
||||
|
||||
pchg->irqthread = create_singlethread_workqueue("lp8727-irqthd");
|
||||
if (!pchg->irqthread)
|
||||
dev_err(pchg->dev, "can not create thread for lp8727\n");
|
||||
|
||||
if (request_threaded_irq(pchg->client->irq,
|
||||
NULL,
|
||||
lp8727_isr_func,
|
||||
IRQF_TRIGGER_FALLING, "lp8727_irq", pchg)) {
|
||||
dev_err(pchg->dev, "lp8727 irq can not be registered\n");
|
||||
}
|
||||
}
|
||||
|
||||
static enum power_supply_property lp8727_charger_prop[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static enum power_supply_property lp8727_battery_prop[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
};
|
||||
|
||||
static char *battery_supplied_to[] = {
|
||||
"main_batt",
|
||||
};
|
||||
|
||||
static int lp8727_charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent);
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_ONLINE)
|
||||
val->intval = lp8727_is_charger_attached(psy->name,
|
||||
pchg->devid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8727_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent);
|
||||
u8 read;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (lp8727_is_charger_attached(psy->name, pchg->devid)) {
|
||||
lp8727_i2c_read_byte(pchg, STATUS1, &read);
|
||||
if (((read & CHGSTAT) >> 4) == EOC)
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
} else {
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
lp8727_i2c_read_byte(pchg, STATUS2, &read);
|
||||
read = (read & TEMP_STAT) >> 5;
|
||||
if (read >= 0x1 && read <= 0x3)
|
||||
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
if (pchg->pdata->get_batt_present)
|
||||
val->intval = pchg->pdata->get_batt_present();
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
if (pchg->pdata->get_batt_level)
|
||||
val->intval = pchg->pdata->get_batt_level();
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
if (pchg->pdata->get_batt_capacity)
|
||||
val->intval = pchg->pdata->get_batt_capacity();
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
if (pchg->pdata->get_batt_temp)
|
||||
val->intval = pchg->pdata->get_batt_temp();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lp8727_charger_changed(struct power_supply *psy)
|
||||
{
|
||||
struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent);
|
||||
u8 val;
|
||||
u8 eoc_level, ichg;
|
||||
|
||||
if (lp8727_is_charger_attached(psy->name, pchg->devid)) {
|
||||
if (pchg->chg_parm) {
|
||||
eoc_level = pchg->chg_parm->eoc_level;
|
||||
ichg = pchg->chg_parm->ichg;
|
||||
val = (ichg << 4) | eoc_level;
|
||||
lp8727_i2c_write_byte(pchg, CHGCTRL2, &val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int lp8727_register_psy(struct lp8727_chg *pchg)
|
||||
{
|
||||
struct lp8727_psy *psy;
|
||||
|
||||
psy = kzalloc(sizeof(*psy), GFP_KERNEL);
|
||||
if (!psy)
|
||||
goto err_mem;
|
||||
|
||||
pchg->psy = psy;
|
||||
|
||||
psy->ac.name = "ac";
|
||||
psy->ac.type = POWER_SUPPLY_TYPE_MAINS;
|
||||
psy->ac.properties = lp8727_charger_prop;
|
||||
psy->ac.num_properties = ARRAY_SIZE(lp8727_charger_prop);
|
||||
psy->ac.get_property = lp8727_charger_get_property;
|
||||
psy->ac.supplied_to = battery_supplied_to;
|
||||
psy->ac.num_supplicants = ARRAY_SIZE(battery_supplied_to);
|
||||
|
||||
if (power_supply_register(pchg->dev, &psy->ac))
|
||||
goto err_psy;
|
||||
|
||||
psy->usb.name = "usb";
|
||||
psy->usb.type = POWER_SUPPLY_TYPE_USB;
|
||||
psy->usb.properties = lp8727_charger_prop;
|
||||
psy->usb.num_properties = ARRAY_SIZE(lp8727_charger_prop);
|
||||
psy->usb.get_property = lp8727_charger_get_property;
|
||||
psy->usb.supplied_to = battery_supplied_to;
|
||||
psy->usb.num_supplicants = ARRAY_SIZE(battery_supplied_to);
|
||||
|
||||
if (power_supply_register(pchg->dev, &psy->usb))
|
||||
goto err_psy;
|
||||
|
||||
psy->batt.name = "main_batt";
|
||||
psy->batt.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
psy->batt.properties = lp8727_battery_prop;
|
||||
psy->batt.num_properties = ARRAY_SIZE(lp8727_battery_prop);
|
||||
psy->batt.get_property = lp8727_battery_get_property;
|
||||
psy->batt.external_power_changed = lp8727_charger_changed;
|
||||
|
||||
if (power_supply_register(pchg->dev, &psy->batt))
|
||||
goto err_psy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_mem:
|
||||
return -ENOMEM;
|
||||
err_psy:
|
||||
kfree(psy);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void lp8727_unregister_psy(struct lp8727_chg *pchg)
|
||||
{
|
||||
struct lp8727_psy *psy = pchg->psy;
|
||||
|
||||
if (!psy)
|
||||
return;
|
||||
|
||||
power_supply_unregister(&psy->ac);
|
||||
power_supply_unregister(&psy->usb);
|
||||
power_supply_unregister(&psy->batt);
|
||||
kfree(psy);
|
||||
}
|
||||
|
||||
static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id)
|
||||
{
|
||||
struct lp8727_chg *pchg;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -EIO;
|
||||
|
||||
pchg = kzalloc(sizeof(*pchg), GFP_KERNEL);
|
||||
if (!pchg)
|
||||
return -ENOMEM;
|
||||
|
||||
pchg->client = cl;
|
||||
pchg->dev = &cl->dev;
|
||||
pchg->pdata = cl->dev.platform_data;
|
||||
i2c_set_clientdata(cl, pchg);
|
||||
|
||||
mutex_init(&pchg->xfer_lock);
|
||||
|
||||
lp8727_init_device(pchg);
|
||||
lp8727_intr_config(pchg);
|
||||
|
||||
ret = lp8727_register_psy(pchg);
|
||||
if (ret)
|
||||
dev_err(pchg->dev,
|
||||
"can not register power supplies. err=%d", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit lp8727_remove(struct i2c_client *cl)
|
||||
{
|
||||
struct lp8727_chg *pchg = i2c_get_clientdata(cl);
|
||||
|
||||
lp8727_unregister_psy(pchg);
|
||||
free_irq(pchg->client->irq, pchg);
|
||||
flush_workqueue(pchg->irqthread);
|
||||
destroy_workqueue(pchg->irqthread);
|
||||
kfree(pchg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lp8727_ids[] = {
|
||||
{"lp8727", 0},
|
||||
};
|
||||
|
||||
static struct i2c_driver lp8727_driver = {
|
||||
.driver = {
|
||||
.name = "lp8727",
|
||||
},
|
||||
.probe = lp8727_probe,
|
||||
.remove = __devexit_p(lp8727_remove),
|
||||
.id_table = lp8727_ids,
|
||||
};
|
||||
|
||||
static int __init lp8727_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lp8727_driver);
|
||||
}
|
||||
|
||||
static void __exit lp8727_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lp8727_driver);
|
||||
}
|
||||
|
||||
module_init(lp8727_init);
|
||||
module_exit(lp8727_exit);
|
||||
|
||||
MODULE_DESCRIPTION("National Semiconductor LP8727 charger driver");
|
||||
MODULE_AUTHOR
|
||||
("Woogyom Kim <milo.kim@ti.com>, Daniel Jeong <daniel.jeong@ti.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -85,55 +85,79 @@ static int max17042_get_property(struct power_supply *psy,
|
||||
{
|
||||
struct max17042_chip *chip = container_of(psy,
|
||||
struct max17042_chip, battery);
|
||||
int ret;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_STATUS);
|
||||
if (val->intval & MAX17042_STATUS_BattAbsent)
|
||||
ret = max17042_read_reg(chip->client, MAX17042_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret & MAX17042_STATUS_BattAbsent)
|
||||
val->intval = 0;
|
||||
else
|
||||
val->intval = 1;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CYCLE_COUNT:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_Cycles);
|
||||
ret = max17042_read_reg(chip->client, MAX17042_Cycles);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_MinMaxVolt);
|
||||
val->intval >>= 8;
|
||||
ret = max17042_read_reg(chip->client, MAX17042_MinMaxVolt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret >> 8;
|
||||
val->intval *= 20000; /* Units of LSB = 20mV */
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_V_empty);
|
||||
val->intval >>= 7;
|
||||
ret = max17042_read_reg(chip->client, MAX17042_V_empty);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret >> 7;
|
||||
val->intval *= 10000; /* Units of LSB = 10mV */
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
|
||||
ret = max17042_read_reg(chip->client, MAX17042_VCELL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret * 625 / 8;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_AvgVCELL) * 83;
|
||||
ret = max17042_read_reg(chip->client, MAX17042_AvgVCELL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret * 625 / 8;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_SOC) / 256;
|
||||
ret = max17042_read_reg(chip->client, MAX17042_SOC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret >> 8;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_RepSOC);
|
||||
if ((val->intval / 256) >= MAX17042_BATTERY_FULL)
|
||||
ret = max17042_read_reg(chip->client, MAX17042_RepSOC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret >> 8) >= MAX17042_BATTERY_FULL)
|
||||
val->intval = 1;
|
||||
else if (val->intval >= 0)
|
||||
else if (ret >= 0)
|
||||
val->intval = 0;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_TEMP);
|
||||
ret = max17042_read_reg(chip->client, MAX17042_TEMP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret;
|
||||
/* The value is signed. */
|
||||
if (val->intval & 0x8000) {
|
||||
val->intval = (0x7fff & ~val->intval) + 1;
|
||||
@ -145,24 +169,30 @@ static int max17042_get_property(struct power_supply *psy,
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
if (chip->pdata->enable_current_sense) {
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_Current);
|
||||
ret = max17042_read_reg(chip->client, MAX17042_Current);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret;
|
||||
if (val->intval & 0x8000) {
|
||||
/* Negative */
|
||||
val->intval = ~val->intval & 0x7fff;
|
||||
val->intval++;
|
||||
val->intval *= -1;
|
||||
}
|
||||
val->intval >>= 4;
|
||||
val->intval *= 1000000 * 25 / chip->pdata->r_sns;
|
||||
val->intval *= 1562500 / chip->pdata->r_sns;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
if (chip->pdata->enable_current_sense) {
|
||||
val->intval = max17042_read_reg(chip->client,
|
||||
MAX17042_AvgCurrent);
|
||||
ret = max17042_read_reg(chip->client,
|
||||
MAX17042_AvgCurrent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ret;
|
||||
if (val->intval & 0x8000) {
|
||||
/* Negative */
|
||||
val->intval = ~val->intval & 0x7fff;
|
||||
@ -210,6 +240,9 @@ static int __devinit max17042_probe(struct i2c_client *client,
|
||||
if (!chip->pdata->enable_current_sense)
|
||||
chip->battery.num_properties -= 2;
|
||||
|
||||
if (chip->pdata->r_sns == 0)
|
||||
chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
|
||||
|
||||
ret = power_supply_register(&client->dev, &chip->battery);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed: power supply register\n");
|
||||
@ -226,9 +259,6 @@ static int __devinit max17042_probe(struct i2c_client *client,
|
||||
max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
|
||||
max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
|
||||
max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
|
||||
} else {
|
||||
if (chip->pdata->r_sns == 0)
|
||||
chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -374,19 +374,9 @@ static struct platform_driver max8903_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init max8903_init(void)
|
||||
{
|
||||
return platform_driver_register(&max8903_driver);
|
||||
}
|
||||
module_init(max8903_init);
|
||||
|
||||
static void __exit max8903_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&max8903_driver);
|
||||
}
|
||||
module_exit(max8903_exit);
|
||||
module_platform_driver(max8903_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("MAX8903 Charger Driver");
|
||||
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||
MODULE_ALIAS("max8903-charger");
|
||||
MODULE_ALIAS("platform:max8903-charger");
|
||||
|
@ -78,6 +78,8 @@ struct max8925_power_info {
|
||||
unsigned batt_detect:1; /* detecing MB by ID pin */
|
||||
unsigned topoff_threshold:2;
|
||||
unsigned fast_charge:3;
|
||||
unsigned no_temp_support:1;
|
||||
unsigned no_insert_detect:1;
|
||||
|
||||
int (*set_charger) (int);
|
||||
};
|
||||
@ -116,17 +118,7 @@ static irqreturn_t max8925_charger_handler(int irq, void *data)
|
||||
case MAX8925_IRQ_VCHG_DC_F:
|
||||
info->ac_online = 0;
|
||||
__set_charger(info, 0);
|
||||
dev_dbg(chip->dev, "Adapter is removal\n");
|
||||
break;
|
||||
case MAX8925_IRQ_VCHG_USB_R:
|
||||
info->usb_online = 1;
|
||||
__set_charger(info, 1);
|
||||
dev_dbg(chip->dev, "USB inserted\n");
|
||||
break;
|
||||
case MAX8925_IRQ_VCHG_USB_F:
|
||||
info->usb_online = 0;
|
||||
__set_charger(info, 0);
|
||||
dev_dbg(chip->dev, "USB is removal\n");
|
||||
dev_dbg(chip->dev, "Adapter removed\n");
|
||||
break;
|
||||
case MAX8925_IRQ_VCHG_THM_OK_F:
|
||||
/* Battery is not ready yet */
|
||||
@ -168,27 +160,33 @@ static irqreturn_t max8925_charger_handler(int irq, void *data)
|
||||
static int start_measure(struct max8925_power_info *info, int type)
|
||||
{
|
||||
unsigned char buf[2] = {0, 0};
|
||||
int meas_cmd;
|
||||
int meas_reg = 0, ret;
|
||||
|
||||
switch (type) {
|
||||
case MEASURE_VCHG:
|
||||
meas_cmd = MAX8925_CMD_VCHG;
|
||||
meas_reg = MAX8925_ADC_VCHG;
|
||||
break;
|
||||
case MEASURE_VBBATT:
|
||||
meas_cmd = MAX8925_CMD_VBBATT;
|
||||
meas_reg = MAX8925_ADC_VBBATT;
|
||||
break;
|
||||
case MEASURE_VMBATT:
|
||||
meas_cmd = MAX8925_CMD_VMBATT;
|
||||
meas_reg = MAX8925_ADC_VMBATT;
|
||||
break;
|
||||
case MEASURE_ISNS:
|
||||
meas_cmd = MAX8925_CMD_ISNS;
|
||||
meas_reg = MAX8925_ADC_ISNS;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
max8925_reg_write(info->adc, meas_cmd, 0);
|
||||
max8925_bulk_read(info->adc, meas_reg, 2, buf);
|
||||
ret = (buf[0] << 4) | (buf[1] >> 4);
|
||||
ret = ((buf[0]<<8) | buf[1]) >> 4;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -208,7 +206,7 @@ static int max8925_ac_get_prop(struct power_supply *psy,
|
||||
if (info->ac_online) {
|
||||
ret = start_measure(info, MEASURE_VCHG);
|
||||
if (ret >= 0) {
|
||||
val->intval = ret << 1; /* unit is mV */
|
||||
val->intval = ret * 2000; /* unit is uV */
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -242,7 +240,7 @@ static int max8925_usb_get_prop(struct power_supply *psy,
|
||||
if (info->usb_online) {
|
||||
ret = start_measure(info, MEASURE_VCHG);
|
||||
if (ret >= 0) {
|
||||
val->intval = ret << 1; /* unit is mV */
|
||||
val->intval = ret * 2000; /* unit is uV */
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -266,7 +264,6 @@ static int max8925_bat_get_prop(struct power_supply *psy,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
|
||||
long long int tmp = 0;
|
||||
int ret = 0;
|
||||
|
||||
switch (psp) {
|
||||
@ -277,7 +274,7 @@ static int max8925_bat_get_prop(struct power_supply *psy,
|
||||
if (info->bat_online) {
|
||||
ret = start_measure(info, MEASURE_VMBATT);
|
||||
if (ret >= 0) {
|
||||
val->intval = ret << 1; /* unit is mV */
|
||||
val->intval = ret * 2000; /* unit is uV */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@ -288,8 +285,8 @@ static int max8925_bat_get_prop(struct power_supply *psy,
|
||||
if (info->bat_online) {
|
||||
ret = start_measure(info, MEASURE_ISNS);
|
||||
if (ret >= 0) {
|
||||
tmp = (long long int)ret * 6250 / 4096 - 3125;
|
||||
ret = (int)tmp;
|
||||
/* assume r_sns is 0.02 */
|
||||
ret = ((ret * 6250) - 3125) /* uA */;
|
||||
val->intval = 0;
|
||||
if (ret > 0)
|
||||
val->intval = ret; /* unit is mA */
|
||||
@ -365,13 +362,14 @@ static __devinit int max8925_init_charger(struct max8925_chip *chip,
|
||||
int ret;
|
||||
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_OVP, "usb-ovp");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_F, "usb-remove");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_R, "usb-insert");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range");
|
||||
if (!info->no_insert_detect) {
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert");
|
||||
}
|
||||
if (!info->no_temp_support) {
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range");
|
||||
}
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset");
|
||||
@ -379,9 +377,15 @@ static __devinit int max8925_init_charger(struct max8925_chip *chip,
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff");
|
||||
REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire");
|
||||
|
||||
info->ac_online = 0;
|
||||
info->usb_online = 0;
|
||||
info->bat_online = 0;
|
||||
|
||||
/* check for power - can miss interrupt at boot time */
|
||||
if (start_measure(info, MEASURE_VCHG) * 2000 > 500000)
|
||||
info->ac_online = 1;
|
||||
else
|
||||
info->ac_online = 0;
|
||||
|
||||
ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
|
||||
if (ret >= 0) {
|
||||
/*
|
||||
@ -449,6 +453,8 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
|
||||
info->ac.properties = max8925_ac_props;
|
||||
info->ac.num_properties = ARRAY_SIZE(max8925_ac_props);
|
||||
info->ac.get_property = max8925_ac_get_prop;
|
||||
info->ac.supplied_to = pdata->supplied_to;
|
||||
info->ac.num_supplicants = pdata->num_supplicants;
|
||||
ret = power_supply_register(&pdev->dev, &info->ac);
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -459,6 +465,9 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
|
||||
info->usb.properties = max8925_usb_props;
|
||||
info->usb.num_properties = ARRAY_SIZE(max8925_usb_props);
|
||||
info->usb.get_property = max8925_usb_get_prop;
|
||||
info->usb.supplied_to = pdata->supplied_to;
|
||||
info->usb.num_supplicants = pdata->num_supplicants;
|
||||
|
||||
ret = power_supply_register(&pdev->dev, &info->usb);
|
||||
if (ret)
|
||||
goto out_usb;
|
||||
@ -478,6 +487,8 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
|
||||
info->topoff_threshold = pdata->topoff_threshold;
|
||||
info->fast_charge = pdata->fast_charge;
|
||||
info->set_charger = pdata->set_charger;
|
||||
info->no_temp_support = pdata->no_temp_support;
|
||||
info->no_insert_detect = pdata->no_insert_detect;
|
||||
|
||||
max8925_init_charger(chip, info);
|
||||
return 0;
|
||||
@ -512,17 +523,7 @@ static struct platform_driver max8925_power_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init max8925_power_init(void)
|
||||
{
|
||||
return platform_driver_register(&max8925_power_driver);
|
||||
}
|
||||
module_init(max8925_power_init);
|
||||
|
||||
static void __exit max8925_power_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&max8925_power_driver);
|
||||
}
|
||||
module_exit(max8925_power_exit);
|
||||
module_platform_driver(max8925_power_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Power supply driver for MAX8925");
|
||||
|
@ -19,7 +19,6 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@ -98,7 +97,7 @@ static __devinit int max8997_battery_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
|
||||
if (pdata->eoc_mA) {
|
||||
u8 val = (pdata->eoc_mA - 50) / 10;
|
||||
int val = (pdata->eoc_mA - 50) / 10;
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
if (val > 0xf)
|
||||
@ -179,6 +178,7 @@ static int __devexit max8997_battery_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct platform_device_id max8997_battery_id[] = {
|
||||
{ "max8997-battery", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver max8997_battery_driver = {
|
||||
|
@ -154,6 +154,7 @@ static __devinit int max8998_battery_probe(struct platform_device *pdev)
|
||||
case 0:
|
||||
dev_dbg(max8998->dev,
|
||||
"Full Timeout not set: leave it unchanged.\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(max8998->dev, "Invalid Full Timeout value\n");
|
||||
ret = -EINVAL;
|
||||
@ -190,6 +191,7 @@ static int __devexit max8998_battery_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct platform_device_id max8998_battery_id[] = {
|
||||
{ "max8998-battery", TYPE_MAX8998 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver max8998_battery_driver = {
|
||||
@ -202,17 +204,7 @@ static struct platform_driver max8998_battery_driver = {
|
||||
.id_table = max8998_battery_id,
|
||||
};
|
||||
|
||||
static int __init max8998_battery_init(void)
|
||||
{
|
||||
return platform_driver_register(&max8998_battery_driver);
|
||||
}
|
||||
module_init(max8998_battery_init);
|
||||
|
||||
static void __exit max8998_battery_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&max8998_battery_driver);
|
||||
}
|
||||
module_exit(max8998_battery_cleanup);
|
||||
module_platform_driver(max8998_battery_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 8998 battery control driver");
|
||||
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||
|
@ -519,29 +519,35 @@ static struct device_attribute olpc_bat_error = {
|
||||
* Initialisation
|
||||
*********************************************************************/
|
||||
|
||||
static struct platform_device *bat_pdev;
|
||||
|
||||
static struct power_supply olpc_bat = {
|
||||
.name = "olpc-battery",
|
||||
.get_property = olpc_bat_get_property,
|
||||
.use_for_apm = 1,
|
||||
};
|
||||
|
||||
void olpc_battery_trigger_uevent(unsigned long cause)
|
||||
static int olpc_battery_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
{
|
||||
if (cause & EC_SCI_SRC_ACPWR)
|
||||
kobject_uevent(&olpc_ac.dev->kobj, KOBJ_CHANGE);
|
||||
if (cause & (EC_SCI_SRC_BATERR|EC_SCI_SRC_BATSOC|EC_SCI_SRC_BATTERY))
|
||||
kobject_uevent(&olpc_bat.dev->kobj, KOBJ_CHANGE);
|
||||
if (device_may_wakeup(olpc_ac.dev))
|
||||
olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR);
|
||||
else
|
||||
olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR);
|
||||
|
||||
if (device_may_wakeup(olpc_bat.dev))
|
||||
olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
|
||||
| EC_SCI_SRC_BATERR);
|
||||
else
|
||||
olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
|
||||
| EC_SCI_SRC_BATERR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init olpc_bat_init(void)
|
||||
static int __devinit olpc_battery_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
uint8_t status;
|
||||
|
||||
if (!olpc_platform_info.ecver)
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* We've seen a number of EC protocol changes; this driver requires
|
||||
* the latest EC protocol, supported by 0x44 and above.
|
||||
@ -558,15 +564,10 @@ static int __init olpc_bat_init(void)
|
||||
|
||||
/* Ignore the status. It doesn't actually matter */
|
||||
|
||||
bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
|
||||
if (IS_ERR(bat_pdev))
|
||||
return PTR_ERR(bat_pdev);
|
||||
|
||||
ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
|
||||
ret = power_supply_register(&pdev->dev, &olpc_ac);
|
||||
if (ret)
|
||||
goto ac_failed;
|
||||
return ret;
|
||||
|
||||
olpc_bat.name = bat_pdev->name;
|
||||
if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
|
||||
olpc_bat.properties = olpc_xo15_bat_props;
|
||||
olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
|
||||
@ -575,7 +576,7 @@ static int __init olpc_bat_init(void)
|
||||
olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
|
||||
}
|
||||
|
||||
ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
|
||||
ret = power_supply_register(&pdev->dev, &olpc_bat);
|
||||
if (ret)
|
||||
goto battery_failed;
|
||||
|
||||
@ -587,7 +588,12 @@ static int __init olpc_bat_init(void)
|
||||
if (ret)
|
||||
goto error_failed;
|
||||
|
||||
goto success;
|
||||
if (olpc_ec_wakeup_available()) {
|
||||
device_set_wakeup_capable(olpc_ac.dev, true);
|
||||
device_set_wakeup_capable(olpc_bat.dev, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_failed:
|
||||
device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
|
||||
@ -595,23 +601,36 @@ eeprom_failed:
|
||||
power_supply_unregister(&olpc_bat);
|
||||
battery_failed:
|
||||
power_supply_unregister(&olpc_ac);
|
||||
ac_failed:
|
||||
platform_device_unregister(bat_pdev);
|
||||
success:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit olpc_bat_exit(void)
|
||||
static int __devexit olpc_battery_remove(struct platform_device *pdev)
|
||||
{
|
||||
device_remove_file(olpc_bat.dev, &olpc_bat_error);
|
||||
device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
|
||||
power_supply_unregister(&olpc_bat);
|
||||
power_supply_unregister(&olpc_ac);
|
||||
platform_device_unregister(bat_pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(olpc_bat_init);
|
||||
module_exit(olpc_bat_exit);
|
||||
static const struct of_device_id olpc_battery_ids[] __devinitconst = {
|
||||
{ .compatible = "olpc,xo1-battery" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, olpc_battery_ids);
|
||||
|
||||
static struct platform_driver olpc_battery_driver = {
|
||||
.driver = {
|
||||
.name = "olpc-battery",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = olpc_battery_ids,
|
||||
},
|
||||
.probe = olpc_battery_probe,
|
||||
.remove = __devexit_p(olpc_battery_remove),
|
||||
.suspend = olpc_battery_suspend,
|
||||
};
|
||||
|
||||
module_platform_driver(olpc_battery_driver);
|
||||
|
||||
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -474,17 +474,7 @@ static struct platform_driver pcf50633_mbc_driver = {
|
||||
.remove = __devexit_p(pcf50633_mbc_remove),
|
||||
};
|
||||
|
||||
static int __init pcf50633_mbc_init(void)
|
||||
{
|
||||
return platform_driver_register(&pcf50633_mbc_driver);
|
||||
}
|
||||
module_init(pcf50633_mbc_init);
|
||||
|
||||
static void __exit pcf50633_mbc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pcf50633_mbc_driver);
|
||||
}
|
||||
module_exit(pcf50633_mbc_exit);
|
||||
module_platform_driver(pcf50633_mbc_driver);
|
||||
|
||||
MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
|
||||
MODULE_DESCRIPTION("PCF50633 mbc driver");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/pda_power.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@ -40,7 +41,9 @@ static int polling;
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
static struct otg_transceiver *transceiver;
|
||||
static struct notifier_block otg_nb;
|
||||
#endif
|
||||
|
||||
static struct regulator *ac_draw;
|
||||
|
||||
enum {
|
||||
@ -222,7 +225,42 @@ static void polling_timer_func(unsigned long unused)
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
static int otg_is_usb_online(void)
|
||||
{
|
||||
return (transceiver->state == OTG_STATE_B_PERIPHERAL);
|
||||
return (transceiver->last_event == USB_EVENT_VBUS ||
|
||||
transceiver->last_event == USB_EVENT_ENUMERATED);
|
||||
}
|
||||
|
||||
static int otg_is_ac_online(void)
|
||||
{
|
||||
return (transceiver->last_event == USB_EVENT_CHARGER);
|
||||
}
|
||||
|
||||
static int otg_handle_notification(struct notifier_block *nb,
|
||||
unsigned long event, void *unused)
|
||||
{
|
||||
switch (event) {
|
||||
case USB_EVENT_CHARGER:
|
||||
ac_status = PDA_PSY_TO_CHANGE;
|
||||
break;
|
||||
case USB_EVENT_VBUS:
|
||||
case USB_EVENT_ENUMERATED:
|
||||
usb_status = PDA_PSY_TO_CHANGE;
|
||||
break;
|
||||
case USB_EVENT_NONE:
|
||||
ac_status = PDA_PSY_TO_CHANGE;
|
||||
usb_status = PDA_PSY_TO_CHANGE;
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait a bit before reading ac/usb line status and setting charger,
|
||||
* because ac/usb status readings may lag from irq.
|
||||
*/
|
||||
mod_timer(&charger_timer,
|
||||
jiffies + msecs_to_jiffies(pdata->wait_for_status));
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -282,6 +320,16 @@ static int pda_power_probe(struct platform_device *pdev)
|
||||
ret = PTR_ERR(ac_draw);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
transceiver = otg_get_transceiver();
|
||||
if (transceiver && !pdata->is_usb_online) {
|
||||
pdata->is_usb_online = otg_is_usb_online;
|
||||
}
|
||||
if (transceiver && !pdata->is_ac_online) {
|
||||
pdata->is_ac_online = otg_is_ac_online;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pdata->is_ac_online) {
|
||||
ret = power_supply_register(&pdev->dev, &pda_psy_ac);
|
||||
if (ret) {
|
||||
@ -303,13 +351,6 @@ static int pda_power_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
transceiver = otg_get_transceiver();
|
||||
if (transceiver && !pdata->is_usb_online) {
|
||||
pdata->is_usb_online = otg_is_usb_online;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pdata->is_usb_online) {
|
||||
ret = power_supply_register(&pdev->dev, &pda_psy_usb);
|
||||
if (ret) {
|
||||
@ -331,6 +372,18 @@ static int pda_power_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (transceiver && pdata->use_otg_notifier) {
|
||||
otg_nb.notifier_call = otg_handle_notification;
|
||||
ret = otg_register_notifier(transceiver, &otg_nb);
|
||||
if (ret) {
|
||||
dev_err(dev, "failure to register otg notifier\n");
|
||||
goto otg_reg_notifier_failed;
|
||||
}
|
||||
polling = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (polling) {
|
||||
dev_dbg(dev, "will poll for status\n");
|
||||
setup_timer(&polling_timer, polling_timer_func, 0);
|
||||
@ -343,6 +396,11 @@ static int pda_power_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
otg_reg_notifier_failed:
|
||||
if (pdata->is_usb_online && usb_irq)
|
||||
free_irq(usb_irq->start, &pda_psy_usb);
|
||||
#endif
|
||||
usb_irq_failed:
|
||||
if (pdata->is_usb_online)
|
||||
power_supply_unregister(&pda_psy_usb);
|
||||
@ -440,8 +498,6 @@ static int pda_power_resume(struct platform_device *pdev)
|
||||
#define pda_power_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
MODULE_ALIAS("platform:pda-power");
|
||||
|
||||
static struct platform_driver pda_power_pdrv = {
|
||||
.driver = {
|
||||
.name = "pda-power",
|
||||
@ -452,17 +508,8 @@ static struct platform_driver pda_power_pdrv = {
|
||||
.resume = pda_power_resume,
|
||||
};
|
||||
|
||||
static int __init pda_power_init(void)
|
||||
{
|
||||
return platform_driver_register(&pda_power_pdrv);
|
||||
}
|
||||
module_platform_driver(pda_power_pdrv);
|
||||
|
||||
static void __exit pda_power_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pda_power_pdrv);
|
||||
}
|
||||
|
||||
module_init(pda_power_init);
|
||||
module_exit(pda_power_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
|
||||
MODULE_ALIAS("platform:pda-power");
|
||||
|
@ -98,7 +98,9 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data)
|
||||
{
|
||||
union power_supply_propval ret = {0,};
|
||||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
unsigned int *count = data;
|
||||
|
||||
(*count)++;
|
||||
if (psy->type != POWER_SUPPLY_TYPE_BATTERY) {
|
||||
if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
|
||||
return 0;
|
||||
@ -111,10 +113,18 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data)
|
||||
int power_supply_is_system_supplied(void)
|
||||
{
|
||||
int error;
|
||||
unsigned int count = 0;
|
||||
|
||||
error = class_for_each_device(power_supply_class, NULL, NULL,
|
||||
error = class_for_each_device(power_supply_class, NULL, &count,
|
||||
__power_supply_is_system_supplied);
|
||||
|
||||
/*
|
||||
* If no power class device was found at all, most probably we are
|
||||
* running on a desktop system, so assume we are on mains power.
|
||||
*/
|
||||
if (count == 0)
|
||||
return 1;
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
|
||||
@ -147,6 +157,12 @@ struct power_supply *power_supply_get_by_name(char *name)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_get_by_name);
|
||||
|
||||
int power_supply_powers(struct power_supply *psy, struct device *dev)
|
||||
{
|
||||
return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_powers);
|
||||
|
||||
static void power_supply_dev_release(struct device *dev)
|
||||
{
|
||||
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
|
||||
@ -202,6 +218,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
|
||||
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);
|
||||
device_unregister(psy->dev);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ static ssize_t power_supply_show_property(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
static char *type_text[] = {
|
||||
"Battery", "UPS", "Mains", "USB",
|
||||
"Unknown", "Battery", "UPS", "Mains", "USB",
|
||||
"USB_DCP", "USB_CDP", "USB_ACA"
|
||||
};
|
||||
static char *status_text[] = {
|
||||
@ -63,6 +63,9 @@ static ssize_t power_supply_show_property(struct device *dev,
|
||||
static char *capacity_level_text[] = {
|
||||
"Unknown", "Critical", "Low", "Normal", "High", "Full"
|
||||
};
|
||||
static char *scope_text[] = {
|
||||
"Unknown", "System", "Device"
|
||||
};
|
||||
ssize_t ret = 0;
|
||||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
const ptrdiff_t off = attr - power_supply_attrs;
|
||||
@ -78,8 +81,8 @@ static ssize_t power_supply_show_property(struct device *dev,
|
||||
dev_dbg(dev, "driver has no data for `%s' property\n",
|
||||
attr->attr.name);
|
||||
else if (ret != -ENODEV)
|
||||
dev_err(dev, "driver failed to report `%s' property\n",
|
||||
attr->attr.name);
|
||||
dev_err(dev, "driver failed to report `%s' property: %zd\n",
|
||||
attr->attr.name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -95,6 +98,8 @@ static ssize_t power_supply_show_property(struct device *dev,
|
||||
return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
|
||||
else if (off == POWER_SUPPLY_PROP_TYPE)
|
||||
return sprintf(buf, "%s\n", type_text[value.intval]);
|
||||
else if (off == POWER_SUPPLY_PROP_SCOPE)
|
||||
return sprintf(buf, "%s\n", scope_text[value.intval]);
|
||||
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
|
||||
return sprintf(buf, "%s\n", value.strval);
|
||||
|
||||
@ -167,6 +172,7 @@ static struct device_attribute power_supply_attrs[] = {
|
||||
POWER_SUPPLY_ATTR(time_to_full_now),
|
||||
POWER_SUPPLY_ATTR(time_to_full_avg),
|
||||
POWER_SUPPLY_ATTR(type),
|
||||
POWER_SUPPLY_ATTR(scope),
|
||||
/* Properties of type `const char *' */
|
||||
POWER_SUPPLY_ATTR(model_name),
|
||||
POWER_SUPPLY_ATTR(manufacturer),
|
||||
|
@ -47,6 +47,22 @@ static void s3c_adc_bat_ext_power_changed(struct power_supply *psy)
|
||||
msecs_to_jiffies(JITTER_DELAY));
|
||||
}
|
||||
|
||||
static int gather_samples(struct s3c_adc_client *client, int num, int channel)
|
||||
{
|
||||
int value, i;
|
||||
|
||||
/* default to 1 if nothing is set */
|
||||
if (num < 1)
|
||||
num = 1;
|
||||
|
||||
value = 0;
|
||||
for (i = 0; i < num; i++)
|
||||
value += s3c_adc_read(client, channel);
|
||||
value /= num;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static enum power_supply_property s3c_adc_backup_bat_props[] = {
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN,
|
||||
@ -67,7 +83,8 @@ static int s3c_adc_backup_bat_get_property(struct power_supply *psy,
|
||||
if (bat->volt_value < 0 ||
|
||||
jiffies_to_msecs(jiffies - bat->timestamp) >
|
||||
BAT_POLL_INTERVAL) {
|
||||
bat->volt_value = s3c_adc_read(bat->client,
|
||||
bat->volt_value = gather_samples(bat->client,
|
||||
bat->pdata->backup_volt_samples,
|
||||
bat->pdata->backup_volt_channel);
|
||||
bat->volt_value *= bat->pdata->backup_volt_mult;
|
||||
bat->timestamp = jiffies;
|
||||
@ -139,9 +156,11 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
|
||||
if (bat->volt_value < 0 || bat->cur_value < 0 ||
|
||||
jiffies_to_msecs(jiffies - bat->timestamp) >
|
||||
BAT_POLL_INTERVAL) {
|
||||
bat->volt_value = s3c_adc_read(bat->client,
|
||||
bat->volt_value = gather_samples(bat->client,
|
||||
bat->pdata->volt_samples,
|
||||
bat->pdata->volt_channel) * bat->pdata->volt_mult;
|
||||
bat->cur_value = s3c_adc_read(bat->client,
|
||||
bat->cur_value = gather_samples(bat->client,
|
||||
bat->pdata->current_samples,
|
||||
bat->pdata->current_channel) * bat->pdata->current_mult;
|
||||
bat->timestamp = jiffies;
|
||||
}
|
||||
@ -421,17 +440,7 @@ static struct platform_driver s3c_adc_bat_driver = {
|
||||
.resume = s3c_adc_bat_resume,
|
||||
};
|
||||
|
||||
static int __init s3c_adc_bat_init(void)
|
||||
{
|
||||
return platform_driver_register(&s3c_adc_bat_driver);
|
||||
}
|
||||
module_init(s3c_adc_bat_init);
|
||||
|
||||
static void __exit s3c_adc_bat_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&s3c_adc_bat_driver);
|
||||
}
|
||||
module_exit(s3c_adc_bat_exit);
|
||||
module_platform_driver(s3c_adc_bat_driver);
|
||||
|
||||
MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
|
||||
MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Gas Gauge driver for TI's BQ20Z75
|
||||
* Gas Gauge driver for SBS Compliant Batteries
|
||||
*
|
||||
* Copyright (c) 2010, NVIDIA Corporation.
|
||||
*
|
||||
@ -28,7 +28,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <linux/power/bq20z75.h>
|
||||
#include <linux/power/sbs-battery.h>
|
||||
|
||||
enum {
|
||||
REG_MANUFACTURER_DATA,
|
||||
@ -53,7 +53,7 @@ enum {
|
||||
/* Battery Mode defines */
|
||||
#define BATTERY_MODE_OFFSET 0x03
|
||||
#define BATTERY_MODE_MASK 0x8000
|
||||
enum bq20z75_battery_mode {
|
||||
enum sbs_battery_mode {
|
||||
BATTERY_MODE_AMPS,
|
||||
BATTERY_MODE_WATTS
|
||||
};
|
||||
@ -67,62 +67,56 @@ enum bq20z75_battery_mode {
|
||||
#define BATTERY_FULL_CHARGED 0x20
|
||||
#define BATTERY_FULL_DISCHARGED 0x10
|
||||
|
||||
#define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) { \
|
||||
#define SBS_DATA(_psp, _addr, _min_value, _max_value) { \
|
||||
.psp = _psp, \
|
||||
.addr = _addr, \
|
||||
.min_value = _min_value, \
|
||||
.max_value = _max_value, \
|
||||
}
|
||||
|
||||
static const struct bq20z75_device_data {
|
||||
static const struct chip_data {
|
||||
enum power_supply_property psp;
|
||||
u8 addr;
|
||||
int min_value;
|
||||
int max_value;
|
||||
} bq20z75_data[] = {
|
||||
} sbs_data[] = {
|
||||
[REG_MANUFACTURER_DATA] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535),
|
||||
[REG_TEMPERATURE] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535),
|
||||
[REG_VOLTAGE] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000),
|
||||
[REG_CURRENT] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768,
|
||||
32767),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, 32767),
|
||||
[REG_CAPACITY] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
|
||||
[REG_REMAINING_CAPACITY] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
|
||||
[REG_REMAINING_CAPACITY_CHARGE] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
|
||||
[REG_FULL_CHARGE_CAPACITY] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
|
||||
[REG_FULL_CHARGE_CAPACITY_CHARGE] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
|
||||
[REG_TIME_TO_EMPTY] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
|
||||
65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 65535),
|
||||
[REG_TIME_TO_FULL] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0,
|
||||
65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, 65535),
|
||||
[REG_STATUS] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
|
||||
[REG_CYCLE_COUNT] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
|
||||
[REG_DESIGN_CAPACITY] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
|
||||
65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, 65535),
|
||||
[REG_DESIGN_CAPACITY_CHARGE] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0,
|
||||
65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, 65535),
|
||||
[REG_DESIGN_VOLTAGE] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
|
||||
65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, 65535),
|
||||
[REG_SERIAL_NUMBER] =
|
||||
BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
|
||||
SBS_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
|
||||
};
|
||||
|
||||
static enum power_supply_property bq20z75_properties[] = {
|
||||
static enum power_supply_property sbs_properties[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
@ -144,10 +138,10 @@ static enum power_supply_property bq20z75_properties[] = {
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
};
|
||||
|
||||
struct bq20z75_info {
|
||||
struct sbs_info {
|
||||
struct i2c_client *client;
|
||||
struct power_supply power_supply;
|
||||
struct bq20z75_platform_data *pdata;
|
||||
struct sbs_platform_data *pdata;
|
||||
bool is_present;
|
||||
bool gpio_detect;
|
||||
bool enable_detection;
|
||||
@ -158,14 +152,14 @@ struct bq20z75_info {
|
||||
int ignore_changes;
|
||||
};
|
||||
|
||||
static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
|
||||
static int sbs_read_word_data(struct i2c_client *client, u8 address)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
|
||||
struct sbs_info *chip = i2c_get_clientdata(client);
|
||||
s32 ret = 0;
|
||||
int retries = 1;
|
||||
|
||||
if (bq20z75_device->pdata)
|
||||
retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
|
||||
if (chip->pdata)
|
||||
retries = max(chip->pdata->i2c_retry_count + 1, 1);
|
||||
|
||||
while (retries > 0) {
|
||||
ret = i2c_smbus_read_word_data(client, address);
|
||||
@ -184,15 +178,15 @@ static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
|
||||
return le16_to_cpu(ret);
|
||||
}
|
||||
|
||||
static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
|
||||
static int sbs_write_word_data(struct i2c_client *client, u8 address,
|
||||
u16 value)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
|
||||
struct sbs_info *chip = i2c_get_clientdata(client);
|
||||
s32 ret = 0;
|
||||
int retries = 1;
|
||||
|
||||
if (bq20z75_device->pdata)
|
||||
retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
|
||||
if (chip->pdata)
|
||||
retries = max(chip->pdata->i2c_retry_count + 1, 1);
|
||||
|
||||
while (retries > 0) {
|
||||
ret = i2c_smbus_write_word_data(client, address,
|
||||
@ -212,44 +206,41 @@ static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq20z75_get_battery_presence_and_health(
|
||||
static int sbs_get_battery_presence_and_health(
|
||||
struct i2c_client *client, enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
s32 ret;
|
||||
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
|
||||
struct sbs_info *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT &&
|
||||
bq20z75_device->gpio_detect) {
|
||||
ret = gpio_get_value(
|
||||
bq20z75_device->pdata->battery_detect);
|
||||
if (ret == bq20z75_device->pdata->battery_detect_present)
|
||||
chip->gpio_detect) {
|
||||
ret = gpio_get_value(chip->pdata->battery_detect);
|
||||
if (ret == chip->pdata->battery_detect_present)
|
||||
val->intval = 1;
|
||||
else
|
||||
val->intval = 0;
|
||||
bq20z75_device->is_present = val->intval;
|
||||
chip->is_present = val->intval;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write to ManufacturerAccess with
|
||||
* ManufacturerAccess command and then
|
||||
* read the status */
|
||||
ret = bq20z75_write_word_data(client,
|
||||
bq20z75_data[REG_MANUFACTURER_DATA].addr,
|
||||
MANUFACTURER_ACCESS_STATUS);
|
||||
ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
|
||||
MANUFACTURER_ACCESS_STATUS);
|
||||
if (ret < 0) {
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT)
|
||||
val->intval = 0; /* battery removed */
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bq20z75_read_word_data(client,
|
||||
bq20z75_data[REG_MANUFACTURER_DATA].addr);
|
||||
ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value ||
|
||||
ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) {
|
||||
if (ret < sbs_data[REG_MANUFACTURER_DATA].min_value ||
|
||||
ret > sbs_data[REG_MANUFACTURER_DATA].max_value) {
|
||||
val->intval = 0;
|
||||
return 0;
|
||||
}
|
||||
@ -279,24 +270,23 @@ static int bq20z75_get_battery_presence_and_health(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq20z75_get_battery_property(struct i2c_client *client,
|
||||
static int sbs_get_battery_property(struct i2c_client *client,
|
||||
int reg_offset, enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
|
||||
struct sbs_info *chip = i2c_get_clientdata(client);
|
||||
s32 ret;
|
||||
|
||||
ret = bq20z75_read_word_data(client,
|
||||
bq20z75_data[reg_offset].addr);
|
||||
ret = sbs_read_word_data(client, sbs_data[reg_offset].addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* returned values are 16 bit */
|
||||
if (bq20z75_data[reg_offset].min_value < 0)
|
||||
if (sbs_data[reg_offset].min_value < 0)
|
||||
ret = (s16)ret;
|
||||
|
||||
if (ret >= bq20z75_data[reg_offset].min_value &&
|
||||
ret <= bq20z75_data[reg_offset].max_value) {
|
||||
if (ret >= sbs_data[reg_offset].min_value &&
|
||||
ret <= sbs_data[reg_offset].max_value) {
|
||||
val->intval = ret;
|
||||
if (psp != POWER_SUPPLY_PROP_STATUS)
|
||||
return 0;
|
||||
@ -310,12 +300,12 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
|
||||
if (bq20z75_device->poll_time == 0)
|
||||
bq20z75_device->last_state = val->intval;
|
||||
else if (bq20z75_device->last_state != val->intval) {
|
||||
cancel_delayed_work_sync(&bq20z75_device->work);
|
||||
power_supply_changed(&bq20z75_device->power_supply);
|
||||
bq20z75_device->poll_time = 0;
|
||||
if (chip->poll_time == 0)
|
||||
chip->last_state = val->intval;
|
||||
else if (chip->last_state != val->intval) {
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
power_supply_changed(&chip->power_supply);
|
||||
chip->poll_time = 0;
|
||||
}
|
||||
} else {
|
||||
if (psp == POWER_SUPPLY_PROP_STATUS)
|
||||
@ -327,7 +317,7 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bq20z75_unit_adjustment(struct i2c_client *client,
|
||||
static void sbs_unit_adjustment(struct i2c_client *client,
|
||||
enum power_supply_property psp, union power_supply_propval *val)
|
||||
{
|
||||
#define BASE_UNIT_CONVERSION 1000
|
||||
@ -338,7 +328,7 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
|
||||
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
||||
case POWER_SUPPLY_PROP_ENERGY_FULL:
|
||||
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
|
||||
/* bq20z75 provides energy in units of 10mWh.
|
||||
/* sbs provides energy in units of 10mWh.
|
||||
* Convert to µWh
|
||||
*/
|
||||
val->intval *= BATTERY_MODE_CAP_MULT_WATT;
|
||||
@ -354,7 +344,7 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
/* bq20z75 provides battery temperature in 0.1K
|
||||
/* sbs provides battery temperature in 0.1K
|
||||
* so convert it to 0.1°C
|
||||
*/
|
||||
val->intval -= TEMP_KELVIN_TO_CELSIUS;
|
||||
@ -362,7 +352,7 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
|
||||
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
|
||||
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
|
||||
/* bq20z75 provides time to empty and time to full in minutes.
|
||||
/* sbs provides time to empty and time to full in minutes.
|
||||
* Convert to seconds
|
||||
*/
|
||||
val->intval *= TIME_UNIT_CONVERSION;
|
||||
@ -374,13 +364,12 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
static enum bq20z75_battery_mode
|
||||
bq20z75_set_battery_mode(struct i2c_client *client,
|
||||
enum bq20z75_battery_mode mode)
|
||||
static enum sbs_battery_mode sbs_set_battery_mode(struct i2c_client *client,
|
||||
enum sbs_battery_mode mode)
|
||||
{
|
||||
int ret, original_val;
|
||||
|
||||
original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET);
|
||||
original_val = sbs_read_word_data(client, BATTERY_MODE_OFFSET);
|
||||
if (original_val < 0)
|
||||
return original_val;
|
||||
|
||||
@ -392,68 +381,67 @@ bq20z75_set_battery_mode(struct i2c_client *client,
|
||||
else
|
||||
ret = original_val | BATTERY_MODE_MASK;
|
||||
|
||||
ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret);
|
||||
ret = sbs_write_word_data(client, BATTERY_MODE_OFFSET, ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return original_val & BATTERY_MODE_MASK;
|
||||
}
|
||||
|
||||
static int bq20z75_get_battery_capacity(struct i2c_client *client,
|
||||
static int sbs_get_battery_capacity(struct i2c_client *client,
|
||||
int reg_offset, enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
s32 ret;
|
||||
enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS;
|
||||
enum sbs_battery_mode mode = BATTERY_MODE_WATTS;
|
||||
|
||||
if (power_supply_is_amp_property(psp))
|
||||
mode = BATTERY_MODE_AMPS;
|
||||
|
||||
mode = bq20z75_set_battery_mode(client, mode);
|
||||
mode = sbs_set_battery_mode(client, mode);
|
||||
if (mode < 0)
|
||||
return mode;
|
||||
|
||||
ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
|
||||
ret = sbs_read_word_data(client, sbs_data[reg_offset].addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (psp == POWER_SUPPLY_PROP_CAPACITY) {
|
||||
/* bq20z75 spec says that this can be >100 %
|
||||
/* sbs spec says that this can be >100 %
|
||||
* even if max value is 100 % */
|
||||
val->intval = min(ret, 100);
|
||||
} else
|
||||
val->intval = ret;
|
||||
|
||||
ret = bq20z75_set_battery_mode(client, mode);
|
||||
ret = sbs_set_battery_mode(client, mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char bq20z75_serial[5];
|
||||
static int bq20z75_get_battery_serial_number(struct i2c_client *client,
|
||||
static char sbs_serial[5];
|
||||
static int sbs_get_battery_serial_number(struct i2c_client *client,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bq20z75_read_word_data(client,
|
||||
bq20z75_data[REG_SERIAL_NUMBER].addr);
|
||||
ret = sbs_read_word_data(client, sbs_data[REG_SERIAL_NUMBER].addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sprintf(bq20z75_serial, "%04x", ret);
|
||||
val->strval = bq20z75_serial;
|
||||
ret = sprintf(sbs_serial, "%04x", ret);
|
||||
val->strval = sbs_serial;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq20z75_get_property_index(struct i2c_client *client,
|
||||
static int sbs_get_property_index(struct i2c_client *client,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
int count;
|
||||
for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++)
|
||||
if (psp == bq20z75_data[count].psp)
|
||||
for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
|
||||
if (psp == sbs_data[count].psp)
|
||||
return count;
|
||||
|
||||
dev_warn(&client->dev,
|
||||
@ -462,19 +450,19 @@ static int bq20z75_get_property_index(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bq20z75_get_property(struct power_supply *psy,
|
||||
static int sbs_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int ret = 0;
|
||||
struct bq20z75_info *bq20z75_device = container_of(psy,
|
||||
struct bq20z75_info, power_supply);
|
||||
struct i2c_client *client = bq20z75_device->client;
|
||||
struct sbs_info *chip = container_of(psy,
|
||||
struct sbs_info, power_supply);
|
||||
struct i2c_client *client = chip->client;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
ret = bq20z75_get_battery_presence_and_health(client, psp, val);
|
||||
ret = sbs_get_battery_presence_and_health(client, psp, val);
|
||||
if (psp == POWER_SUPPLY_PROP_PRESENT)
|
||||
return 0;
|
||||
break;
|
||||
@ -490,15 +478,15 @@ static int bq20z75_get_property(struct power_supply *psy,
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = bq20z75_get_property_index(client, psp);
|
||||
ret = sbs_get_property_index(client, psp);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
ret = bq20z75_get_battery_capacity(client, ret, psp, val);
|
||||
ret = sbs_get_battery_capacity(client, ret, psp, val);
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
|
||||
ret = bq20z75_get_battery_serial_number(client, val);
|
||||
ret = sbs_get_battery_serial_number(client, val);
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
@ -509,11 +497,11 @@ static int bq20z75_get_property(struct power_supply *psy,
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
|
||||
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
|
||||
ret = bq20z75_get_property_index(client, psp);
|
||||
ret = sbs_get_property_index(client, psp);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
ret = bq20z75_get_battery_property(client, ret, psp, val);
|
||||
ret = sbs_get_battery_property(client, ret, psp, val);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -522,25 +510,25 @@ static int bq20z75_get_property(struct power_supply *psy,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!bq20z75_device->enable_detection)
|
||||
if (!chip->enable_detection)
|
||||
goto done;
|
||||
|
||||
if (!bq20z75_device->gpio_detect &&
|
||||
bq20z75_device->is_present != (ret >= 0)) {
|
||||
bq20z75_device->is_present = (ret >= 0);
|
||||
power_supply_changed(&bq20z75_device->power_supply);
|
||||
if (!chip->gpio_detect &&
|
||||
chip->is_present != (ret >= 0)) {
|
||||
chip->is_present = (ret >= 0);
|
||||
power_supply_changed(&chip->power_supply);
|
||||
}
|
||||
|
||||
done:
|
||||
if (!ret) {
|
||||
/* Convert units to match requirements for power supply class */
|
||||
bq20z75_unit_adjustment(client, psp, val);
|
||||
sbs_unit_adjustment(client, psp, val);
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s: property = %d, value = %x\n", __func__, psp, val->intval);
|
||||
|
||||
if (ret && bq20z75_device->is_present)
|
||||
if (ret && chip->is_present)
|
||||
return ret;
|
||||
|
||||
/* battery not present, so return NODATA for properties */
|
||||
@ -550,7 +538,7 @@ done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t bq20z75_irq(int irq, void *devid)
|
||||
static irqreturn_t sbs_irq(int irq, void *devid)
|
||||
{
|
||||
struct power_supply *battery = devid;
|
||||
|
||||
@ -559,36 +547,35 @@ static irqreturn_t bq20z75_irq(int irq, void *devid)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void bq20z75_external_power_changed(struct power_supply *psy)
|
||||
static void sbs_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device;
|
||||
struct sbs_info *chip;
|
||||
|
||||
bq20z75_device = container_of(psy, struct bq20z75_info, power_supply);
|
||||
chip = container_of(psy, struct sbs_info, power_supply);
|
||||
|
||||
if (bq20z75_device->ignore_changes > 0) {
|
||||
bq20z75_device->ignore_changes--;
|
||||
if (chip->ignore_changes > 0) {
|
||||
chip->ignore_changes--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* cancel outstanding work */
|
||||
cancel_delayed_work_sync(&bq20z75_device->work);
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
|
||||
schedule_delayed_work(&bq20z75_device->work, HZ);
|
||||
bq20z75_device->poll_time = bq20z75_device->pdata->poll_retry_count;
|
||||
schedule_delayed_work(&chip->work, HZ);
|
||||
chip->poll_time = chip->pdata->poll_retry_count;
|
||||
}
|
||||
|
||||
static void bq20z75_delayed_work(struct work_struct *work)
|
||||
static void sbs_delayed_work(struct work_struct *work)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device;
|
||||
struct sbs_info *chip;
|
||||
s32 ret;
|
||||
|
||||
bq20z75_device = container_of(work, struct bq20z75_info, work.work);
|
||||
chip = container_of(work, struct sbs_info, work.work);
|
||||
|
||||
ret = bq20z75_read_word_data(bq20z75_device->client,
|
||||
bq20z75_data[REG_STATUS].addr);
|
||||
ret = sbs_read_word_data(chip->client, sbs_data[REG_STATUS].addr);
|
||||
/* if the read failed, give up on this work */
|
||||
if (ret < 0) {
|
||||
bq20z75_device->poll_time = 0;
|
||||
chip->poll_time = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -601,62 +588,145 @@ static void bq20z75_delayed_work(struct work_struct *work)
|
||||
else
|
||||
ret = POWER_SUPPLY_STATUS_CHARGING;
|
||||
|
||||
if (bq20z75_device->last_state != ret) {
|
||||
bq20z75_device->poll_time = 0;
|
||||
power_supply_changed(&bq20z75_device->power_supply);
|
||||
if (chip->last_state != ret) {
|
||||
chip->poll_time = 0;
|
||||
power_supply_changed(&chip->power_supply);
|
||||
return;
|
||||
}
|
||||
if (bq20z75_device->poll_time > 0) {
|
||||
schedule_delayed_work(&bq20z75_device->work, HZ);
|
||||
bq20z75_device->poll_time--;
|
||||
if (chip->poll_time > 0) {
|
||||
schedule_delayed_work(&chip->work, HZ);
|
||||
chip->poll_time--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit bq20z75_probe(struct i2c_client *client,
|
||||
#if defined(CONFIG_OF)
|
||||
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
static const struct of_device_id sbs_dt_ids[] = {
|
||||
{ .compatible = "sbs,sbs-battery" },
|
||||
{ .compatible = "ti,bq20z75" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sbs_dt_ids);
|
||||
|
||||
static struct sbs_platform_data *sbs_of_populate_pdata(
|
||||
struct i2c_client *client)
|
||||
{
|
||||
struct device_node *of_node = client->dev.of_node;
|
||||
struct sbs_platform_data *pdata = client->dev.platform_data;
|
||||
enum of_gpio_flags gpio_flags;
|
||||
int rc;
|
||||
u32 prop;
|
||||
|
||||
/* verify this driver matches this device */
|
||||
if (!of_node)
|
||||
return NULL;
|
||||
|
||||
/* if platform data is set, honor it */
|
||||
if (pdata)
|
||||
return pdata;
|
||||
|
||||
/* first make sure at least one property is set, otherwise
|
||||
* it won't change behavior from running without pdata.
|
||||
*/
|
||||
if (!of_get_property(of_node, "sbs,i2c-retry-count", NULL) &&
|
||||
!of_get_property(of_node, "sbs,poll-retry-count", NULL) &&
|
||||
!of_get_property(of_node, "sbs,battery-detect-gpios", NULL))
|
||||
goto of_out;
|
||||
|
||||
pdata = devm_kzalloc(&client->dev, sizeof(struct sbs_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
goto of_out;
|
||||
|
||||
rc = of_property_read_u32(of_node, "sbs,i2c-retry-count", &prop);
|
||||
if (!rc)
|
||||
pdata->i2c_retry_count = prop;
|
||||
|
||||
rc = of_property_read_u32(of_node, "sbs,poll-retry-count", &prop);
|
||||
if (!rc)
|
||||
pdata->poll_retry_count = prop;
|
||||
|
||||
if (!of_get_property(of_node, "sbs,battery-detect-gpios", NULL)) {
|
||||
pdata->battery_detect = -1;
|
||||
goto of_out;
|
||||
}
|
||||
|
||||
pdata->battery_detect = of_get_named_gpio_flags(of_node,
|
||||
"sbs,battery-detect-gpios", 0, &gpio_flags);
|
||||
|
||||
if (gpio_flags & OF_GPIO_ACTIVE_LOW)
|
||||
pdata->battery_detect_present = 0;
|
||||
else
|
||||
pdata->battery_detect_present = 1;
|
||||
|
||||
of_out:
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
#define sbs_dt_ids NULL
|
||||
static struct sbs_platform_data *sbs_of_populate_pdata(
|
||||
struct i2c_client *client)
|
||||
{
|
||||
return client->dev.platform_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __devinit sbs_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device;
|
||||
struct bq20z75_platform_data *pdata = client->dev.platform_data;
|
||||
struct sbs_info *chip;
|
||||
struct sbs_platform_data *pdata = client->dev.platform_data;
|
||||
int rc;
|
||||
int irq;
|
||||
char *name;
|
||||
|
||||
bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
|
||||
if (!bq20z75_device)
|
||||
name = kasprintf(GFP_KERNEL, "sbs-%s", dev_name(&client->dev));
|
||||
if (!name) {
|
||||
dev_err(&client->dev, "Failed to allocate device name\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bq20z75_device->client = client;
|
||||
bq20z75_device->enable_detection = false;
|
||||
bq20z75_device->gpio_detect = false;
|
||||
bq20z75_device->power_supply.name = "battery";
|
||||
bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
bq20z75_device->power_supply.properties = bq20z75_properties;
|
||||
bq20z75_device->power_supply.num_properties =
|
||||
ARRAY_SIZE(bq20z75_properties);
|
||||
bq20z75_device->power_supply.get_property = bq20z75_get_property;
|
||||
chip = kzalloc(sizeof(struct sbs_info), GFP_KERNEL);
|
||||
if (!chip) {
|
||||
rc = -ENOMEM;
|
||||
goto exit_free_name;
|
||||
}
|
||||
|
||||
chip->client = client;
|
||||
chip->enable_detection = false;
|
||||
chip->gpio_detect = false;
|
||||
chip->power_supply.name = name;
|
||||
chip->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
chip->power_supply.properties = sbs_properties;
|
||||
chip->power_supply.num_properties = ARRAY_SIZE(sbs_properties);
|
||||
chip->power_supply.get_property = sbs_get_property;
|
||||
/* ignore first notification of external change, it is generated
|
||||
* from the power_supply_register call back
|
||||
*/
|
||||
bq20z75_device->ignore_changes = 1;
|
||||
bq20z75_device->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
bq20z75_device->power_supply.external_power_changed =
|
||||
bq20z75_external_power_changed;
|
||||
chip->ignore_changes = 1;
|
||||
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
chip->power_supply.external_power_changed = sbs_external_power_changed;
|
||||
|
||||
pdata = sbs_of_populate_pdata(client);
|
||||
|
||||
if (pdata) {
|
||||
bq20z75_device->gpio_detect =
|
||||
gpio_is_valid(pdata->battery_detect);
|
||||
bq20z75_device->pdata = pdata;
|
||||
chip->gpio_detect = gpio_is_valid(pdata->battery_detect);
|
||||
chip->pdata = pdata;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, bq20z75_device);
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
||||
if (!bq20z75_device->gpio_detect)
|
||||
if (!chip->gpio_detect)
|
||||
goto skip_gpio;
|
||||
|
||||
rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
|
||||
if (rc) {
|
||||
dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
|
||||
bq20z75_device->gpio_detect = false;
|
||||
chip->gpio_detect = false;
|
||||
goto skip_gpio;
|
||||
}
|
||||
|
||||
@ -664,7 +734,7 @@ static int __devinit bq20z75_probe(struct i2c_client *client,
|
||||
if (rc) {
|
||||
dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
|
||||
gpio_free(pdata->battery_detect);
|
||||
bq20z75_device->gpio_detect = false;
|
||||
chip->gpio_detect = false;
|
||||
goto skip_gpio;
|
||||
}
|
||||
|
||||
@ -672,25 +742,25 @@ static int __devinit bq20z75_probe(struct i2c_client *client,
|
||||
if (irq <= 0) {
|
||||
dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
|
||||
gpio_free(pdata->battery_detect);
|
||||
bq20z75_device->gpio_detect = false;
|
||||
chip->gpio_detect = false;
|
||||
goto skip_gpio;
|
||||
}
|
||||
|
||||
rc = request_irq(irq, bq20z75_irq,
|
||||
rc = request_irq(irq, sbs_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
dev_name(&client->dev), &bq20z75_device->power_supply);
|
||||
dev_name(&client->dev), &chip->power_supply);
|
||||
if (rc) {
|
||||
dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
|
||||
gpio_free(pdata->battery_detect);
|
||||
bq20z75_device->gpio_detect = false;
|
||||
chip->gpio_detect = false;
|
||||
goto skip_gpio;
|
||||
}
|
||||
|
||||
bq20z75_device->irq = irq;
|
||||
chip->irq = irq;
|
||||
|
||||
skip_gpio:
|
||||
|
||||
rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
|
||||
rc = power_supply_register(&client->dev, &chip->power_supply);
|
||||
if (rc) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to register power supply\n", __func__);
|
||||
@ -700,95 +770,100 @@ skip_gpio:
|
||||
dev_info(&client->dev,
|
||||
"%s: battery gas gauge device registered\n", client->name);
|
||||
|
||||
INIT_DELAYED_WORK(&bq20z75_device->work, bq20z75_delayed_work);
|
||||
INIT_DELAYED_WORK(&chip->work, sbs_delayed_work);
|
||||
|
||||
bq20z75_device->enable_detection = true;
|
||||
chip->enable_detection = true;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_psupply:
|
||||
if (bq20z75_device->irq)
|
||||
free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
|
||||
if (bq20z75_device->gpio_detect)
|
||||
if (chip->irq)
|
||||
free_irq(chip->irq, &chip->power_supply);
|
||||
if (chip->gpio_detect)
|
||||
gpio_free(pdata->battery_detect);
|
||||
|
||||
kfree(bq20z75_device);
|
||||
kfree(chip);
|
||||
|
||||
exit_free_name:
|
||||
kfree(name);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit bq20z75_remove(struct i2c_client *client)
|
||||
static int __devexit sbs_remove(struct i2c_client *client)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
|
||||
struct sbs_info *chip = i2c_get_clientdata(client);
|
||||
|
||||
if (bq20z75_device->irq)
|
||||
free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
|
||||
if (bq20z75_device->gpio_detect)
|
||||
gpio_free(bq20z75_device->pdata->battery_detect);
|
||||
if (chip->irq)
|
||||
free_irq(chip->irq, &chip->power_supply);
|
||||
if (chip->gpio_detect)
|
||||
gpio_free(chip->pdata->battery_detect);
|
||||
|
||||
power_supply_unregister(&bq20z75_device->power_supply);
|
||||
power_supply_unregister(&chip->power_supply);
|
||||
|
||||
cancel_delayed_work_sync(&bq20z75_device->work);
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
|
||||
kfree(bq20z75_device);
|
||||
bq20z75_device = NULL;
|
||||
kfree(chip->power_supply.name);
|
||||
kfree(chip);
|
||||
chip = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined CONFIG_PM
|
||||
static int bq20z75_suspend(struct i2c_client *client,
|
||||
static int sbs_suspend(struct i2c_client *client,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
|
||||
struct sbs_info *chip = i2c_get_clientdata(client);
|
||||
s32 ret;
|
||||
|
||||
if (bq20z75_device->poll_time > 0)
|
||||
cancel_delayed_work_sync(&bq20z75_device->work);
|
||||
if (chip->poll_time > 0)
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
|
||||
/* write to manufacturer access with sleep command */
|
||||
ret = bq20z75_write_word_data(client,
|
||||
bq20z75_data[REG_MANUFACTURER_DATA].addr,
|
||||
ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
|
||||
MANUFACTURER_ACCESS_SLEEP);
|
||||
if (bq20z75_device->is_present && ret < 0)
|
||||
if (chip->is_present && ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define bq20z75_suspend NULL
|
||||
#define sbs_suspend NULL
|
||||
#endif
|
||||
/* any smbus transaction will wake up bq20z75 */
|
||||
#define bq20z75_resume NULL
|
||||
/* any smbus transaction will wake up sbs */
|
||||
#define sbs_resume NULL
|
||||
|
||||
static const struct i2c_device_id bq20z75_id[] = {
|
||||
static const struct i2c_device_id sbs_id[] = {
|
||||
{ "bq20z75", 0 },
|
||||
{ "sbs-battery", 1 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bq20z75_id);
|
||||
MODULE_DEVICE_TABLE(i2c, sbs_id);
|
||||
|
||||
static struct i2c_driver bq20z75_battery_driver = {
|
||||
.probe = bq20z75_probe,
|
||||
.remove = __devexit_p(bq20z75_remove),
|
||||
.suspend = bq20z75_suspend,
|
||||
.resume = bq20z75_resume,
|
||||
.id_table = bq20z75_id,
|
||||
static struct i2c_driver sbs_battery_driver = {
|
||||
.probe = sbs_probe,
|
||||
.remove = __devexit_p(sbs_remove),
|
||||
.suspend = sbs_suspend,
|
||||
.resume = sbs_resume,
|
||||
.id_table = sbs_id,
|
||||
.driver = {
|
||||
.name = "bq20z75-battery",
|
||||
.name = "sbs-battery",
|
||||
.of_match_table = sbs_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init bq20z75_battery_init(void)
|
||||
static int __init sbs_battery_init(void)
|
||||
{
|
||||
return i2c_add_driver(&bq20z75_battery_driver);
|
||||
return i2c_add_driver(&sbs_battery_driver);
|
||||
}
|
||||
module_init(bq20z75_battery_init);
|
||||
module_init(sbs_battery_init);
|
||||
|
||||
static void __exit bq20z75_battery_exit(void)
|
||||
static void __exit sbs_battery_exit(void)
|
||||
{
|
||||
i2c_del_driver(&bq20z75_battery_driver);
|
||||
i2c_del_driver(&sbs_battery_driver);
|
||||
}
|
||||
module_exit(bq20z75_battery_exit);
|
||||
module_exit(sbs_battery_exit);
|
||||
|
||||
MODULE_DESCRIPTION("BQ20z75 battery monitor driver");
|
||||
MODULE_DESCRIPTION("SBS battery monitor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -307,25 +307,20 @@ static struct tosa_bat tosa_bat_bu = {
|
||||
.adc_temp_divider = -1,
|
||||
};
|
||||
|
||||
static struct {
|
||||
int gpio;
|
||||
char *name;
|
||||
bool output;
|
||||
int value;
|
||||
} gpios[] = {
|
||||
{ TOSA_GPIO_CHARGE_OFF, "main charge off", 1, 1 },
|
||||
{ TOSA_GPIO_CHARGE_OFF_JC, "jacket charge off", 1, 1 },
|
||||
{ TOSA_GPIO_BAT_SW_ON, "battery switch", 1, 0 },
|
||||
{ TOSA_GPIO_BAT0_V_ON, "main battery", 1, 0 },
|
||||
{ TOSA_GPIO_BAT1_V_ON, "jacket battery", 1, 0 },
|
||||
{ TOSA_GPIO_BAT1_TH_ON, "main battery temp", 1, 0 },
|
||||
{ TOSA_GPIO_BAT0_TH_ON, "jacket battery temp", 1, 0 },
|
||||
{ TOSA_GPIO_BU_CHRG_ON, "backup battery", 1, 0 },
|
||||
{ TOSA_GPIO_BAT0_CRG, "main battery full", 0, 0 },
|
||||
{ TOSA_GPIO_BAT1_CRG, "jacket battery full", 0, 0 },
|
||||
{ TOSA_GPIO_BAT0_LOW, "main battery low", 0, 0 },
|
||||
{ TOSA_GPIO_BAT1_LOW, "jacket battery low", 0, 0 },
|
||||
{ TOSA_GPIO_JACKET_DETECT, "jacket detect", 0, 0 },
|
||||
static struct gpio tosa_bat_gpios[] = {
|
||||
{ TOSA_GPIO_CHARGE_OFF, GPIOF_OUT_INIT_HIGH, "main charge off" },
|
||||
{ TOSA_GPIO_CHARGE_OFF_JC, GPIOF_OUT_INIT_HIGH, "jacket charge off" },
|
||||
{ TOSA_GPIO_BAT_SW_ON, GPIOF_OUT_INIT_LOW, "battery switch" },
|
||||
{ TOSA_GPIO_BAT0_V_ON, GPIOF_OUT_INIT_LOW, "main battery" },
|
||||
{ TOSA_GPIO_BAT1_V_ON, GPIOF_OUT_INIT_LOW, "jacket battery" },
|
||||
{ TOSA_GPIO_BAT1_TH_ON, GPIOF_OUT_INIT_LOW, "main battery temp" },
|
||||
{ TOSA_GPIO_BAT0_TH_ON, GPIOF_OUT_INIT_LOW, "jacket battery temp" },
|
||||
{ TOSA_GPIO_BU_CHRG_ON, GPIOF_OUT_INIT_LOW, "backup battery" },
|
||||
{ TOSA_GPIO_BAT0_CRG, GPIOF_IN, "main battery full" },
|
||||
{ TOSA_GPIO_BAT1_CRG, GPIOF_IN, "jacket battery full" },
|
||||
{ TOSA_GPIO_BAT0_LOW, GPIOF_IN, "main battery low" },
|
||||
{ TOSA_GPIO_BAT1_LOW, GPIOF_IN, "jacket battery low" },
|
||||
{ TOSA_GPIO_JACKET_DETECT, GPIOF_IN, "jacket detect" },
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -350,27 +345,13 @@ static int tosa_bat_resume(struct platform_device *dev)
|
||||
static int __devinit tosa_bat_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!machine_is_tosa())
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gpios); i++) {
|
||||
ret = gpio_request(gpios[i].gpio, gpios[i].name);
|
||||
if (ret) {
|
||||
i--;
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (gpios[i].output)
|
||||
ret = gpio_direction_output(gpios[i].gpio,
|
||||
gpios[i].value);
|
||||
else
|
||||
ret = gpio_direction_input(gpios[i].gpio);
|
||||
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
}
|
||||
ret = gpio_request_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&tosa_bat_main.work_lock);
|
||||
mutex_init(&tosa_bat_jacket.work_lock);
|
||||
@ -424,18 +405,12 @@ err_psy_reg_main:
|
||||
/* see comment in tosa_bat_remove */
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
i--;
|
||||
err_gpio:
|
||||
for (; i >= 0; i--)
|
||||
gpio_free(gpios[i].gpio);
|
||||
|
||||
gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tosa_bat_remove(struct platform_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket);
|
||||
free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket);
|
||||
free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
|
||||
@ -450,10 +425,7 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
|
||||
* unregistered now.
|
||||
*/
|
||||
cancel_work_sync(&bat_work);
|
||||
|
||||
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
|
||||
gpio_free(gpios[i].gpio);
|
||||
|
||||
gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -466,18 +438,7 @@ static struct platform_driver tosa_bat_driver = {
|
||||
.resume = tosa_bat_resume,
|
||||
};
|
||||
|
||||
static int __init tosa_bat_init(void)
|
||||
{
|
||||
return platform_driver_register(&tosa_bat_driver);
|
||||
}
|
||||
|
||||
static void __exit tosa_bat_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tosa_bat_driver);
|
||||
}
|
||||
|
||||
module_init(tosa_bat_init);
|
||||
module_exit(tosa_bat_exit);
|
||||
module_platform_driver(tosa_bat_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Dmitry Baryshkov");
|
||||
|
@ -226,17 +226,7 @@ static struct platform_driver wm831x_backup_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init wm831x_backup_init(void)
|
||||
{
|
||||
return platform_driver_register(&wm831x_backup_driver);
|
||||
}
|
||||
module_init(wm831x_backup_init);
|
||||
|
||||
static void __exit wm831x_backup_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wm831x_backup_driver);
|
||||
}
|
||||
module_exit(wm831x_backup_exit);
|
||||
module_platform_driver(wm831x_backup_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Backup battery charger driver for WM831x PMICs");
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
|
@ -27,6 +27,7 @@ struct wm831x_power {
|
||||
char wall_name[20];
|
||||
char usb_name[20];
|
||||
char battery_name[20];
|
||||
bool have_battery;
|
||||
};
|
||||
|
||||
static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
|
||||
@ -449,7 +450,8 @@ static irqreturn_t wm831x_bat_irq(int irq, void *data)
|
||||
|
||||
/* The battery charger is autonomous so we don't need to do
|
||||
* anything except kick user space */
|
||||
power_supply_changed(&wm831x_power->battery);
|
||||
if (wm831x_power->have_battery)
|
||||
power_supply_changed(&wm831x_power->battery);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -479,7 +481,8 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
|
||||
dev_dbg(wm831x->dev, "Power source changed\n");
|
||||
|
||||
/* Just notify for everything - little harm in overnotifying. */
|
||||
power_supply_changed(&wm831x_power->battery);
|
||||
if (wm831x_power->have_battery)
|
||||
power_supply_changed(&wm831x_power->battery);
|
||||
power_supply_changed(&wm831x_power->usb);
|
||||
power_supply_changed(&wm831x_power->wall);
|
||||
|
||||
@ -537,15 +540,6 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_kmalloc;
|
||||
|
||||
battery->name = power->battery_name;
|
||||
battery->properties = wm831x_bat_props;
|
||||
battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
|
||||
battery->get_property = wm831x_bat_get_prop;
|
||||
battery->use_for_apm = 1;
|
||||
ret = power_supply_register(&pdev->dev, battery);
|
||||
if (ret)
|
||||
goto err_wall;
|
||||
|
||||
usb->name = power->usb_name,
|
||||
usb->type = POWER_SUPPLY_TYPE_USB;
|
||||
usb->properties = wm831x_usb_props;
|
||||
@ -553,7 +547,23 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
|
||||
usb->get_property = wm831x_usb_get_prop;
|
||||
ret = power_supply_register(&pdev->dev, usb);
|
||||
if (ret)
|
||||
goto err_battery;
|
||||
goto err_wall;
|
||||
|
||||
ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_1);
|
||||
if (ret < 0)
|
||||
goto err_wall;
|
||||
power->have_battery = ret & WM831X_CHG_ENA;
|
||||
|
||||
if (power->have_battery) {
|
||||
battery->name = power->battery_name;
|
||||
battery->properties = wm831x_bat_props;
|
||||
battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
|
||||
battery->get_property = wm831x_bat_get_prop;
|
||||
battery->use_for_apm = 1;
|
||||
ret = power_supply_register(&pdev->dev, battery);
|
||||
if (ret)
|
||||
goto err_usb;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "SYSLO");
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
|
||||
@ -562,7 +572,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
goto err_usb;
|
||||
goto err_battery;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "PWR SRC");
|
||||
@ -601,10 +611,11 @@ err_bat_irq:
|
||||
err_syslo:
|
||||
irq = platform_get_irq_byname(pdev, "SYSLO");
|
||||
free_irq(irq, power);
|
||||
err_battery:
|
||||
if (power->have_battery)
|
||||
power_supply_unregister(battery);
|
||||
err_usb:
|
||||
power_supply_unregister(usb);
|
||||
err_battery:
|
||||
power_supply_unregister(battery);
|
||||
err_wall:
|
||||
power_supply_unregister(wall);
|
||||
err_kmalloc:
|
||||
@ -628,7 +639,8 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev)
|
||||
irq = platform_get_irq_byname(pdev, "SYSLO");
|
||||
free_irq(irq, wm831x_power);
|
||||
|
||||
power_supply_unregister(&wm831x_power->battery);
|
||||
if (wm831x_power->have_battery)
|
||||
power_supply_unregister(&wm831x_power->battery);
|
||||
power_supply_unregister(&wm831x_power->wall);
|
||||
power_supply_unregister(&wm831x_power->usb);
|
||||
kfree(wm831x_power);
|
||||
@ -643,17 +655,7 @@ static struct platform_driver wm831x_power_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init wm831x_power_init(void)
|
||||
{
|
||||
return platform_driver_register(&wm831x_power_driver);
|
||||
}
|
||||
module_init(wm831x_power_init);
|
||||
|
||||
static void __exit wm831x_power_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wm831x_power_driver);
|
||||
}
|
||||
module_exit(wm831x_power_exit);
|
||||
module_platform_driver(wm831x_power_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Power supply driver for WM831x PMICs");
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
|
@ -522,17 +522,7 @@ static struct platform_driver wm8350_power_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init wm8350_power_init(void)
|
||||
{
|
||||
return platform_driver_register(&wm8350_power_driver);
|
||||
}
|
||||
module_init(wm8350_power_init);
|
||||
|
||||
static void __exit wm8350_power_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wm8350_power_driver);
|
||||
}
|
||||
module_exit(wm8350_power_exit);
|
||||
module_platform_driver(wm8350_power_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Power supply driver for WM8350");
|
||||
|
@ -25,9 +25,8 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static DEFINE_MUTEX(bat_lock);
|
||||
static struct work_struct bat_work;
|
||||
static struct mutex work_lock;
|
||||
static DEFINE_MUTEX(work_lock);
|
||||
static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
static enum power_supply_property *prop;
|
||||
|
||||
@ -181,8 +180,6 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev)
|
||||
if (dev->id != -1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_init(&work_lock);
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&dev->dev, "No platform_data supplied\n");
|
||||
return -EINVAL;
|
||||
@ -196,7 +193,7 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev)
|
||||
if (ret)
|
||||
goto err2;
|
||||
ret = request_irq(gpio_to_irq(pdata->charge_gpio),
|
||||
wm97xx_chrg_irq, IRQF_DISABLED,
|
||||
wm97xx_chrg_irq, 0,
|
||||
"AC Detect", dev);
|
||||
if (ret)
|
||||
goto err2;
|
||||
@ -291,18 +288,7 @@ static struct platform_driver wm97xx_bat_driver = {
|
||||
.remove = __devexit_p(wm97xx_bat_remove),
|
||||
};
|
||||
|
||||
static int __init wm97xx_bat_init(void)
|
||||
{
|
||||
return platform_driver_register(&wm97xx_bat_driver);
|
||||
}
|
||||
|
||||
static void __exit wm97xx_bat_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wm97xx_bat_driver);
|
||||
}
|
||||
|
||||
module_init(wm97xx_bat_init);
|
||||
module_exit(wm97xx_bat_exit);
|
||||
module_platform_driver(wm97xx_bat_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
|
||||
|
@ -218,7 +218,7 @@ static int __devinit z2_batt_probe(struct i2c_client *client,
|
||||
irq_set_irq_type(gpio_to_irq(info->charge_gpio),
|
||||
IRQ_TYPE_EDGE_BOTH);
|
||||
ret = request_irq(gpio_to_irq(info->charge_gpio),
|
||||
z2_charge_switch_irq, IRQF_DISABLED,
|
||||
z2_charge_switch_irq, 0,
|
||||
"AC Detect", charger);
|
||||
if (ret)
|
||||
goto err3;
|
||||
@ -313,7 +313,7 @@ static struct i2c_driver z2_batt_driver = {
|
||||
.pm = Z2_BATTERY_PM_OPS
|
||||
},
|
||||
.probe = z2_batt_probe,
|
||||
.remove = z2_batt_remove,
|
||||
.remove = __devexit_p(z2_batt_remove),
|
||||
.id_table = z2_batt_id,
|
||||
};
|
||||
|
||||
|
51
include/linux/lp8727.h
Executable file
51
include/linux/lp8727.h
Executable file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2011 National Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _LP8727_H
|
||||
#define _LP8727_H
|
||||
|
||||
enum lp8727_eoc_level {
|
||||
EOC_5P,
|
||||
EOC_10P,
|
||||
EOC_16P,
|
||||
EOC_20P,
|
||||
EOC_25P,
|
||||
EOC_33P,
|
||||
EOC_50P,
|
||||
};
|
||||
|
||||
enum lp8727_ichg {
|
||||
ICHG_90mA,
|
||||
ICHG_100mA,
|
||||
ICHG_400mA,
|
||||
ICHG_450mA,
|
||||
ICHG_500mA,
|
||||
ICHG_600mA,
|
||||
ICHG_700mA,
|
||||
ICHG_800mA,
|
||||
ICHG_900mA,
|
||||
ICHG_1000mA,
|
||||
};
|
||||
|
||||
struct lp8727_chg_param {
|
||||
/* end of charge level setting */
|
||||
enum lp8727_eoc_level eoc_level;
|
||||
/* charging current */
|
||||
enum lp8727_ichg ichg;
|
||||
};
|
||||
|
||||
struct lp8727_platform_data {
|
||||
u8 (*get_batt_present)(void);
|
||||
u16 (*get_batt_level)(void);
|
||||
u8 (*get_batt_capacity)(void);
|
||||
u8 (*get_batt_temp)(void);
|
||||
struct lp8727_chg_param ac;
|
||||
struct lp8727_chg_param usb;
|
||||
};
|
||||
|
||||
#endif
|
@ -167,9 +167,6 @@ enum {
|
||||
MAX8925_IRQ_VCHG_DC_OVP,
|
||||
MAX8925_IRQ_VCHG_DC_F,
|
||||
MAX8925_IRQ_VCHG_DC_R,
|
||||
MAX8925_IRQ_VCHG_USB_OVP,
|
||||
MAX8925_IRQ_VCHG_USB_F,
|
||||
MAX8925_IRQ_VCHG_USB_R,
|
||||
MAX8925_IRQ_VCHG_THM_OK_R,
|
||||
MAX8925_IRQ_VCHG_THM_OK_F,
|
||||
MAX8925_IRQ_VCHG_SYSLOW_F,
|
||||
@ -223,6 +220,10 @@ struct max8925_power_pdata {
|
||||
unsigned batt_detect:1;
|
||||
unsigned topoff_threshold:2;
|
||||
unsigned fast_charge:3; /* charge current */
|
||||
unsigned no_temp_support:1; /* set if no temperature detect */
|
||||
unsigned no_insert_detect:1; /* set if no ac insert detect */
|
||||
char **supplied_to;
|
||||
int num_supplicants;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -35,6 +35,8 @@ struct pda_power_pdata {
|
||||
unsigned int polling_interval; /* msecs, default is 2000 */
|
||||
|
||||
unsigned long ac_max_uA; /* current to draw when on AC */
|
||||
|
||||
bool use_otg_notifier;
|
||||
};
|
||||
|
||||
#endif /* __PDA_POWER_H__ */
|
||||
|
147
include/linux/power/charger-manager.h
Normal file
147
include/linux/power/charger-manager.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
|
||||
* MyungJoo.Ham <myungjoo.ham@samsung.com>
|
||||
*
|
||||
* Charger Manager.
|
||||
* This framework enables to control and multiple chargers and to
|
||||
* monitor charging even in the context of suspend-to-RAM with
|
||||
* an interface combining the chargers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
**/
|
||||
|
||||
#ifndef _CHARGER_MANAGER_H
|
||||
#define _CHARGER_MANAGER_H
|
||||
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
enum data_source {
|
||||
CM_FUEL_GAUGE,
|
||||
CM_CHARGER_STAT,
|
||||
};
|
||||
|
||||
enum polling_modes {
|
||||
CM_POLL_DISABLE = 0,
|
||||
CM_POLL_ALWAYS,
|
||||
CM_POLL_EXTERNAL_POWER_ONLY,
|
||||
CM_POLL_CHARGING_ONLY,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct charger_global_desc
|
||||
* @rtc_name: the name of RTC used to wake up the system from suspend.
|
||||
* @rtc_only_wakeup:
|
||||
* If the system is woken up by waekup-sources other than the RTC or
|
||||
* callbacks, Charger Manager should recognize with
|
||||
* rtc_only_wakeup() returning false.
|
||||
* If the RTC given to CM is the only wakeup reason,
|
||||
* rtc_only_wakeup should return true.
|
||||
*/
|
||||
struct charger_global_desc {
|
||||
char *rtc_name;
|
||||
|
||||
bool (*rtc_only_wakeup)(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct charger_desc
|
||||
* @psy_name: the name of power-supply-class for charger manager
|
||||
* @polling_mode:
|
||||
* Determine which polling mode will be used
|
||||
* @fullbatt_uV: voltage in microvolt
|
||||
* If it is not being charged and VBATT >= fullbatt_uV,
|
||||
* it is assumed to be full.
|
||||
* @polling_interval_ms: interval in millisecond at which
|
||||
* charger manager will monitor battery health
|
||||
* @battery_present:
|
||||
* Specify where information for existance of battery can be obtained
|
||||
* @psy_charger_stat: the names of power-supply for chargers
|
||||
* @num_charger_regulator: the number of entries in charger_regulators
|
||||
* @charger_regulators: array of regulator_bulk_data for chargers
|
||||
* @psy_fuel_gauge: the name of power-supply for fuel gauge
|
||||
* @temperature_out_of_range:
|
||||
* Determine whether the status is overheat or cold or normal.
|
||||
* return_value > 0: overheat
|
||||
* return_value == 0: normal
|
||||
* return_value < 0: cold
|
||||
* @measure_battery_temp:
|
||||
* true: measure battery temperature
|
||||
* false: measure ambient temperature
|
||||
*/
|
||||
struct charger_desc {
|
||||
char *psy_name;
|
||||
|
||||
enum polling_modes polling_mode;
|
||||
unsigned int polling_interval_ms;
|
||||
|
||||
unsigned int fullbatt_uV;
|
||||
|
||||
enum data_source battery_present;
|
||||
|
||||
char **psy_charger_stat;
|
||||
|
||||
int num_charger_regulators;
|
||||
struct regulator_bulk_data *charger_regulators;
|
||||
|
||||
char *psy_fuel_gauge;
|
||||
|
||||
int (*temperature_out_of_range)(int *mC);
|
||||
bool measure_battery_temp;
|
||||
};
|
||||
|
||||
#define PSY_NAME_MAX 30
|
||||
|
||||
/**
|
||||
* struct charger_manager
|
||||
* @entry: entry for list
|
||||
* @dev: device pointer
|
||||
* @desc: instance of charger_desc
|
||||
* @fuel_gauge: power_supply for fuel gauge
|
||||
* @charger_stat: array of power_supply for chargers
|
||||
* @charger_enabled: the state of charger
|
||||
* @emergency_stop:
|
||||
* When setting true, stop charging
|
||||
* @last_temp_mC: the measured temperature in milli-Celsius
|
||||
* @psy_name_buf: the name of power-supply-class for charger manager
|
||||
* @charger_psy: power_supply for charger manager
|
||||
* @status_save_ext_pwr_inserted:
|
||||
* saved status of external power before entering suspend-to-RAM
|
||||
* @status_save_batt:
|
||||
* saved status of battery before entering suspend-to-RAM
|
||||
*/
|
||||
struct charger_manager {
|
||||
struct list_head entry;
|
||||
struct device *dev;
|
||||
struct charger_desc *desc;
|
||||
|
||||
struct power_supply *fuel_gauge;
|
||||
struct power_supply **charger_stat;
|
||||
|
||||
bool charger_enabled;
|
||||
|
||||
int emergency_stop;
|
||||
int last_temp_mC;
|
||||
|
||||
char psy_name_buf[PSY_NAME_MAX + 1];
|
||||
struct power_supply charger_psy;
|
||||
|
||||
bool status_save_ext_pwr_inserted;
|
||||
bool status_save_batt;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CHARGER_MANAGER
|
||||
extern int setup_charger_manager(struct charger_global_desc *gd);
|
||||
extern bool cm_suspend_again(void);
|
||||
#else
|
||||
static void __maybe_unused setup_charger_manager(struct charger_global_desc *gd)
|
||||
{ }
|
||||
|
||||
static bool __maybe_unused cm_suspend_again(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _CHARGER_MANAGER_H */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Gas Gauge driver for TI's BQ20Z75
|
||||
* Gas Gauge driver for SBS Compliant Gas Gauges
|
||||
*
|
||||
* Copyright (c) 2010, NVIDIA Corporation.
|
||||
*
|
||||
@ -18,21 +18,21 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_POWER_BQ20Z75_H_
|
||||
#define __LINUX_POWER_BQ20Z75_H_
|
||||
#ifndef __LINUX_POWER_SBS_BATTERY_H_
|
||||
#define __LINUX_POWER_SBS_BATTERY_H_
|
||||
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* struct bq20z75_platform_data - platform data for bq20z75 devices
|
||||
* struct sbs_platform_data - platform data for sbs devices
|
||||
* @battery_detect: GPIO which is used to detect battery presence
|
||||
* @battery_detect_present: gpio state when battery is present (0 / 1)
|
||||
* @i2c_retry_count: # of times to retry on i2c IO failure
|
||||
* @poll_retry_count: # of times to retry looking for new status after
|
||||
* external change notification
|
||||
*/
|
||||
struct bq20z75_platform_data {
|
||||
struct sbs_platform_data {
|
||||
int battery_detect;
|
||||
int battery_detect_present;
|
||||
int i2c_retry_count;
|
@ -74,6 +74,12 @@ enum {
|
||||
POWER_SUPPLY_CAPACITY_LEVEL_FULL,
|
||||
};
|
||||
|
||||
enum {
|
||||
POWER_SUPPLY_SCOPE_UNKNOWN = 0,
|
||||
POWER_SUPPLY_SCOPE_SYSTEM,
|
||||
POWER_SUPPLY_SCOPE_DEVICE,
|
||||
};
|
||||
|
||||
enum power_supply_property {
|
||||
/* Properties of type `int' */
|
||||
POWER_SUPPLY_PROP_STATUS = 0,
|
||||
@ -116,6 +122,7 @@ enum power_supply_property {
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
|
||||
POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
/* Properties of type `const char *' */
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
@ -123,7 +130,8 @@ enum power_supply_property {
|
||||
};
|
||||
|
||||
enum power_supply_type {
|
||||
POWER_SUPPLY_TYPE_BATTERY = 0,
|
||||
POWER_SUPPLY_TYPE_UNKNOWN = 0,
|
||||
POWER_SUPPLY_TYPE_BATTERY,
|
||||
POWER_SUPPLY_TYPE_UPS,
|
||||
POWER_SUPPLY_TYPE_MAINS,
|
||||
POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */
|
||||
@ -211,6 +219,7 @@ static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
|
||||
extern int power_supply_register(struct device *parent,
|
||||
struct power_supply *psy);
|
||||
extern void power_supply_unregister(struct power_supply *psy);
|
||||
extern int power_supply_powers(struct power_supply *psy, struct device *dev);
|
||||
|
||||
/* For APM emulation, think legacy userspace. */
|
||||
extern struct class *power_supply_class;
|
||||
|
@ -25,6 +25,10 @@ struct s3c_adc_bat_pdata {
|
||||
const unsigned int current_channel;
|
||||
const unsigned int backup_volt_channel;
|
||||
|
||||
const unsigned int volt_samples;
|
||||
const unsigned int current_samples;
|
||||
const unsigned int backup_volt_samples;
|
||||
|
||||
const unsigned int volt_mult;
|
||||
const unsigned int current_mult;
|
||||
const unsigned int backup_volt_mult;
|
||||
|
Loading…
Reference in New Issue
Block a user