2c38ac17ab648395b022ed667e29e77d7b81d757
[safe/jmp/linux-2.6] / drivers / mfd / twl4030-power.c
1 /*
2  * linux/drivers/i2c/chips/twl4030-power.c
3  *
4  * Handle TWL4030 Power initialization
5  *
6  * Copyright (C) 2008 Nokia Corporation
7  * Copyright (C) 2006 Texas Instruments, Inc
8  *
9  * Written by   Kalle Jokiniemi
10  *              Peter De Schrijver <peter.de-schrijver@nokia.com>
11  * Several fixes by Amit Kucheria <amit.kucheria@verdurent.com>
12  *
13  * This file is subject to the terms and conditions of the GNU General
14  * Public License. See the file "COPYING" in the main directory of this
15  * archive for more details.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include <linux/module.h>
28 #include <linux/pm.h>
29 #include <linux/i2c/twl4030.h>
30 #include <linux/platform_device.h>
31
32 #include <asm/mach-types.h>
33
34 static u8 twl4030_start_script_address = 0x2b;
35
36 #define PWR_P1_SW_EVENTS        0x10
37 #define PWR_DEVOFF      (1<<0)
38
39 #define PHY_TO_OFF_PM_MASTER(p)         (p - 0x36)
40 #define PHY_TO_OFF_PM_RECEIVER(p)       (p - 0x5b)
41
42 /* resource - hfclk */
43 #define R_HFCLKOUT_DEV_GRP      PHY_TO_OFF_PM_RECEIVER(0xe6)
44
45 /* PM events */
46 #define R_P1_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x46)
47 #define R_P2_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x47)
48 #define R_P3_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x48)
49 #define R_CFG_P1_TRANSITION     PHY_TO_OFF_PM_MASTER(0x36)
50 #define R_CFG_P2_TRANSITION     PHY_TO_OFF_PM_MASTER(0x37)
51 #define R_CFG_P3_TRANSITION     PHY_TO_OFF_PM_MASTER(0x38)
52
53 #define LVL_WAKEUP      0x08
54
55 #define ENABLE_WARMRESET (1<<4)
56
57 #define END_OF_SCRIPT           0x3f
58
59 #define R_SEQ_ADD_A2S           PHY_TO_OFF_PM_MASTER(0x55)
60 #define R_SEQ_ADD_S2A12         PHY_TO_OFF_PM_MASTER(0x56)
61 #define R_SEQ_ADD_S2A3          PHY_TO_OFF_PM_MASTER(0x57)
62 #define R_SEQ_ADD_WARM          PHY_TO_OFF_PM_MASTER(0x58)
63 #define R_MEMORY_ADDRESS        PHY_TO_OFF_PM_MASTER(0x59)
64 #define R_MEMORY_DATA           PHY_TO_OFF_PM_MASTER(0x5a)
65
66 #define R_PROTECT_KEY           0x0E
67 #define R_KEY_1                 0xC0
68 #define R_KEY_2                 0x0C
69
70 /* resource configuration registers
71    <RESOURCE>_DEV_GRP   at address 'n+0'
72    <RESOURCE>_TYPE      at address 'n+1'
73    <RESOURCE>_REMAP     at address 'n+2'
74    <RESOURCE>_DEDICATED at address 'n+3'
75 */
76 #define DEV_GRP_OFFSET          0
77 #define TYPE_OFFSET             1
78
79 /* Bit positions in the registers */
80
81 /* <RESOURCE>_DEV_GRP */
82 #define DEV_GRP_SHIFT           5
83 #define DEV_GRP_MASK            (7 << DEV_GRP_SHIFT)
84
85 /* <RESOURCE>_TYPE */
86 #define TYPE_SHIFT              0
87 #define TYPE_MASK               (7 << TYPE_SHIFT)
88 #define TYPE2_SHIFT             3
89 #define TYPE2_MASK              (3 << TYPE2_SHIFT)
90
91 static u8 res_config_addrs[] = {
92         [RES_VAUX1]     = 0x17,
93         [RES_VAUX2]     = 0x1b,
94         [RES_VAUX3]     = 0x1f,
95         [RES_VAUX4]     = 0x23,
96         [RES_VMMC1]     = 0x27,
97         [RES_VMMC2]     = 0x2b,
98         [RES_VPLL1]     = 0x2f,
99         [RES_VPLL2]     = 0x33,
100         [RES_VSIM]      = 0x37,
101         [RES_VDAC]      = 0x3b,
102         [RES_VINTANA1]  = 0x3f,
103         [RES_VINTANA2]  = 0x43,
104         [RES_VINTDIG]   = 0x47,
105         [RES_VIO]       = 0x4b,
106         [RES_VDD1]      = 0x55,
107         [RES_VDD2]      = 0x63,
108         [RES_VUSB_1V5]  = 0x71,
109         [RES_VUSB_1V8]  = 0x74,
110         [RES_VUSB_3V1]  = 0x77,
111         [RES_VUSBCP]    = 0x7a,
112         [RES_REGEN]     = 0x7f,
113         [RES_NRES_PWRON] = 0x82,
114         [RES_CLKEN]     = 0x85,
115         [RES_SYSEN]     = 0x88,
116         [RES_HFCLKOUT]  = 0x8b,
117         [RES_32KCLKOUT] = 0x8e,
118         [RES_RESET]     = 0x91,
119         [RES_Main_Ref]  = 0x94,
120 };
121
122 static int __init twl4030_write_script_byte(u8 address, u8 byte)
123 {
124         int err;
125
126         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
127                                 R_MEMORY_ADDRESS);
128         if (err)
129                 goto out;
130         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
131                                 R_MEMORY_DATA);
132 out:
133         return err;
134 }
135
136 static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
137                                            u8 delay, u8 next)
138 {
139         int err;
140
141         address *= 4;
142         err = twl4030_write_script_byte(address++, pmb_message >> 8);
143         if (err)
144                 goto out;
145         err = twl4030_write_script_byte(address++, pmb_message & 0xff);
146         if (err)
147                 goto out;
148         err = twl4030_write_script_byte(address++, delay);
149         if (err)
150                 goto out;
151         err = twl4030_write_script_byte(address++, next);
152 out:
153         return err;
154 }
155
156 static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
157                                        int len)
158 {
159         int err;
160
161         for (; len; len--, address++, script++) {
162                 if (len == 1) {
163                         err = twl4030_write_script_ins(address,
164                                                 script->pmb_message,
165                                                 script->delay,
166                                                 END_OF_SCRIPT);
167                         if (err)
168                                 break;
169                 } else {
170                         err = twl4030_write_script_ins(address,
171                                                 script->pmb_message,
172                                                 script->delay,
173                                                 address + 1);
174                         if (err)
175                                 break;
176                 }
177         }
178         return err;
179 }
180
181 static int __init twl4030_config_wakeup3_sequence(u8 address)
182 {
183         int err;
184         u8 data;
185
186         /* Set SLEEP to ACTIVE SEQ address for P3 */
187         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
188                                 R_SEQ_ADD_S2A3);
189         if (err)
190                 goto out;
191
192         /* P3 LVL_WAKEUP should be on LEVEL */
193         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
194                                 R_P3_SW_EVENTS);
195         if (err)
196                 goto out;
197         data |= LVL_WAKEUP;
198         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
199                                 R_P3_SW_EVENTS);
200 out:
201         if (err)
202                 pr_err("TWL4030 wakeup sequence for P3 config error\n");
203         return err;
204 }
205
206 static int __init twl4030_config_wakeup12_sequence(u8 address)
207 {
208         int err = 0;
209         u8 data;
210
211         /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
212         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
213                                 R_SEQ_ADD_S2A12);
214         if (err)
215                 goto out;
216
217         /* P1/P2 LVL_WAKEUP should be on LEVEL */
218         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
219                                 R_P1_SW_EVENTS);
220         if (err)
221                 goto out;
222
223         data |= LVL_WAKEUP;
224         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
225                                 R_P1_SW_EVENTS);
226         if (err)
227                 goto out;
228
229         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
230                                 R_P2_SW_EVENTS);
231         if (err)
232                 goto out;
233
234         data |= LVL_WAKEUP;
235         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
236                                 R_P2_SW_EVENTS);
237         if (err)
238                 goto out;
239
240         if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
241                 /* Disabling AC charger effect on sleep-active transitions */
242                 err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
243                                         R_CFG_P1_TRANSITION);
244                 if (err)
245                         goto out;
246                 data &= ~(1<<1);
247                 err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
248                                         R_CFG_P1_TRANSITION);
249                 if (err)
250                         goto out;
251         }
252
253 out:
254         if (err)
255                 pr_err("TWL4030 wakeup sequence for P1 and P2" \
256                         "config error\n");
257         return err;
258 }
259
260 static int __init twl4030_config_sleep_sequence(u8 address)
261 {
262         int err;
263
264         /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
265         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
266                                 R_SEQ_ADD_A2S);
267
268         if (err)
269                 pr_err("TWL4030 sleep sequence config error\n");
270
271         return err;
272 }
273
274 static int __init twl4030_config_warmreset_sequence(u8 address)
275 {
276         int err;
277         u8 rd_data;
278
279         /* Set WARM RESET SEQ address for P1 */
280         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
281                                 R_SEQ_ADD_WARM);
282         if (err)
283                 goto out;
284
285         /* P1/P2/P3 enable WARMRESET */
286         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
287                                 R_P1_SW_EVENTS);
288         if (err)
289                 goto out;
290
291         rd_data |= ENABLE_WARMRESET;
292         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
293                                 R_P1_SW_EVENTS);
294         if (err)
295                 goto out;
296
297         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
298                                 R_P2_SW_EVENTS);
299         if (err)
300                 goto out;
301
302         rd_data |= ENABLE_WARMRESET;
303         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
304                                 R_P2_SW_EVENTS);
305         if (err)
306                 goto out;
307
308         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
309                                 R_P3_SW_EVENTS);
310         if (err)
311                 goto out;
312
313         rd_data |= ENABLE_WARMRESET;
314         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
315                                 R_P3_SW_EVENTS);
316 out:
317         if (err)
318                 pr_err("TWL4030 warmreset seq config error\n");
319         return err;
320 }
321
322 static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
323 {
324         int rconfig_addr;
325         int err;
326         u8 type;
327         u8 grp;
328
329         if (rconfig->resource > TOTAL_RESOURCES) {
330                 pr_err("TWL4030 Resource %d does not exist\n",
331                         rconfig->resource);
332                 return -EINVAL;
333         }
334
335         rconfig_addr = res_config_addrs[rconfig->resource];
336
337         /* Set resource group */
338         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
339                                 rconfig_addr + DEV_GRP_OFFSET);
340         if (err) {
341                 pr_err("TWL4030 Resource %d group could not be read\n",
342                         rconfig->resource);
343                 return err;
344         }
345
346         if (rconfig->devgroup >= 0) {
347                 grp &= ~DEV_GRP_MASK;
348                 grp |= rconfig->devgroup << DEV_GRP_SHIFT;
349                 err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
350                                         grp, rconfig_addr + DEV_GRP_OFFSET);
351                 if (err < 0) {
352                         pr_err("TWL4030 failed to program devgroup\n");
353                         return err;
354                 }
355         }
356
357         /* Set resource types */
358         err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
359                                 rconfig_addr + TYPE_OFFSET);
360         if (err < 0) {
361                 pr_err("TWL4030 Resource %d type could not be read\n",
362                         rconfig->resource);
363                 return err;
364         }
365
366         if (rconfig->type >= 0) {
367                 type &= ~TYPE_MASK;
368                 type |= rconfig->type << TYPE_SHIFT;
369         }
370
371         if (rconfig->type2 >= 0) {
372                 type &= ~TYPE2_MASK;
373                 type |= rconfig->type2 << TYPE2_SHIFT;
374         }
375
376         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
377                                 type, rconfig_addr + TYPE_OFFSET);
378         if (err < 0) {
379                 pr_err("TWL4030 failed to program resource type\n");
380                 return err;
381         }
382
383         return 0;
384 }
385
386 static int __init load_twl4030_script(struct twl4030_script *tscript,
387                u8 address)
388 {
389         int err;
390         static int order;
391
392         /* Make sure the script isn't going beyond last valid address (0x3f) */
393         if ((address + tscript->size) > END_OF_SCRIPT) {
394                 pr_err("TWL4030 scripts too big error\n");
395                 return -EINVAL;
396         }
397
398         err = twl4030_write_script(address, tscript->script, tscript->size);
399         if (err)
400                 goto out;
401
402         if (tscript->flags & TWL4030_WRST_SCRIPT) {
403                 err = twl4030_config_warmreset_sequence(address);
404                 if (err)
405                         goto out;
406         }
407         if (tscript->flags & TWL4030_WAKEUP12_SCRIPT) {
408                 err = twl4030_config_wakeup12_sequence(address);
409                 if (err)
410                         goto out;
411                 order = 1;
412         }
413         if (tscript->flags & TWL4030_WAKEUP3_SCRIPT) {
414                 err = twl4030_config_wakeup3_sequence(address);
415                 if (err)
416                         goto out;
417         }
418         if (tscript->flags & TWL4030_SLEEP_SCRIPT)
419                 if (order)
420                         pr_warning("TWL4030: Bad order of scripts (sleep "\
421                                         "script before wakeup) Leads to boot"\
422                                         "failure on some boards\n");
423                 err = twl4030_config_sleep_sequence(address);
424 out:
425         return err;
426 }
427
428 void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
429 {
430         int err = 0;
431         int i;
432         struct twl4030_resconfig *resconfig;
433         u8 address = twl4030_start_script_address;
434
435         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
436                                 R_PROTECT_KEY);
437         if (err)
438                 goto unlock;
439
440         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
441                                 R_PROTECT_KEY);
442         if (err)
443                 goto unlock;
444
445         for (i = 0; i < twl4030_scripts->num; i++) {
446                 err = load_twl4030_script(twl4030_scripts->scripts[i], address);
447                 if (err)
448                         goto load;
449                 address += twl4030_scripts->scripts[i]->size;
450         }
451
452         resconfig = twl4030_scripts->resource_config;
453         if (resconfig) {
454                 while (resconfig->resource) {
455                         err = twl4030_configure_resource(resconfig);
456                         if (err)
457                                 goto resource;
458                         resconfig++;
459
460                 }
461         }
462
463         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
464         if (err)
465                 pr_err("TWL4030 Unable to relock registers\n");
466         return;
467
468 unlock:
469         if (err)
470                 pr_err("TWL4030 Unable to unlock registers\n");
471         return;
472 load:
473         if (err)
474                 pr_err("TWL4030 failed to load scripts\n");
475         return;
476 resource:
477         if (err)
478                 pr_err("TWL4030 failed to configure resource\n");
479         return;
480 }