diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.24/1170-introduce-charging-led-behaviour.patch.patch')
-rw-r--r-- | target/linux/s3c24xx/patches-2.6.24/1170-introduce-charging-led-behaviour.patch.patch | 423 |
1 files changed, 0 insertions, 423 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.24/1170-introduce-charging-led-behaviour.patch.patch b/target/linux/s3c24xx/patches-2.6.24/1170-introduce-charging-led-behaviour.patch.patch deleted file mode 100644 index c2833bdb23..0000000000 --- a/target/linux/s3c24xx/patches-2.6.24/1170-introduce-charging-led-behaviour.patch.patch +++ /dev/null @@ -1,423 +0,0 @@ -From bf74b8891e80dfceb72002f12c7d3c9978631dc0 Mon Sep 17 00:00:00 2001 -From: Andy Green <andy@openmoko.com> -Date: Wed, 2 Jul 2008 22:37:47 +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 2878baa..2ed6dc0 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); -@@ -760,6 +844,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) { -@@ -797,8 +908,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); -@@ -830,8 +940,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 */ -@@ -1064,10 +1203,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) -@@ -1075,8 +1217,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); - -@@ -1106,16 +1280,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); -@@ -1712,7 +1906,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.5 - |