aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.26/1153-introduce-charging-led-behaviour.patch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.26/1153-introduce-charging-led-behaviour.patch.patch')
-rwxr-xr-xtarget/linux/s3c24xx/patches-2.6.26/1153-introduce-charging-led-behaviour.patch.patch423
1 files changed, 0 insertions, 423 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.26/1153-introduce-charging-led-behaviour.patch.patch b/target/linux/s3c24xx/patches-2.6.26/1153-introduce-charging-led-behaviour.patch.patch
deleted file mode 100755
index 6f510ed0cc..0000000000
--- a/target/linux/s3c24xx/patches-2.6.26/1153-introduce-charging-led-behaviour.patch.patch
+++ /dev/null
@@ -1,423 +0,0 @@
-From 86bec3382cd1694a3b5cd6d8796cfcbdbe5ca5ff Mon Sep 17 00:00:00 2001
-From: Andy Green <andy@openmoko.com>
-Date: Fri, 25 Jul 2008 23:06:11 +0100
-Subject: [PATCH] introduce-charging-led-behaviour.patch
-
-Creates a new behaviour requested by Will that the red LED on GTA02
-is lit during battery charging.and goes out when the battery is full.
-
-This is done by leveraging the PMU interrupts, but in one scenario
-there is no interrupt that occurs, when the battery is replaced after
-being removed with the USB power in all the while. So a sleepy work
-function is started under those circumstances to watch for battery
-reinsertion or USB cable pull.
-
-100mA limit was not being observed under some conditions so this was
-fixed and tested with a USB cable with D+/D- disconnected. 1A
-charger behaviour was also tested.
-
-Showing the charging action exposes some inconsistency in pcf50633
-charging action. If your battery is nearly full, it will keep
-charging it at decreasing current even after it thinks it is at
-100% capacity for a long while. But if you pull that same battery
-and re-insert it, the charger state machine in pcf50633 believe it is
-full and won't charge it.
-
-Signed-off-by: Andy Green <andy@openmoko.com>
----
- arch/arm/mach-s3c2440/mach-gta02.c | 8 ++
- drivers/i2c/chips/pcf50633.c | 212 ++++++++++++++++++++++++++++++++++--
- include/linux/pcf506xx.h | 2 +
- 3 files changed, 214 insertions(+), 8 deletions(-)
-
-diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
-index 601f7bc..d7882ea 100644
---- a/arch/arm/mach-s3c2440/mach-gta02.c
-+++ b/arch/arm/mach-s3c2440/mach-gta02.c
-@@ -437,6 +437,14 @@ static int pmu_callback(struct device *dev, unsigned int feature,
- case PMU_EVT_USB_REMOVE:
- pcf50633_charge_enable(pcf50633_global, 0);
- break;
-+ case PMU_EVT_CHARGER_IDLE:
-+ /* printk(KERN_ERR"PMU_EVT_CHARGER_IDLE\n"); */
-+ neo1973_gpb_setpin(GTA02_GPIO_AUX_LED, 0);
-+ break;
-+ case PMU_EVT_CHARGER_ACTIVE:
-+ /* printk(KERN_ERR"PMU_EVT_CHARGER_ACTIVE\n"); */
-+ neo1973_gpb_setpin(GTA02_GPIO_AUX_LED, 1);
-+ break;
- default:
- break;
- }
-diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
-index 8ba81d2..38cabd2 100644
---- a/drivers/i2c/chips/pcf50633.c
-+++ b/drivers/i2c/chips/pcf50633.c
-@@ -47,6 +47,7 @@
- #include <linux/platform_device.h>
- #include <linux/pcf50633.h>
- #include <linux/apm-emulation.h>
-+#include <linux/jiffies.h>
-
- #include <asm/mach-types.h>
- #include <asm/arch/gta02.h>
-@@ -121,8 +122,23 @@ struct pcf50633_data {
- int onkey_seconds;
- int irq;
- int have_been_suspended;
-+ int usb_removal_count;
- unsigned char pcfirq_resume[5];
-
-+ /* if he pulls battery while charging, we notice that and correctly
-+ * report that the charger is idle. But there is no interrupt that
-+ * fires if he puts a battery back in and charging resumes. So when
-+ * the battery is pulled, we run this work function looking for
-+ * either charger resumption or USB cable pull
-+ */
-+ struct mutex working_lock_nobat;
-+ struct work_struct work_nobat;
-+ int working_nobat;
-+ int usb_removal_count_nobat;
-+ int jiffies_last_bat_ins;
-+
-+ int last_curlim_set;
-+
- int coldplug_done; /* cleared by probe, set by first work service */
- int flag_bat_voltage_read; /* ipc to /sys batt voltage read func */
-
-@@ -259,6 +275,8 @@ static u_int16_t async_adc_complete(struct pcf50633_data *pcf)
- (__reg_read(pcf, PCF50633_REG_ADCS3) &
- PCF50633_ADCS3_ADCDAT1L_MASK);
-
-+ DEBUGPC("adc result = %d\n", ret);
-+
- return ret;
- }
-
-@@ -512,8 +530,7 @@ static void configure_pmu_for_charger(struct pcf50633_data *pcf,
- {
- switch (type) {
- case CHARGER_TYPE_NONE:
-- __reg_write(pcf, PCF50633_REG_MBCC7,
-- PCF50633_MBCC7_USB_SUSPEND);
-+ pcf50633_usb_curlim_set(pcf, 0);
- break;
- /*
- * the PCF50633 has a feature that it will supply only excess current
-@@ -521,10 +538,19 @@ static void configure_pmu_for_charger(struct pcf50633_data *pcf,
- * 500mA setting is "up to 500mA" according to that.
- */
- case CHARGER_TYPE_HOSTUSB:
-- __reg_write(pcf, PCF50633_REG_MBCC7, PCF50633_MBCC7_USB_500mA);
-+ /* USB subsystem should call pcf50633_usb_curlim_set to set
-+ * what was negotiated with the host when it is enumerated
-+ * successfully. If we get called again after a good
-+ * negotiation, we keep what was negotiated. (Removal of
-+ * USB plug destroys pcf->last_curlim_set to 0)
-+ */
-+ if (pcf->last_curlim_set > 100)
-+ pcf50633_usb_curlim_set(pcf, pcf->last_curlim_set);
-+ else
-+ pcf50633_usb_curlim_set(pcf, 100);
- break;
- case CHARGER_TYPE_1A:
-- __reg_write(pcf, PCF50633_REG_MBCC7, PCF50633_MBCC7_USB_1000mA);
-+ pcf50633_usb_curlim_set(pcf, 1000);
- /*
- * stop GPO / EN_HOSTUSB power driving out on the same
- * USB power pins we have a 1A charger on right now!
-@@ -536,6 +562,12 @@ static void configure_pmu_for_charger(struct pcf50633_data *pcf,
- PCF50633_REG_GPIO1CFG) & 0xf0);
- break;
- }
-+
-+ /* max out USB fast charge current -- actual current drawn is
-+ * additionally limited by USB limit so no worries
-+ */
-+ __reg_write(pcf, PCF50633_REG_MBCC5, 0xff);
-+
- }
-
- static void trigger_next_adc_job_if_any(struct pcf50633_data *pcf)
-@@ -562,6 +594,49 @@ static void add_request_to_adc_queue(struct pcf50633_data *pcf,
- trigger_next_adc_job_if_any(pcf);
- }
-
-+/* we are run when we see a NOBAT situation, because there is no interrupt
-+ * source in pcf50633 that triggers on resuming charging. It watches to see
-+ * if charging resumes, it reassesses the charging source if it does. If the
-+ * USB power disappears, it is also a sign there must be a battery and it is
-+ * NOT being charged, so it exits since the next move must be USB insertion for
-+ * change of charger state
-+ */
-+
-+static void pcf50633_work_nobat(struct work_struct *work)
-+{
-+ struct pcf50633_data *pcf =
-+ container_of(work, struct pcf50633_data, work_nobat);
-+
-+ mutex_lock(&pcf->working_lock_nobat);
-+ pcf->working_nobat = 1;
-+ mutex_unlock(&pcf->working_lock_nobat);
-+
-+ while (1) {
-+ msleep(1000);
-+
-+ /* there's a battery in there now? */
-+ if (reg_read(pcf, PCF50633_REG_MBCS3) & 0x40) {
-+
-+ pcf->jiffies_last_bat_ins = jiffies;
-+
-+ /* figure out our charging stance */
-+ add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
-+ PCF50633_ADCC1_AVERAGE_16);
-+ goto bail;
-+ }
-+
-+ /* he pulled USB cable since we were started? exit then */
-+ if (pcf->usb_removal_count_nobat != pcf->usb_removal_count)
-+ goto bail;
-+ }
-+
-+bail:
-+ mutex_lock(&pcf->working_lock_nobat);
-+ pcf->working_nobat = 0;
-+ mutex_unlock(&pcf->working_lock_nobat);
-+}
-+
-+
- static void pcf50633_work(struct work_struct *work)
- {
- struct pcf50633_data *pcf =
-@@ -674,20 +749,29 @@ static void pcf50633_work(struct work_struct *work)
- if (pcf->pdata->cb)
- pcf->pdata->cb(&pcf->client.dev,
- PCF50633_FEAT_MBC, PMU_EVT_USB_INSERT);
-+ msleep(500); /* debounce, allow to see any ID resistor */
- /* completion irq will figure out our charging stance */
- add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
- PCF50633_ADCC1_AVERAGE_16);
- }
- if (pcfirq[0] & PCF50633_INT1_USBREM) {
- DEBUGPC("USBREM ");
-+
-+ pcf->usb_removal_count++;
-+
- /* only deal if we had understood it was in */
- if (pcf->flags & PCF50633_F_USB_PRESENT) {
- input_report_key(pcf->input_dev, KEY_POWER2, 0);
- apm_queue_event(APM_POWER_STATUS_CHANGE);
- pcf->flags &= ~PCF50633_F_USB_PRESENT;
-+
- if (pcf->pdata->cb)
- pcf->pdata->cb(&pcf->client.dev,
- PCF50633_FEAT_MBC, PMU_EVT_USB_REMOVE);
-+
-+ /* destroy any memory of grant of power from host */
-+ pcf->last_curlim_set = 0;
-+
- /* completion irq will figure out our charging stance */
- add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
- PCF50633_ADCC1_AVERAGE_16);
-@@ -759,6 +843,33 @@ static void pcf50633_work(struct work_struct *work)
-
- if (pcfirq[2] & PCF50633_INT3_BATFULL) {
- DEBUGPC("BATFULL ");
-+
-+ /* the problem is, we get a false BATFULL if we inserted battery
-+ * while USB powered. Defeat BATFULL if we recently inserted
-+ * battery
-+ */
-+
-+ if ((jiffies - pcf->jiffies_last_bat_ins) < (HZ * 2)) {
-+
-+ DEBUGPC("*** Ignoring BATFULL ***\n");
-+
-+ ret = reg_read(pcf, PCF50633_REG_MBCC7) &
-+ PCF56033_MBCC7_USB_MASK;
-+
-+
-+ reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
-+ PCF56033_MBCC7_USB_MASK,
-+ PCF50633_MBCC7_USB_SUSPEND);
-+
-+ reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
-+ PCF56033_MBCC7_USB_MASK,
-+ ret);
-+ } else {
-+ if (pcf->pdata->cb)
-+ pcf->pdata->cb(&pcf->client.dev,
-+ PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
-+ }
-+
- /* FIXME: signal this to userspace */
- }
- if (pcfirq[2] & PCF50633_INT3_CHGHALT) {
-@@ -796,8 +907,7 @@ static void pcf50633_work(struct work_struct *work)
-
- switch (pcf->adc_queue_mux[tail]) {
- case PCF50633_ADCC1_MUX_BATSNS_RES: /* battery voltage */
-- pcf->flag_bat_voltage_read =
-- async_adc_complete(pcf);
-+ pcf->flag_bat_voltage_read = async_adc_complete(pcf);
- break;
- case PCF50633_ADCC1_MUX_ADCIN1: /* charger type */
- pcf->charger_adc_result_raw = async_adc_complete(pcf);
-@@ -829,8 +939,37 @@ static void pcf50633_work(struct work_struct *work)
- (PCF50633_MBCS1_USBPRES | PCF50633_MBCS1_USBOK)) {
- /*
- * hey no need to freak out, we have some kind of
-- * valid charger power
-+ * valid charger power to keep us going -- but note that
-+ * we are not actually charging anything
-+ */
-+ if (pcf->pdata->cb)
-+ pcf->pdata->cb(&pcf->client.dev,
-+ PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
-+
-+ reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
-+ PCF50633_MBCC1_RESUME,
-+ PCF50633_MBCC1_RESUME);
-+
-+ /*
-+ * Well, we are not charging anything right this second
-+ * ... however in the next ~30s before we get the next
-+ * NOBAT, he might insert a battery. So we schedule a
-+ * work function checking to see if
-+ * we started charging something during that time.
-+ * USB removal as well as charging terminates the work
-+ * function so we can't get terminally confused
- */
-+ mutex_lock(&pcf->working_lock_nobat);
-+ if (!pcf->working_nobat) {
-+ pcf->usb_removal_count_nobat =
-+ pcf->usb_removal_count;
-+
-+ if (!schedule_work(&pcf->work_nobat))
-+ DEBUGPC("failed to schedule nobat\n");
-+ }
-+ mutex_unlock(&pcf->working_lock_nobat);
-+
-+
- DEBUGPC("(NO)BAT ");
- } else {
- /* Really low battery voltage, we have 8 seconds left */
-@@ -1063,10 +1202,13 @@ void pcf50633_usb_curlim_set(struct pcf50633_data *pcf, int ma)
- {
- u_int8_t bits;
-
-+ pcf->last_curlim_set = ma;
-+
- dev_dbg(&pcf->client.dev, "setting usb current limit to %d ma", ma);
-
-- if (ma >= 1000)
-+ if (ma >= 1000) {
- bits = PCF50633_MBCC7_USB_1000mA;
-+ }
- else if (ma >= 500)
- bits = PCF50633_MBCC7_USB_500mA;
- else if (ma >= 100)
-@@ -1074,8 +1216,40 @@ void pcf50633_usb_curlim_set(struct pcf50633_data *pcf, int ma)
- else
- bits = PCF50633_MBCC7_USB_SUSPEND;
-
-+ DEBUGPC("pcf50633_usb_curlim_set -> %dmA\n", ma);
-+
-+ if (!pcf->pdata->cb)
-+ goto set_it;
-+
-+ switch (bits) {
-+ case PCF50633_MBCC7_USB_100mA:
-+ case PCF50633_MBCC7_USB_SUSPEND:
-+ /* no charging is gonna be happening */
-+ pcf->pdata->cb(&pcf->client.dev,
-+ PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
-+ break;
-+ default: /* right charging context that if there is power, we charge */
-+ if (pcf->flags & PCF50633_F_USB_PRESENT)
-+ pcf->pdata->cb(&pcf->client.dev,
-+ PCF50633_FEAT_MBC, PMU_EVT_CHARGER_ACTIVE);
-+ break;
-+ }
-+
-+set_it:
- reg_set_bit_mask(pcf, PCF50633_REG_MBCC7, PCF56033_MBCC7_USB_MASK,
- bits);
-+
-+ /* clear batfull */
-+ reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
-+ PCF50633_MBCC1_AUTORES,
-+ 0);
-+ reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
-+ PCF50633_MBCC1_RESUME,
-+ PCF50633_MBCC1_RESUME);
-+ reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
-+ PCF50633_MBCC1_AUTORES,
-+ PCF50633_MBCC1_AUTORES);
-+
- }
- EXPORT_SYMBOL_GPL(pcf50633_usb_curlim_set);
-
-@@ -1105,16 +1279,36 @@ static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, NULL);
- void pcf50633_charge_enable(struct pcf50633_data *pcf, int on)
- {
- u_int8_t bits;
-+ u_int8_t usblim;
-
- if (!(pcf->pdata->used_features & PCF50633_FEAT_MBC))
- return;
-
-+ DEBUGPC("pcf50633_charge_enable %d\n", on);
-+
- if (on) {
- pcf->flags |= PCF50633_F_CHG_ENABLED;
- bits = PCF50633_MBCC1_CHGENA;
-+ usblim = reg_read(pcf, PCF50633_REG_MBCC7) &
-+ PCF56033_MBCC7_USB_MASK;
-+ switch (usblim) {
-+ case PCF50633_MBCC7_USB_1000mA:
-+ case PCF50633_MBCC7_USB_500mA:
-+ if (pcf->flags & PCF50633_F_USB_PRESENT)
-+ if (pcf->pdata->cb)
-+ pcf->pdata->cb(&pcf->client.dev,
-+ PCF50633_FEAT_MBC,
-+ PMU_EVT_CHARGER_ACTIVE);
-+ break;
-+ default:
-+ break;
-+ }
- } else {
- pcf->flags &= ~PCF50633_F_CHG_ENABLED;
- bits = 0;
-+ if (pcf->pdata->cb)
-+ pcf->pdata->cb(&pcf->client.dev,
-+ PCF50633_FEAT_MBC, PMU_EVT_CHARGER_IDLE);
- }
- reg_set_bit_mask(pcf, PCF50633_REG_MBCC1, PCF50633_MBCC1_CHGENA,
- bits);
-@@ -1703,7 +1897,9 @@ static int pcf50633_detect(struct i2c_adapter *adapter, int address, int kind)
-
- mutex_init(&data->lock);
- mutex_init(&data->working_lock);
-+ mutex_init(&data->working_lock_nobat);
- INIT_WORK(&data->work, pcf50633_work);
-+ INIT_WORK(&data->work_nobat, pcf50633_work_nobat);
- data->irq = irq;
- data->working = 0;
- data->onkey_seconds = -1;
-diff --git a/include/linux/pcf506xx.h b/include/linux/pcf506xx.h
-index 33be73e..9069bd4 100644
---- a/include/linux/pcf506xx.h
-+++ b/include/linux/pcf506xx.h
-@@ -21,6 +21,8 @@ enum pmu_event {
- PMU_EVT_USB_INSERT,
- PMU_EVT_USB_REMOVE,
- #endif
-+ PMU_EVT_CHARGER_ACTIVE,
-+ PMU_EVT_CHARGER_IDLE,
- __NUM_PMU_EVTS
- };
-
---
-1.5.6.3
-