add support for target 3c24xx (more known as Openmoko GTA02 "Freerunner") and merge...
[openwrt.git] / target / linux / s3c24xx / patches / 0159-fix-pcf50633-suspend-resume-onehit-i2c-other-meddlin.patch
1 From 286581f7a1cd2536b70cc0cfbc742ee45260252e Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Fri, 25 Jul 2008 23:06:12 +0100
4 Subject: [PATCH] fix-pcf50633-suspend-resume-onehit-i2c-other-meddling.patch
5
6  - speed up suspend and resume by using one hit i2c bulk transactions
7  - don't bother storing int mask set on suspend, the default one is
8    what we use anyway
9  - put stack_trace() on pcf50633 low level access that fire if we
10    try to touch them before we resumed
11  - cosmetic source cleanup
12  - reduces resume time for pcf50633 from 450ms to 255ms
13
14 Signed-off-by: Andy Green <andy@openmoko.com>
15 ---
16  arch/arm/mach-s3c2440/mach-gta02.c |   21 ++-------
17  drivers/i2c/chips/pcf50633.c       |   83 +++++++++++++++++++----------------
18  2 files changed, 49 insertions(+), 55 deletions(-)
19
20 diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
21 index 9ba1036..22de181 100644
22 --- a/arch/arm/mach-s3c2440/mach-gta02.c
23 +++ b/arch/arm/mach-s3c2440/mach-gta02.c
24 @@ -477,24 +477,11 @@ static struct pcf50633_platform_data gta02_pcf_pdata = {
25         .r_fix_batt_par = 10000,
26         .r_sense_milli  = 220,
27         .resumers = {
28 -               [0] = /* PCF50633_INT1_ADPINS   | */
29 -                 /* PCF50633_INT1_ADPREM       | */
30 -                 PCF50633_INT1_USBINS          |
31 -                 PCF50633_INT1_USBREM          |
32 -                 PCF50633_INT1_ALARM,
33 +               [0] = PCF50633_INT1_USBINS |
34 +                     PCF50633_INT1_USBREM |
35 +                     PCF50633_INT1_ALARM,
36                 [1] = PCF50633_INT2_ONKEYF,
37 -               [2] =  /* PCF50633_INT3_BATFULL | */
38 -                 /* PCF50633_INT3_CHGHALT      | */
39 -                 /* PCF50633_INT3_THLIMON      | */
40 -                 /* PCF50633_INT3_THLIMOFF     | */
41 -                 /* PCF50633_INT3_USBLIMON     | */
42 -                 /* PCF50633_INT3_USBLIMOFF    | */
43 -                 PCF50633_INT3_ONKEY1S ,
44 -               [3] = 0                         /* |
45 -                    PCF50633_INT4_LOWSYS       | */
46 -                 /* PCF50633_INT4_LOWBAT       | */
47 -                 /* PCF50633_INT4_HIGHTMP */,
48 -               [4] = 0
49 +               [2] = PCF50633_INT3_ONKEY1S
50         },
51         .rails  = {
52                 [PCF50633_REGULATOR_AUTO] = {
53 diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
54 index f6886d7..c148ea7 100644
55 --- a/drivers/i2c/chips/pcf50633.c
56 +++ b/drivers/i2c/chips/pcf50633.c
57 @@ -163,10 +163,7 @@ struct pcf50633_data {
58                 u_int8_t down2out, down2ena;
59                 u_int8_t memldoout, memldoena;
60                 u_int8_t ledout, ledena, leddim;
61 -               struct {
62 -                       u_int8_t out;
63 -                       u_int8_t ena;
64 -               } ldo[__NUM_PCF50633_REGS];
65 +               u_int8_t ldo[__NUM_PCF50633_REGS][2];
66         } standby_regs;
67  
68         struct resume_dependency resume_dependency;
69 @@ -187,6 +184,10 @@ static struct platform_device *pcf50633_pdev;
70  
71  static int __reg_write(struct pcf50633_data *pcf, u_int8_t reg, u_int8_t val)
72  {
73 +       if (pcf->have_been_suspended == 1) {
74 +               dev_err(&pcf->client.dev, "__reg_write while suspended\n");
75 +               dump_stack();
76 +       }
77         return i2c_smbus_write_byte_data(&pcf->client, reg, val);
78  }
79  
80 @@ -205,6 +206,10 @@ static int32_t __reg_read(struct pcf50633_data *pcf, u_int8_t reg)
81  {
82         int32_t ret;
83  
84 +       if (pcf->have_been_suspended == 1) {
85 +               dev_err(&pcf->client.dev, "__reg_read while suspended\n");
86 +               dump_stack();
87 +       }
88         ret = i2c_smbus_read_byte_data(&pcf->client, reg);
89  
90         return ret;
91 @@ -2155,6 +2160,13 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
92         struct i2c_client *client = to_i2c_client(dev);
93         struct pcf50633_data *pcf = i2c_get_clientdata(client);
94         int i;
95 +       int ret;
96 +       u_int8_t tmp;
97 +
98 +       /* we suspend once (!) as late as possible in the suspend sequencing */
99 +
100 +       if ((state.event != PM_EVENT_SUSPEND) || (pcf->have_been_suspended))
101 +               return 0;
102  
103         /* The general idea is to power down all unused power supplies,
104          * and then mask all PCF50606 interrup sources but EXTONR, ONKEYF
105 @@ -2176,25 +2188,25 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
106         pcf->standby_regs.ledout = __reg_read(pcf, PCF50633_REG_LEDOUT);
107         pcf->standby_regs.ledena = __reg_read(pcf, PCF50633_REG_LEDENA);
108         pcf->standby_regs.leddim = __reg_read(pcf, PCF50633_REG_LEDDIM);
109 -       /* FIXME: one big read? */
110 -       for (i = 0; i < 7; i++) {
111 -               u_int8_t reg_out = PCF50633_REG_LDO1OUT + 2*i;
112 -               pcf->standby_regs.ldo[i].out = __reg_read(pcf, reg_out);
113 -               pcf->standby_regs.ldo[i].ena = __reg_read(pcf, reg_out+1);
114 -       }
115 +
116 +       /* regulator voltages and enable states */
117 +       ret = i2c_smbus_read_i2c_block_data(&pcf->client,
118 +                                           PCF50633_REG_LDO1OUT, 14,
119 +                                           &pcf->standby_regs.ldo[0][0]);
120 +       if (ret != 14)
121 +               dev_err(dev, "Failed to save LDO levels and enables :-(\n");
122  
123         /* switch off power supplies that are not needed during suspend */
124         for (i = 0; i < __NUM_PCF50633_REGULATORS; i++) {
125 -               if (!(pcf->pdata->rails[i].flags & PMU_VRAIL_F_SUSPEND_ON)) {
126 -                       u_int8_t tmp;
127 -
128 -                       DEBUGP("disabling pcf50633 regulator %u\n", i);
129 -                       /* we cannot use pcf50633_onoff_set() because we're
130 -                        * already under the mutex */
131 -                       tmp = __reg_read(pcf, regulator_registers[i]+1);
132 -                       tmp &= 0xfe;
133 -                       __reg_write(pcf, regulator_registers[i]+1, tmp);
134 -               }
135 +               if ((pcf->pdata->rails[i].flags & PMU_VRAIL_F_SUSPEND_ON))
136 +                       continue;
137 +
138 +               dev_dbg(dev, "disabling regulator %u\n", i);
139 +               /* we cannot use pcf50633_onoff_set() because we're
140 +                * already under the mutex */
141 +               tmp = __reg_read(pcf, regulator_registers[i]+1);
142 +               tmp &= 0xfe;
143 +               __reg_write(pcf, regulator_registers[i]+1, tmp);
144         }
145  
146         /* turn off the backlight */
147 @@ -2202,11 +2214,9 @@ static int pcf50633_suspend(struct device *dev, pm_message_t state)
148         __reg_write(pcf, PCF50633_REG_LEDOUT, 2);
149         __reg_write(pcf, PCF50633_REG_LEDENA, 0x00);
150  
151 -       pcf->standby_regs.int1m = __reg_read(pcf, PCF50633_REG_INT1M);
152 -       pcf->standby_regs.int2m = __reg_read(pcf, PCF50633_REG_INT2M);
153 -       pcf->standby_regs.int3m = __reg_read(pcf, PCF50633_REG_INT3M);
154 -       pcf->standby_regs.int4m = __reg_read(pcf, PCF50633_REG_INT4M);
155 -       pcf->standby_regs.int5m = __reg_read(pcf, PCF50633_REG_INT5M);
156 +       /* set interrupt masks so only those sources we want to wake
157 +        * us are able to
158 +        */
159         __reg_write(pcf, PCF50633_REG_INT1M, ~pcf->pdata->resumers[0]);
160         __reg_write(pcf, PCF50633_REG_INT2M, ~pcf->pdata->resumers[1]);
161         __reg_write(pcf, PCF50633_REG_INT3M, ~pcf->pdata->resumers[2]);
162 @@ -2240,16 +2250,13 @@ static int pcf50633_resume(struct device *dev)
163  {
164         struct i2c_client *client = to_i2c_client(dev);
165         struct pcf50633_data *pcf = i2c_get_clientdata(client);
166 -       int i;
167 +       int ret;
168  
169         mutex_lock(&pcf->lock);
170  
171 -       /* Resume all saved registers that don't "survive" standby state */
172 -       __reg_write(pcf, PCF50633_REG_INT1M, pcf->standby_regs.int1m);
173 -       __reg_write(pcf, PCF50633_REG_INT2M, pcf->standby_regs.int2m);
174 -       __reg_write(pcf, PCF50633_REG_INT3M, pcf->standby_regs.int3m);
175 -       __reg_write(pcf, PCF50633_REG_INT4M, pcf->standby_regs.int4m);
176 -       __reg_write(pcf, PCF50633_REG_INT5M, pcf->standby_regs.int5m);
177 +       pcf->have_been_suspended = 2; /* resuming */
178 +
179 +       /* these guys get reset while pcf50633 is suspend state, refresh */
180  
181         __reg_write(pcf, PCF50633_REG_OOCTIM2, pcf->standby_regs.ooctim2);
182         __reg_write(pcf, PCF50633_REG_AUTOOUT, pcf->standby_regs.autoout);
183 @@ -2265,12 +2272,12 @@ static int pcf50633_resume(struct device *dev)
184         if (!pcf->pdata->defer_resume_backlight)
185                 pcf50633_backlight_resume(pcf);
186  
187 -       /* FIXME: one big read? */
188 -       for (i = 0; i < 7; i++) {
189 -               u_int8_t reg_out = PCF50633_REG_LDO1OUT + 2*i;
190 -               __reg_write(pcf, reg_out, pcf->standby_regs.ldo[i].out);
191 -               __reg_write(pcf, reg_out+1, pcf->standby_regs.ldo[i].ena);
192 -       }
193 +       /* regulator voltages and enable states */
194 +       ret = i2c_smbus_write_i2c_block_data(&pcf->client,
195 +                                           PCF50633_REG_LDO1OUT, 14,
196 +                                           &pcf->standby_regs.ldo[0][0]);
197 +       if (ret)
198 +               dev_err(dev, "Failed to restore LDOs :-( %d\n", ret);
199  
200         mutex_unlock(&pcf->lock);
201  
202 -- 
203 1.5.6.3
204