summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Wilson <evan@oliodevices.com>2016-01-20 02:10:50 +0000
committerGerrit Code Review <gerrit2@ip-172-31-25-77.us-west-1.compute.internal>2015-04-16 10:08:13 +0000
commit058e418668659a82ae277b05dc1fc1a546aa3bc8 (patch)
tree84dd0edeb63c32b667577d42e3c2823876c69942
parent7a919b1fe2429b091d2c983ed554b431d3828abf (diff)
parentadacad29a479dff5c4959e11f59ed2623faa455a (diff)
downloadolio-linux-3.10-058e418668659a82ae277b05dc1fc1a546aa3bc8.tar.xz
olio-linux-3.10-058e418668659a82ae277b05dc1fc1a546aa3bc8.zip
Merge "Enable/disable fuel gauge wake up depending on charge state. This turns off interrupts from the fuel gauge while charging." into android-3.10-bringup
-rw-r--r--arch/arm/boot/dts/omap3_h1.dts26
-rw-r--r--drivers/i2c/busses/i2c-omap.c2
-rw-r--r--drivers/power/bq27x00_battery.c225
3 files changed, 221 insertions, 32 deletions
diff --git a/arch/arm/boot/dts/omap3_h1.dts b/arch/arm/boot/dts/omap3_h1.dts
index e82008f9b87..46c6e2d97b1 100644
--- a/arch/arm/boot/dts/omap3_h1.dts
+++ b/arch/arm/boot/dts/omap3_h1.dts
@@ -68,7 +68,7 @@
* for a gpio IRQ (banks numbered 1 to 6)
* irq = 16 + 96 + (gpio_bank - 1) * 32 + GPIO no.
*/
- compatible = "ti,pad-wkup";
+ compatible = "ti,pad-wkup";
/* Map the pad offset (off) to an interrupt (IRQ). */
/* if handle is 1, an irq will be generated based on */
@@ -83,10 +83,10 @@
/* off IRQ handle */
ti,pad_irq = <0x150 88 1>, /* 72 + 16, uart1 - BT input */
- <0x9f6 143 1>, /* mpu6515 irq pin - is this offset correct? */
- <0x9ea 122 1>, /* bq27400 chg irq8 */
- <0x9f4 123 1>, /* BT host wake */
- <0x1b0 23 1>; /* sys_nirq */
+ <0x9f6 143 1>, /* mpu6515 irq pin - is this offset correct? */
+ /* <0x9ea 122 1>, */ /* bq27400 chg irq8 - needed here? */
+ <0x9f4 123 1>, /* BT host wake */
+ <0x1b0 23 1>; /* sys_nirq */
};
sound {
@@ -216,14 +216,14 @@
>;
};
- dev_pins: pinmux_pv_pins {
- pinctrl-single,pins = <
- 0x5b2 0x204 /* USB control, ETK_D3, MODE4 | OUTPUT */
- /* 0x1a2 0x104 */ /* ALS interrupt, input, GPIO */
- 0x086 0x004 /* DRV2605 vibrator, output, GPIO */
- /* 0x938 0x104 */ /* Battery state, input, GPIO */
- >;
- };
+dev_pins: pinmux_pv_pins {
+ pinctrl-single,pins = <
+ 0x5b2 0x204 /* USB control, ETK_D3, MODE4 | OUTPUT */
+ /* 0x1a2 0x104 */ /* ALS interrupt, input, GPIO */
+ 0x086 0x004 /* DRV2605 vibrator, output, GPIO */
+ /* 0x938 0x104 */ /* Battery state, input, GPIO */
+ >;
+ };
/*
i2c1_pins: pinmux_i2c1_pins {
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 0e15ad357aa..00fb5ac811c 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -690,7 +690,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
r = omap_i2c_wait_for_bb(dev);
/* If timeout, try to again check after attempting to clear the bus */
- if (WARN_ON(r == -ETIMEDOUT)) {
+ if (r == -ETIMEDOUT) { /* removed WARN_ON here, too much output from ts81001 */
r = omap_i2c_bus_clear(dev);
if (r < 0) {
dev_err(dev->dev, "Unable to recover i2c bus from bb\n");
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 144e36bf07d..5835bc881cd 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -47,6 +47,19 @@
#include <linux/power/bq27x00_battery.h>
#ifdef CONFIG_OLIO_TS81001
+
+/*
+ * OLIO Model One needs the fuel gauge to talk to the charger in some
+ * instances, such as deciding whether we're using the wireless
+ * charger or not. Hence this build flag.
+ *
+ * In hindsight, a lot of this can probably be moved to the charger
+ * manager.
+ */
+
+#include "asm/io.h"
+#include "../../arch/arm/mach-omap2/mux.h"
+#include "../../arch/arm/mach-omap2/iomap.h"
#include "../staging/triune/ts81001.h"
#endif /* CONFIG_OLIO_TS81001 */
@@ -58,7 +71,6 @@
#define olio_debug(format, ...)
#endif
-
#define DRIVER_VERSION "1.2.0"
#define INVALID_REG_ADDR 0xFF
@@ -84,8 +96,14 @@ enum bq27xxx_reg_index {
NUM_REGS
};
+/* lock taken if we want the upper layers to run */
+
struct wake_lock chg_wake_lock;
+/* lock taken by interrupt to let work queue run*/
+
+struct wake_lock isr_wake_lock;
+
/* bq27500 registers */
static __initdata u8 bq27500_regs[NUM_REGS] = {
0x00, /* CONTROL */
@@ -226,7 +244,7 @@ static __initdata u8 bq276xx_regs[NUM_REGS] = {
#define BQ274XX_UNSEAL_KEY 0x80008000
#define BQ274XX_SOFT_RESET 0x43
-#define BQ274XX_FLAG_ITPOR 0x20
+#define BQ274XX_FLAG_ITPOR 0x20
#define BQ274XX_CTRL_STATUS_INITCOMP 0x80
#define BQ27XXX_FLAG_DSC BIT(0)
@@ -306,6 +324,7 @@ struct bq27x00_device_info {
unsigned long last_update;
struct delayed_work work;
+ struct delayed_work interrupt_work;
struct power_supply bat;
@@ -410,6 +429,10 @@ static __initdata enum power_supply_property bq276xx_battery_props[] = {
* Ordering the parameters based on subclass and then offset will help in
* having fewer flash writes while updating.
* Customize these values and, if necessary, add more based on system needs.
+
+ To be added, maybe (for bq274xx):
+ {81, 9, 1, 3}, /* Quit Relax Time (3s) */
+
*/
static struct dm_reg bq274xx_dm_regs[] = {
{36, 6, 1, 90}, /* FC Clear % */
@@ -447,6 +470,14 @@ static int read_dm_block(struct bq27x00_device_info *di, u8 subclass,
u8 offset, u8 *data);
+#ifdef CONFIG_OLIO_TS81001
+static int bq27x00_charger_status(struct bq27x00_device_info *di,
+ union power_supply_propval *val);
+static int bq27x00_battery_status(struct bq27x00_device_info *di,
+ union power_supply_propval *val);
+#endif
+
+
/*
* Common code for BQ27x00 devices
*/
@@ -1067,10 +1098,11 @@ static bool rom_mode_gauge_dm_initialized(struct bq27x00_device_info *di)
dev_dbg(di->dev, "%s: flags - 0x%04x\n", __func__, flags);
- if (flags & BQ274XX_FLAG_ITPOR)
+ if (flags & BQ274XX_FLAG_ITPOR) {
return false;
- else
+ } else {
return true;
+ }
}
#define INITCOMP_TIMEOUT_MS 10000
@@ -1110,6 +1142,9 @@ static void rom_mode_gauge_dm_init(struct bq27x00_device_info *di)
subclass = dm_reg->subclass;
offset = dm_reg->offset;
+ printk ("%s OLIO updating reg %d, offset %d\n", __FUNCTION__,
+ subclass, offset);
+
/*
* Create a composite block number to see if the subsequent
* register also belongs to the same 32 btye block in the DM
@@ -1143,10 +1178,112 @@ static void rom_mode_gauge_dm_init(struct bq27x00_device_info *di)
exit_cfg_update_mode(di);
}
-static void bq27x00_battery_poll(struct work_struct *work)
+/***************************************************************************
+ * bq27x00_should_wakeup - decide whether to sleep or wake
+ *
+ * All I need is the power level last time we had an interrupt. If it isn't
+ * at least 2% from last time, go back to sleep.
+ *
+ * OK, that's not good enough. It needs to detect whether we're on or off
+ * the charger as well - use the status inquiry for that.
+ *
+ * I need to make a wrapper function around battery_poll that can be
+ * invoked when we're coming from an interrupt. That, or a global variable.
+ * Some way to only do this test when it's actually relevant.
+ */
+
+
+static bool bq27x00_should_wakeup(struct bq27x00_device_info *di) {
+
+ static int previous_charge = 0; /* initial value */
+ static int status_previous = 0;
+ int charge_diff;
+ int soc;
+ union power_supply_propval val;
+
+ int status;
+
+ printk ("%s OLIO entered\n", __FUNCTION__);
+
+ /* check if power change is big enough for us to
+ * wake up to.
+ */
+
+ if ((soc = bq27x00_battery_read_soc(di)) < 0)
+ return false; /* error */
+
+ charge_diff = abs (soc - previous_charge);
+
+ printk ("%s OLIO found diff %d\n", __FUNCTION__, charge_diff);
+
+ if (charge_diff >= 5) {
+ previous_charge = soc;
+ printk ("exiting, true\n");
+ return true;
+ }
+
+ /* else check the status. This should turn off interrupts if
+ * it wasn't done before.
+ */
+
+ status = bq27x00_battery_status(di, &val);
+
+ /* we ignore unknown statuses - it's probably just the ts81001
+ * that hasn't woken up yet
+ */
+
+ if (status != POWER_SUPPLY_STATUS_UNKNOWN &&
+ status != status_previous) { /* something has changed! */
+ printk ("%s OLIO state changed (old = %d, new = %d, "
+ "wake up!\n", __FUNCTION__, status_previous,
+ status);
+ status_previous = status;
+ return true;
+ } else {
+ printk ("%s OLIO old state = %d, new state = %d, sleep\n",
+ __FUNCTION__, status_previous, status);
+ }
+
+ printk ("exiting, false\n");
+
+ return false;
+}
+
+/***************************************************************************
+ * bq27x00_battery_interrupt - work to do from interrupt
+ *
+ * Decide whether we actually want to wake up, then take a wake lock if
+ * appropriate.
+ */
+
+static void bq27x00_battery_interrupt (struct work_struct *i_work)
+{
+ int status;
+ union power_supply_propval val;
+ struct bq27x00_device_info *di =
+ container_of(i_work, struct bq27x00_device_info, interrupt_work.work);
+
+ printk ("%s OLIO taking charge wake lock\n", __FUNCTION__);
+
+ wake_lock_timeout(&chg_wake_lock, msecs_to_jiffies(500));
+ bq27x00_update (di);
+ status = bq27x00_battery_status(di, &val);
+#if 0
+ if (bq27x00_should_wakeup(di)) {
+
+ }
+#endif
+ printk ("%s OLIO battery status = %d\n", __FUNCTION__, status);
+
+ /* release the low-level wake lock (taken in isr handler) */
+ wake_unlock (&isr_wake_lock);
+}
+
+
+static void bq27x00_battery_poll(struct work_struct *p_work)
{
struct bq27x00_device_info *di =
- container_of(work, struct bq27x00_device_info, work.work);
+ container_of(p_work, struct bq27x00_device_info, work.work);
if (((di->chip == BQ274XX) || (di->chip == BQ276XX)) &&
!rom_mode_gauge_dm_initialized(di)) {
@@ -1168,7 +1305,7 @@ static void bq27x00_battery_poll(struct work_struct *work)
* Or 0 if something fails.
*/
static int bq27x00_battery_current(struct bq27x00_device_info *di,
- union power_supply_propval *val)
+ union power_supply_propval *val)
{
int curr;
int flags;
@@ -1197,13 +1334,39 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di,
#ifdef CONFIG_OLIO_TS81001
-static int bq27x00_charger_status(struct bq27x00_device_info *di,
- union power_supply_propval *val) {
+/* These are unfortunately hardcoded to our (OLIO's) GPIO pins right now. */
+
+/* We need to turn off the wakeup capability of the pins when we don't
+ * want the interrupts, or all heck breaks loose.
+
+static void olio_interrupt_enabled (int irq) {
+ __raw_writew ((u16) (4 << 12 | 1 << 8 | 0 << 4 | 4),
+ (volatile void *)
+ OMAP2_L4_IO_ADDRESS(OMAP3_CONTROL_PADCONF_MUX_PBASE) +
+ OMAP3_CONTROL_PADCONF_SYS_CLKOUT1_OFFSET);
+ enable_irq (irq);
+ enable_irq_wake (irq);
+}
+
+
+static void olio_interrupt_disabled (int irq) {
+ disable_irq_wake (irq);
+ disable_irq (irq);
+ __raw_writew ((u16) (0 << 12 | 1 << 8 | 0 << 4 | 4),
+ (volatile void *)
+ OMAP2_L4_IO_ADDRESS(OMAP3_CONTROL_PADCONF_MUX_PBASE) +
+ OMAP3_CONTROL_PADCONF_SYS_CLKOUT1_OFFSET);
+}
+
+
+static volatile int irq_enabled = 1; /* enabled from start */
+
+static int bq27x00_charger_status (struct bq27x00_device_info *di,
+ union power_supply_propval *val) {
struct device * bq = di->dev;
struct bq27x00_platform_data * pdata = bq->platform_data;
struct ts81001 * ts81001;
ts81001_state_t state;
- int curr;
olio_debug("entered\n");
@@ -1240,11 +1403,29 @@ static int bq27x00_charger_status(struct bq27x00_device_info *di,
{
case NOT_CHARGING:
olio_debug("exiting, DISCHARGING\n");
+ mutex_lock(&di->lock);
+ if (!irq_enabled) {
+ printk ("%s OLIO off charger, enabling chg interrupts\n",
+ __FUNCTION__);
+ irq_enabled = 1;
+ olio_interrupt_enabled (di->irq);
+ /* enable_irq_wake (di->irq); */ /* enable interrupts */
+ }
+ mutex_unlock(&di->lock);
return POWER_SUPPLY_STATUS_DISCHARGING;
case PRECHARGE:
case CHARGING_1C:
case TOPOFF:
olio_debug("exiting, CHARGING\n");
+ mutex_lock(&di->lock);
+ if (irq_enabled) {
+ printk ("%s OLIO on charger, disabling chg interrupts\n",
+ __FUNCTION__);
+ irq_enabled = 0;
+ olio_interrupt_disabled (di->irq);
+ /* disable_irq_wake (di->irq); */ /* disable interrupts */
+ }
+ mutex_unlock(&di->lock);
return POWER_SUPPLY_STATUS_CHARGING;
default:
olio_debug("Couldn't read status from ts81001 charger.\n");
@@ -1252,7 +1433,6 @@ static int bq27x00_charger_status(struct bq27x00_device_info *di,
return POWER_SUPPLY_STATUS_UNKNOWN;
}
}
-
#endif
static int bq27x00_battery_status(struct bq27x00_device_info *di,
@@ -1438,6 +1618,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
return ret;
}
+
static void bq27x00_external_power_changed(struct power_supply *psy)
{
struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
@@ -1446,14 +1627,17 @@ static void bq27x00_external_power_changed(struct power_supply *psy)
schedule_delayed_work(&di->work, 0);
}
-static irqreturn_t bq27x00_chg_isr(int irq, void *dev) {
+static irqreturn_t bq27x00_chg_isr(int irq, void *dev) {
struct power_supply *ps = (struct power_supply*) dev;
- wake_lock_timeout(&chg_wake_lock, msecs_to_jiffies(500));
- /* dev_dbg(ps->dev, "%s: Updating battery status\n", __func__); Don't
- do i/o in interrupt! */
+ struct bq27x00_device_info *di = to_bq27x00_device_info(ps);
+
+ printk ("%s OLIO ISR triggered!\n", __FUNCTION__);
+
+ wake_lock(&isr_wake_lock);
- bq27x00_external_power_changed(ps);
+ cancel_delayed_work(&di->interrupt_work);
+ schedule_delayed_work(&di->interrupt_work, 0);
return IRQ_HANDLED;
}
@@ -1497,6 +1681,7 @@ static int __init bq27x00_powersupply_init(struct bq27x00_device_info *di)
di->bat.get_property = bq27x00_battery_get_property;
di->bat.external_power_changed = bq27x00_external_power_changed;
+ INIT_DELAYED_WORK(&di->interrupt_work, bq27x00_battery_interrupt);
INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll);
mutex_init(&di->lock);
@@ -1510,6 +1695,7 @@ static int __init bq27x00_powersupply_init(struct bq27x00_device_info *di)
/* device_init_wakeup(di->dev, 1); */
+ wake_lock_init(&isr_wake_lock, WAKE_LOCK_SUSPEND, "isr_wake_lock");
wake_lock_init(&chg_wake_lock, WAKE_LOCK_SUSPEND, "chg_wake_lock");
if(di->irq) {
@@ -1549,6 +1735,7 @@ static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di)
poll_interval = 0;
cancel_delayed_work_sync(&di->work);
+ cancel_delayed_work_sync(&di->interrupt_work);
power_supply_unregister(&di->bat);
@@ -1786,6 +1973,7 @@ static const struct attribute_group bq27x00_attr_group = {
#ifdef CONFIG_OLIO_TS81001
+
/***************************************************************************
* bq27x00_set_platform_data - act on basic platform data
*
@@ -1914,6 +2102,7 @@ static int __init bq27x00_battery_probe(struct i2c_client *client,
goto batt_failed_3;
/* Schedule a polling after about 1 min */
+
schedule_delayed_work(&di->work, 60 * HZ);
i2c_set_clientdata(client, di);
@@ -1967,8 +2156,8 @@ static struct i2c_driver bq27x00_battery_driver = {
.driver = {
.name = "bq27x00-battery",
},
- .probe = bq27x00_battery_probe,
- .remove = bq27x00_battery_remove,
+ .probe = bq27x00_battery_probe,
+ .remove = bq27x00_battery_remove,
.id_table = bq27x00_id,
};