aboutsummaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/Kconfig1
-rw-r--r--drivers/power/bq27000_battery.c3
-rw-r--r--drivers/power/gta01_battery.c71
-rw-r--r--drivers/power/pcf50633-charger.c101
4 files changed, 102 insertions, 74 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index b5332f714cd..f88c5aab640 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -90,6 +90,7 @@ config CHARGER_PCF50633
config BATTERY_BQ27000_HDQ
tristate "BQ27000 HDQ battery monitor driver"
+ select HDQ_GPIO_BITBANG
help
Say Y to enable support for the battery on the Neo Freerunner
diff --git a/drivers/power/bq27000_battery.c b/drivers/power/bq27000_battery.c
index 593cbe6f752..f1dcda3297d 100644
--- a/drivers/power/bq27000_battery.c
+++ b/drivers/power/bq27000_battery.c
@@ -186,6 +186,9 @@ static int bq27000_battery_get_property(struct power_supply *psy,
int n;
struct bq27000_device_info *di = container_of(psy, struct bq27000_device_info, bat);
+ if (di->regs.rsoc < 0 && psp != POWER_SUPPLY_PROP_PRESENT)
+ return -ENODEV;
+
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
diff --git a/drivers/power/gta01_battery.c b/drivers/power/gta01_battery.c
index 81a0fe7387e..2078b071b06 100644
--- a/drivers/power/gta01_battery.c
+++ b/drivers/power/gta01_battery.c
@@ -23,8 +23,40 @@ static enum power_supply_property gta01_bat_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
};
+/* Capacity of typical BL-5C dumb battery */
+#define GTA01_BAT_CHARGE_FULL 850000
+
+static int gta01_bat_voltscale(int volt)
+{
+ /* This table is suggested by SpeedEvil based on analysis of
+ * experimental data */
+ static const int lut[][2] = {
+ { 4120, 100 },
+ { 3900, 60 },
+ { 3740, 25 },
+ { 3600, 5 },
+ { 3000, 0 } };
+ int i, res = 0;
+
+ if (volt > lut[0][0])
+ res = lut[0][1];
+ else
+ for (i = 0; lut[i][1]; i++) {
+ if (volt <= lut[i][0] && volt >= lut[i+1][0]) {
+ res = lut[i][1] - (lut[i][0]-volt)*
+ (lut[i][1]-lut[i+1][1])/
+ (lut[i][0]-lut[i+1][0]);
+ break;
+ }
+ }
+ return res;
+}
+
static int gta01_bat_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -33,20 +65,48 @@ static int gta01_bat_get_property(struct power_supply *psy,
switch(psp) {
case POWER_SUPPLY_PROP_STATUS:
- if (bat->pdata->get_charging_status())
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ if (bat->pdata->get_charging_status)
+ if (bat->pdata->get_charging_status())
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- val->intval = bat->pdata->get_voltage();
+ if (bat->pdata->get_voltage)
+ val->intval = bat->pdata->get_voltage();
+ else
+ val->intval = 0;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
- val->intval = bat->pdata->get_current();
+ if (bat->pdata->get_current)
+ val->intval = bat->pdata->get_current();
+ else
+ val->intval = 0;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1; /* You must never run GTA01 without battery. */
break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ if (bat->pdata->get_voltage) {
+ int perc = gta01_bat_voltscale(
+ bat->pdata->get_voltage()/1000);
+ val->intval = perc * GTA01_BAT_CHARGE_FULL / 100;
+ } else
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ if (bat->pdata->get_voltage)
+ val->intval = gta01_bat_voltscale(
+ bat->pdata->get_voltage()/1000);
+ else
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = GTA01_BAT_CHARGE_FULL;
+ break;
+
default:
return -EINVAL;
}
@@ -76,6 +136,7 @@ static int gta01_battery_probe(struct platform_device *pdev)
gta01_bat->psy.external_power_changed = gta01_bat_ext_changed;
gta01_bat->pdata = pdev->dev.platform_data;
+ platform_set_drvdata(pdev, gta01_bat);
power_supply_register(&pdev->dev, &gta01_bat->psy);
return 0;
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
index 1bdb9906201..6fbe26eb756 100644
--- a/drivers/power/pcf50633-charger.c
+++ b/drivers/power/pcf50633-charger.c
@@ -29,16 +29,12 @@
struct pcf50633_mbc {
struct pcf50633 *pcf;
- int adapter_active;
int adapter_online;
- int usb_active;
int usb_online;
struct power_supply usb;
struct power_supply adapter;
struct power_supply ac;
-
- struct delayed_work charging_restart_work;
};
int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
@@ -92,17 +88,19 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
/* If chgmod == BATFULL, setting chgena has no effect.
- * We need to set resume instead.
+ * Datasheet says we need to set resume instead but when autoresume is
+ * used resume doesn't work. Clear and set chgena instead.
*/
if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
- else
+ else {
+ pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1,
+ PCF50633_MBCC1_CHGENA);
pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
- PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);
+ PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
+ }
- mbc->usb_active = charging_start;
-
power_supply_changed(&mbc->usb);
return ret;
@@ -113,23 +111,44 @@ int pcf50633_mbc_get_status(struct pcf50633 *pcf)
{
struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
int status = 0;
+ u8 chgmod;
if (!mbc)
return 0;
+ chgmod = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2)
+ & PCF50633_MBCS2_MBC_MASK;
+
if (mbc->usb_online)
status |= PCF50633_MBC_USB_ONLINE;
- if (mbc->usb_active)
+ if (chgmod == PCF50633_MBCS2_MBC_USB_PRE ||
+ chgmod == PCF50633_MBCS2_MBC_USB_PRE_WAIT ||
+ chgmod == PCF50633_MBCS2_MBC_USB_FAST ||
+ chgmod == PCF50633_MBCS2_MBC_USB_FAST_WAIT)
status |= PCF50633_MBC_USB_ACTIVE;
if (mbc->adapter_online)
status |= PCF50633_MBC_ADAPTER_ONLINE;
- if (mbc->adapter_active)
+ if (chgmod == PCF50633_MBCS2_MBC_ADP_PRE ||
+ chgmod == PCF50633_MBCS2_MBC_ADP_PRE_WAIT ||
+ chgmod == PCF50633_MBCS2_MBC_ADP_FAST ||
+ chgmod == PCF50633_MBCS2_MBC_ADP_FAST_WAIT)
status |= PCF50633_MBC_ADAPTER_ACTIVE;
return status;
}
EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status);
+int pcf50633_mbc_get_usb_online_status(struct pcf50633 *pcf)
+{
+ struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
+
+ if (!mbc)
+ return 0;
+
+ return mbc->usb_online;
+}
+EXPORT_SYMBOL_GPL(pcf50633_mbc_get_usb_online_status);
+
static ssize_t
show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -226,75 +245,24 @@ static struct attribute_group mbc_attr_group = {
.attrs = pcf50633_mbc_sysfs_entries,
};
-/* MBC state machine switches into charging mode when the battery voltage
- * falls below 96% of a battery float voltage. But the voltage drop in Li-ion
- * batteries is marginal(1~2 %) till about 80% of its capacity - which means,
- * after a BATFULL, charging won't be restarted until 80%.
- *
- * This work_struct function restarts charging every few seconds and makes
- * sure we don't discharge too much
- */
-
-static void pcf50633_mbc_charging_restart(struct work_struct *work)
-{
- struct pcf50633_mbc *mbc;
- u8 mbcs2, chgmod;
-
- mbc = container_of(work, struct pcf50633_mbc,
- charging_restart_work.work);
-
- mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
- chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
-
- if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
- return;
-
- /* Restart charging */
- pcf50633_reg_set_bit_mask(mbc->pcf, PCF50633_REG_MBCC1,
- PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);
- mbc->usb_active = 1;
- power_supply_changed(&mbc->usb);
-
- dev_info(mbc->pcf->dev, "Charging restarted\n");
-}
-
static void
pcf50633_mbc_irq_handler(int irq, void *data)
{
struct pcf50633_mbc *mbc = data;
- int chg_restart_interval =
- mbc->pcf->pdata->charging_restart_interval;
/* USB */
if (irq == PCF50633_IRQ_USBINS) {
mbc->usb_online = 1;
} else if (irq == PCF50633_IRQ_USBREM) {
mbc->usb_online = 0;
- mbc->usb_active = 0;
pcf50633_mbc_usb_curlim_set(mbc->pcf, 0);
- cancel_delayed_work_sync(&mbc->charging_restart_work);
}
/* Adapter */
- if (irq == PCF50633_IRQ_ADPINS) {
+ if (irq == PCF50633_IRQ_ADPINS)
mbc->adapter_online = 1;
- mbc->adapter_active = 1;
- } else if (irq == PCF50633_IRQ_ADPREM) {
+ else if (irq == PCF50633_IRQ_ADPREM)
mbc->adapter_online = 0;
- mbc->adapter_active = 0;
- }
-
- if (irq == PCF50633_IRQ_BATFULL) {
- mbc->usb_active = 0;
- mbc->adapter_active = 0;
-
- if (chg_restart_interval > 0)
- schedule_delayed_work(&mbc->charging_restart_work,
- chg_restart_interval);
- } else if (irq == PCF50633_IRQ_USBLIMON)
- mbc->usb_active = 0;
- else if (irq == PCF50633_IRQ_USBLIMOFF)
- mbc->usb_active = 1;
power_supply_changed(&mbc->usb);
power_supply_changed(&mbc->adapter);
@@ -428,9 +396,6 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
mbc->ac.supplied_to = mbc->pcf->pdata->batteries;
mbc->ac.num_supplicants = mbc->pcf->pdata->num_batteries;
- INIT_DELAYED_WORK(&mbc->charging_restart_work,
- pcf50633_mbc_charging_restart);
-
ret = power_supply_register(&pdev->dev, &mbc->adapter);
if (ret) {
dev_err(mbc->pcf->dev, "failed to register adapter\n");
@@ -480,8 +445,6 @@ static int __devexit pcf50633_mbc_remove(struct platform_device *pdev)
power_supply_unregister(&mbc->usb);
power_supply_unregister(&mbc->adapter);
- cancel_delayed_work_sync(&mbc->charging_restart_work);
-
kfree(mbc);
return 0;