From 8a2d04c222684e3278dd28d11f57a05fe0865183 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Wed, 2 Jul 2008 22:40:12 +0100 Subject: [PATCH] fix-pcf50633-use-i2c-bulk-autoincrement.patch Simplify and speed up bulk sequential I2C actions in pcf50633 the time savings are pretty considerable and so is the simplification Signed-off-by: Andy Green --- drivers/i2c/chips/pcf50633.c | 117 +++++++++++++++++++++++++----------------- 1 files changed, 70 insertions(+), 47 deletions(-) diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c index 1f88c32..96857a3 100644 --- a/drivers/i2c/chips/pcf50633.c +++ b/drivers/i2c/chips/pcf50633.c @@ -156,14 +156,14 @@ struct pcf50633_data { #ifdef CONFIG_PM struct { - u_int8_t int1m, int2m, int3m, int4m, int5m; u_int8_t ooctim2; - u_int8_t autoout, autoena, automxc; - u_int8_t down1out, down1mxc; - u_int8_t down2out, down2ena; - u_int8_t memldoout, memldoena; - u_int8_t ledout, ledena, leddim; - u_int8_t ldo[__NUM_PCF50633_REGS][2]; + /* enables are always [1] below + * I2C has limit of 32 sequential regs, so done in two lumps + * because it covers 33 register extent otherwise + */ + u_int8_t misc[PCF50633_REG_LEDDIM - PCF50633_REG_AUTOOUT + 1]; + /* skip 1 reserved reg here */ + u_int8_t ldo[PCF50633_REG_HCLDOENA - PCF50633_REG_LDO1OUT + 1]; } standby_regs; struct resume_dependency resume_dependency; @@ -1737,6 +1737,8 @@ static int pcf50633bl_set_intensity(struct backlight_device *bd) int old_intensity = reg_read(pcf, PCF50633_REG_LEDOUT); int ret; + dev_info(&pcf->client.dev, "pcf50633bl_set_intensity\n"); + if (!(reg_read(pcf, PCF50633_REG_LEDENA) & 1)) old_intensity = 0; @@ -2221,6 +2223,9 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) int i; int ret; u_int8_t tmp; + u_int8_t res[5]; + + dev_err(dev, "pcf50633_suspend\n"); /* we suspend once (!) as late as possible in the suspend sequencing */ @@ -2228,30 +2233,26 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) return 0; /* The general idea is to power down all unused power supplies, - * and then mask all PCF50606 interrup sources but EXTONR, ONKEYF + * and then mask all PCF50633 interrupt sources but EXTONR, ONKEYF * and ALARM */ mutex_lock(&pcf->lock); /* Save all registers that don't "survive" standby state */ pcf->standby_regs.ooctim2 = __reg_read(pcf, PCF50633_REG_OOCTIM2); - pcf->standby_regs.autoout = __reg_read(pcf, PCF50633_REG_AUTOOUT); - pcf->standby_regs.autoena = __reg_read(pcf, PCF50633_REG_AUTOENA); - pcf->standby_regs.automxc = __reg_read(pcf, PCF50633_REG_AUTOMXC); - pcf->standby_regs.down1out = __reg_read(pcf, PCF50633_REG_DOWN1OUT); - pcf->standby_regs.down1mxc = __reg_read(pcf, PCF50633_REG_DOWN1MXC); - pcf->standby_regs.down2out = __reg_read(pcf, PCF50633_REG_DOWN2OUT); - pcf->standby_regs.down2ena = __reg_read(pcf, PCF50633_REG_DOWN2ENA); - pcf->standby_regs.memldoout = __reg_read(pcf, PCF50633_REG_MEMLDOOUT); - pcf->standby_regs.memldoena = __reg_read(pcf, PCF50633_REG_MEMLDOENA); - 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); + + ret = i2c_smbus_read_i2c_block_data(&pcf->client, + PCF50633_REG_AUTOOUT, + sizeof(pcf->standby_regs.misc), + &pcf->standby_regs.misc[0]); + if (ret != 18) + dev_err(dev, "Failed to save misc levels and enables :-(\n"); /* regulator voltages and enable states */ ret = i2c_smbus_read_i2c_block_data(&pcf->client, - PCF50633_REG_LDO1OUT, 14, - &pcf->standby_regs.ldo[0][0]); + PCF50633_REG_LDO1OUT, + sizeof(pcf->standby_regs.ldo), + &pcf->standby_regs.ldo[0]); if (ret != 14) dev_err(dev, "Failed to save LDO levels and enables :-(\n"); @@ -2261,11 +2262,16 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) 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); + + /* we can save ourselves the read part of a read-modify-write + * here because we captured all these already + */ + if (i < 4) + tmp = pcf->standby_regs.misc[i * 4 + 1]; + else + tmp = pcf->standby_regs.ldo[(i - 4) * 2 + 1]; + + __reg_write(pcf, regulator_registers[i] + 1, tmp & 0xfe); } /* turn off the backlight */ @@ -2276,11 +2282,14 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state) /* 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]); - __reg_write(pcf, PCF50633_REG_INT4M, ~pcf->pdata->resumers[3]); - __reg_write(pcf, PCF50633_REG_INT5M, ~pcf->pdata->resumers[4]); + for (i = 0; i < 5; i++) + res[i] = ~pcf->pdata->resumers[i]; + + ret = i2c_smbus_write_i2c_block_data(&pcf->client, + PCF50633_REG_INT1M, + 5, &res[0]); + if (ret) + dev_err(dev, "Failed to set wake masks :-( %d\n", ret); pcf->have_been_suspended = 1; @@ -2312,9 +2321,12 @@ EXPORT_SYMBOL_GPL(pcf50633_ready); void pcf50633_backlight_resume(struct pcf50633_data *pcf) { /* we force the backlight on in fact */ - __reg_write(pcf, PCF50633_REG_LEDOUT, pcf->standby_regs.ledout); - __reg_write(pcf, PCF50633_REG_LEDENA, pcf->standby_regs.ledena | 0x01); - __reg_write(pcf, PCF50633_REG_LEDDIM, pcf->standby_regs.leddim); + __reg_write(pcf, PCF50633_REG_LEDOUT, pcf->standby_regs.misc[ + PCF50633_REG_LEDOUT - PCF50633_REG_AUTOOUT]); + __reg_write(pcf, PCF50633_REG_LEDENA, pcf->standby_regs.misc[ + PCF50633_REG_LEDENA - PCF50633_REG_AUTOOUT] | 1); + __reg_write(pcf, PCF50633_REG_LEDDIM, pcf->standby_regs.misc[ + PCF50633_REG_LEDDIM - PCF50633_REG_AUTOOUT]); } EXPORT_SYMBOL_GPL(pcf50633_backlight_resume); @@ -2324,7 +2336,10 @@ static int pcf50633_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct pcf50633_data *pcf = i2c_get_clientdata(client); int ret; + u8 res[5]; + dev_info(dev, "pcf50633_resume suspended on entry = %d\n", + pcf->have_been_suspended); mutex_lock(&pcf->lock); pcf->have_been_suspended = 2; /* resuming */ @@ -2332,14 +2347,14 @@ static int pcf50633_resume(struct device *dev) /* 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); - __reg_write(pcf, PCF50633_REG_AUTOMXC, pcf->standby_regs.automxc); - __reg_write(pcf, PCF50633_REG_DOWN1OUT, pcf->standby_regs.down1out); - __reg_write(pcf, PCF50633_REG_DOWN1MXC, pcf->standby_regs.down1mxc); - __reg_write(pcf, PCF50633_REG_DOWN2OUT, pcf->standby_regs.down2out); - __reg_write(pcf, PCF50633_REG_DOWN2ENA, pcf->standby_regs.down2ena); - __reg_write(pcf, PCF50633_REG_MEMLDOOUT, pcf->standby_regs.memldoout); - __reg_write(pcf, PCF50633_REG_MEMLDOENA, pcf->standby_regs.memldoena); + + /* regulator voltages and enable states */ + ret = i2c_smbus_write_i2c_block_data(&pcf->client, + PCF50633_REG_AUTOOUT, + sizeof(pcf->standby_regs.misc) - 4, + &pcf->standby_regs.misc[0]); + if (ret) + dev_err(dev, "Failed to restore misc :-( %d\n", ret); /* platform can choose to defer backlight bringup */ if (!pcf->pdata->defer_resume_backlight) @@ -2347,14 +2362,22 @@ static int pcf50633_resume(struct device *dev) /* regulator voltages and enable states */ ret = i2c_smbus_write_i2c_block_data(&pcf->client, - PCF50633_REG_LDO1OUT, 14, - &pcf->standby_regs.ldo[0][0]); + PCF50633_REG_LDO1OUT, + sizeof(pcf->standby_regs.ldo), + &pcf->standby_regs.ldo[0]); if (ret) dev_err(dev, "Failed to restore LDOs :-( %d\n", ret); - mutex_unlock(&pcf->lock); + memset(res, 0, sizeof(res)); + ret = i2c_smbus_write_i2c_block_data(&pcf->client, + PCF50633_REG_INT1M, + 5, &res[0]); + if (ret) + dev_err(dev, "Failed to set int masks :-( %d\n", ret); - pcf50633_irq(pcf->irq, pcf); + pcf->have_been_suspended = 3; /* resume completed */ + + mutex_unlock(&pcf->lock); callback_all_resume_dependencies(&pcf->resume_dependency); -- 1.5.6.5