diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.24/1179-fix-pcf50633-suspend-resume-onehit-i2c-other-meddlin.patch')
-rw-r--r-- | target/linux/s3c24xx/patches-2.6.24/1179-fix-pcf50633-suspend-resume-onehit-i2c-other-meddlin.patch | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.24/1179-fix-pcf50633-suspend-resume-onehit-i2c-other-meddlin.patch b/target/linux/s3c24xx/patches-2.6.24/1179-fix-pcf50633-suspend-resume-onehit-i2c-other-meddlin.patch new file mode 100644 index 0000000..b9b718b --- /dev/null +++ b/target/linux/s3c24xx/patches-2.6.24/1179-fix-pcf50633-suspend-resume-onehit-i2c-other-meddlin.patch @@ -0,0 +1,204 @@ +From 83636af17dab41d313411543c57984b5834cfcf2 Mon Sep 17 00:00:00 2001 +From: Andy Green <andy@openmoko.com> +Date: Wed, 2 Jul 2008 22:39:10 +0100 +Subject: [PATCH] fix-pcf50633-suspend-resume-onehit-i2c-other-meddling.patch + + - speed up suspend and resume by using one hit i2c bulk transactions + - don't bother storing int mask set on suspend, the default one is + what we use anyway + - put stack_trace() on pcf50633 low level access that fire if we + try to touch them before we resumed + - cosmetic source cleanup + - reduces resume time for pcf50633 from 450ms to 255ms + +Signed-off-by: Andy Green <andy@openmoko.com> +--- + arch/arm/mach-s3c2440/mach-gta02.c | 21 ++------- + drivers/i2c/chips/pcf50633.c | 83 +++++++++++++++++++---------------- + 2 files changed, 49 insertions(+), 55 deletions(-) + +diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c +index 9ba1036..22de181 100644 +--- a/arch/arm/mach-s3c2440/mach-gta02.c ++++ b/arch/arm/mach-s3c2440/mach-gta02.c +@@ -477,24 +477,11 @@ static struct pcf50633_platform_data gta02_pcf_pdata = { + .r_fix_batt_par = 10000, + .r_sense_milli = 220, + .resumers = { +- [0] = /* PCF50633_INT1_ADPINS | */ +- /* PCF50633_INT1_ADPREM | */ +- PCF50633_INT1_USBINS | +- PCF50633_INT1_USBREM | +- PCF50633_INT1_ALARM, ++ [0] = PCF50633_INT1_USBINS | ++ PCF50633_INT1_USBREM | ++ PCF50633_INT1_ALARM, + [1] = PCF50633_INT2_ONKEYF, +- [2] = /* PCF50633_INT3_BATFULL | */ +- /* PCF50633_INT3_CHGHALT | */ +- /* PCF50633_INT3_THLIMON | */ +- /* PCF50633_INT3_THLIMOFF | */ +- /* PCF50633_INT3_USBLIMON | */ +- /* PCF50633_INT3_USBLIMOFF | */ +- PCF50633_INT3_ONKEY1S , +- [3] = 0 /* | +- PCF50633_INT4_LOWSYS | */ +- /* PCF50633_INT4_LOWBAT | */ +- /* PCF50633_INT4_HIGHTMP */, +- [4] = 0 ++ [2] = PCF50633_INT3_ONKEY1S + }, + .rails = { + [PCF50633_REGULATOR_AUTO] = { +diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c +index aabf412..8cb6156 100644 +--- a/drivers/i2c/chips/pcf50633.c ++++ b/drivers/i2c/chips/pcf50633.c +@@ -163,10 +163,7 @@ struct pcf50633_data { + u_int8_t down2out, down2ena; + u_int8_t memldoout, memldoena; + u_int8_t ledout, ledena, leddim; +- struct { +- u_int8_t out; +- u_int8_t ena; +- } ldo[__NUM_PCF50633_REGS]; ++ u_int8_t ldo[__NUM_PCF50633_REGS][2]; + } standby_regs; + + struct resume_dependency resume_dependency; +@@ -187,6 +184,10 @@ static struct platform_device *pcf50633_pdev; + + static int __reg_write(struct pcf50633_data *pcf, u_int8_t reg, u_int8_t val) + { ++ if (pcf->have_been_suspended == 1) { ++ dev_err(&pcf->client.dev, "__reg_write while suspended\n"); ++ dump_stack(); ++ } + return i2c_smbus_write_byte_data(&pcf->client, reg, val); + } + +@@ -205,6 +206,10 @@ static int32_t __reg_read(struct pcf50633_data *pcf, u_int8_t reg) + { + int32_t ret; + ++ if (pcf->have_been_suspended == 1) { ++ dev_err(&pcf->client.dev, "__reg_read while suspended\n"); ++ dump_stack(); ++ } + ret = i2c_smbus_read_byte_data(&pcf->client, reg); + + return ret; +@@ -2165,6 +2170,13 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) + struct i2c_client *client = to_i2c_client(dev); + struct pcf50633_data *pcf = i2c_get_clientdata(client); + int i; ++ int ret; ++ u_int8_t tmp; ++ ++ /* we suspend once (!) as late as possible in the suspend sequencing */ ++ ++ if ((state.event != PM_EVENT_SUSPEND) || (pcf->have_been_suspended)) ++ return 0; + + /* The general idea is to power down all unused power supplies, + * and then mask all PCF50606 interrup sources but EXTONR, ONKEYF +@@ -2186,25 +2198,25 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) + pcf->standby_regs.ledout = __reg_read(pcf, PCF50633_REG_LEDOUT); + pcf->standby_regs.ledena = __reg_read(pcf, PCF50633_REG_LEDENA); + pcf->standby_regs.leddim = __reg_read(pcf, PCF50633_REG_LEDDIM); +- /* FIXME: one big read? */ +- for (i = 0; i < 7; i++) { +- u_int8_t reg_out = PCF50633_REG_LDO1OUT + 2*i; +- pcf->standby_regs.ldo[i].out = __reg_read(pcf, reg_out); +- pcf->standby_regs.ldo[i].ena = __reg_read(pcf, reg_out+1); +- } ++ ++ /* regulator voltages and enable states */ ++ ret = i2c_smbus_read_i2c_block_data(&pcf->client, ++ PCF50633_REG_LDO1OUT, 14, ++ &pcf->standby_regs.ldo[0][0]); ++ if (ret != 14) ++ dev_err(dev, "Failed to save LDO levels and enables :-(\n"); + + /* switch off power supplies that are not needed during suspend */ + for (i = 0; i < __NUM_PCF50633_REGULATORS; i++) { +- if (!(pcf->pdata->rails[i].flags & PMU_VRAIL_F_SUSPEND_ON)) { +- u_int8_t tmp; +- +- DEBUGP("disabling pcf50633 regulator %u\n", i); +- /* we cannot use pcf50633_onoff_set() because we're +- * already under the mutex */ +- tmp = __reg_read(pcf, regulator_registers[i]+1); +- tmp &= 0xfe; +- __reg_write(pcf, regulator_registers[i]+1, tmp); +- } ++ if ((pcf->pdata->rails[i].flags & PMU_VRAIL_F_SUSPEND_ON)) ++ continue; ++ ++ dev_dbg(dev, "disabling regulator %u\n", i); ++ /* we cannot use pcf50633_onoff_set() because we're ++ * already under the mutex */ ++ tmp = __reg_read(pcf, regulator_registers[i]+1); ++ tmp &= 0xfe; ++ __reg_write(pcf, regulator_registers[i]+1, tmp); + } + + /* turn off the backlight */ +@@ -2212,11 +2224,9 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) + __reg_write(pcf, PCF50633_REG_LEDOUT, 2); + __reg_write(pcf, PCF50633_REG_LEDENA, 0x00); + +- pcf->standby_regs.int1m = __reg_read(pcf, PCF50633_REG_INT1M); +- pcf->standby_regs.int2m = __reg_read(pcf, PCF50633_REG_INT2M); +- pcf->standby_regs.int3m = __reg_read(pcf, PCF50633_REG_INT3M); +- pcf->standby_regs.int4m = __reg_read(pcf, PCF50633_REG_INT4M); +- pcf->standby_regs.int5m = __reg_read(pcf, PCF50633_REG_INT5M); ++ /* set interrupt masks so only those sources we want to wake ++ * us are able to ++ */ + __reg_write(pcf, PCF50633_REG_INT1M, ~pcf->pdata->resumers[0]); + __reg_write(pcf, PCF50633_REG_INT2M, ~pcf->pdata->resumers[1]); + __reg_write(pcf, PCF50633_REG_INT3M, ~pcf->pdata->resumers[2]); +@@ -2250,16 +2260,13 @@ static int pcf50633_resume(struct device *dev) + { + struct i2c_client *client = to_i2c_client(dev); + struct pcf50633_data *pcf = i2c_get_clientdata(client); +- int i; ++ int ret; + + mutex_lock(&pcf->lock); + +- /* Resume all saved registers that don't "survive" standby state */ +- __reg_write(pcf, PCF50633_REG_INT1M, pcf->standby_regs.int1m); +- __reg_write(pcf, PCF50633_REG_INT2M, pcf->standby_regs.int2m); +- __reg_write(pcf, PCF50633_REG_INT3M, pcf->standby_regs.int3m); +- __reg_write(pcf, PCF50633_REG_INT4M, pcf->standby_regs.int4m); +- __reg_write(pcf, PCF50633_REG_INT5M, pcf->standby_regs.int5m); ++ pcf->have_been_suspended = 2; /* resuming */ ++ ++ /* these guys get reset while pcf50633 is suspend state, refresh */ + + __reg_write(pcf, PCF50633_REG_OOCTIM2, pcf->standby_regs.ooctim2); + __reg_write(pcf, PCF50633_REG_AUTOOUT, pcf->standby_regs.autoout); +@@ -2275,12 +2282,12 @@ static int pcf50633_resume(struct device *dev) + if (!pcf->pdata->defer_resume_backlight) + pcf50633_backlight_resume(pcf); + +- /* FIXME: one big read? */ +- for (i = 0; i < 7; i++) { +- u_int8_t reg_out = PCF50633_REG_LDO1OUT + 2*i; +- __reg_write(pcf, reg_out, pcf->standby_regs.ldo[i].out); +- __reg_write(pcf, reg_out+1, pcf->standby_regs.ldo[i].ena); +- } ++ /* regulator voltages and enable states */ ++ ret = i2c_smbus_write_i2c_block_data(&pcf->client, ++ PCF50633_REG_LDO1OUT, 14, ++ &pcf->standby_regs.ldo[0][0]); ++ if (ret) ++ dev_err(dev, "Failed to restore LDOs :-( %d\n", ret); + + mutex_unlock(&pcf->lock); + +-- +1.5.6.5 + |