mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 10:39:04 +00:00
231 lines
8.7 KiB
Diff
231 lines
8.7 KiB
Diff
|
From cc770a67d483a63e98be55c15f08d97ed5599230 Mon Sep 17 00:00:00 2001
|
||
|
From: Andy Green <andy@openmoko.com>
|
||
|
Date: Fri, 25 Jul 2008 23:06: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 <andy@openmoko.com>
|
||
|
---
|
||
|
drivers/i2c/chips/pcf50633.c | 125 +++++++++++++++++++++++++-----------------
|
||
|
1 files changed, 75 insertions(+), 50 deletions(-)
|
||
|
|
||
|
diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
|
||
|
index 0406767..645cbbb 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;
|
||
|
@@ -1734,9 +1734,13 @@ static int pcf50633bl_set_intensity(struct backlight_device *bd)
|
||
|
u_int8_t ledena = 2;
|
||
|
int ret;
|
||
|
|
||
|
- if (bd->props.power != FB_BLANK_UNBLANK)
|
||
|
- intensity = 0;
|
||
|
- if (bd->props.fb_blank != FB_BLANK_UNBLANK)
|
||
|
+ dev_info(&pcf->client.dev, "pcf50633bl_set_intensity\n");
|
||
|
+
|
||
|
+ if (!(reg_read(pcf, PCF50633_REG_LEDENA) & 1))
|
||
|
+ old_intensity = 0;
|
||
|
+
|
||
|
+ if ((bd->props.power != FB_BLANK_UNBLANK) ||
|
||
|
+ (bd->props.fb_blank != FB_BLANK_UNBLANK))
|
||
|
intensity = 0;
|
||
|
|
||
|
/* The PCF50633 cannot handle LEDOUT = 0 (datasheet p60)
|
||
|
@@ -2211,6 +2215,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 */
|
||
|
|
||
|
@@ -2218,30 +2225,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");
|
||
|
|
||
|
@@ -2251,11 +2254,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 */
|
||
|
@@ -2266,11 +2274,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;
|
||
|
|
||
|
@@ -2302,9 +2313,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);
|
||
|
|
||
|
@@ -2314,7 +2328,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 */
|
||
|
@@ -2322,14 +2339,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)
|
||
|
@@ -2337,14 +2354,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.3
|
||
|
|