Skip to content

Commit

Permalink
pcf50633_charger: Enable periodic charging restart
Browse files Browse the repository at this point in the history
The battery charger 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 at regular intervals to
make sure the battery doesn't discharge too much.

Signed-off-by: Balaji Rao <balajirrao@openmoko.org>
Cc: Andy Green <andy@openmoko.com>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
  • Loading branch information
Balaji Rao authored and Anton Vorontsov committed Feb 2, 2009
1 parent ccc9c8b commit 9705ecc
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
73 changes: 71 additions & 2 deletions drivers/power/pcf50633-charger.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,28 @@ struct pcf50633_mbc {

struct power_supply usb;
struct power_supply adapter;

struct delayed_work charging_restart_work;
};

int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
{
struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
int ret = 0;
u8 bits;
int charging_start = 1;
u8 mbcs2, chgmod;

if (ma >= 1000)
bits = PCF50633_MBCC7_USB_1000mA;
else if (ma >= 500)
bits = PCF50633_MBCC7_USB_500mA;
else if (ma >= 100)
bits = PCF50633_MBCC7_USB_100mA;
else
else {
bits = PCF50633_MBCC7_USB_SUSPEND;
charging_start = 0;
}

ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
PCF50633_MBCC7_USB_MASK, bits);
Expand All @@ -60,6 +66,22 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
else
dev_info(pcf->dev, "usb curlim to %d mA\n", ma);

/* Manual charging start */
mbcs2 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);

/* If chgmod == BATFULL, setting chgena has no effect.
* We need to set resume instead.
*/
if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
else
pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);

mbc->usb_active = charging_start;

power_supply_changed(&mbc->usb);

return ret;
Expand Down Expand Up @@ -160,10 +182,44 @@ 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 at regular intervals to make
* 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) {
Expand All @@ -172,6 +228,7 @@ pcf50633_mbc_irq_handler(int irq, void *data)
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 */
Expand All @@ -186,7 +243,14 @@ pcf50633_mbc_irq_handler(int irq, void *data)
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);
Expand Down Expand Up @@ -303,6 +367,9 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
return ret;
}

INIT_DELAYED_WORK(&mbc->charging_restart_work,
pcf50633_mbc_charging_restart);

ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group);
if (ret)
dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");
Expand All @@ -328,6 +395,8 @@ 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;
Expand Down
2 changes: 2 additions & 0 deletions include/linux/mfd/pcf50633/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct pcf50633_platform_data {
char **batteries;
int num_batteries;

int charging_restart_interval;

/* Callbacks */
void (*probe_done)(struct pcf50633 *);
void (*mbc_event_callback)(struct pcf50633 *, int);
Expand Down

0 comments on commit 9705ecc

Please sign in to comment.