pandora: update defconfig
[pandora-kernel.git] / 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/twl.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 #define REMAP_OFFSET            2
79 #define DEDICATED_OFFSET        3
80
81 /* Bit positions in the registers */
82
83 /* <RESOURCE>_DEV_GRP */
84 #define DEV_GRP_SHIFT           5
85 #define DEV_GRP_MASK            (7 << DEV_GRP_SHIFT)
86
87 /* <RESOURCE>_TYPE */
88 #define TYPE_SHIFT              0
89 #define TYPE_MASK               (7 << TYPE_SHIFT)
90 #define TYPE2_SHIFT             3
91 #define TYPE2_MASK              (3 << TYPE2_SHIFT)
92
93 /* <RESOURCE>_REMAP */
94 #define SLEEP_STATE_SHIFT       0
95 #define SLEEP_STATE_MASK        (0xf << SLEEP_STATE_SHIFT)
96 #define OFF_STATE_SHIFT         4
97 #define OFF_STATE_MASK          (0xf << OFF_STATE_SHIFT)
98
99 static u8 res_config_addrs[] = {
100         [RES_VAUX1]     = 0x17,
101         [RES_VAUX2]     = 0x1b,
102         [RES_VAUX3]     = 0x1f,
103         [RES_VAUX4]     = 0x23,
104         [RES_VMMC1]     = 0x27,
105         [RES_VMMC2]     = 0x2b,
106         [RES_VPLL1]     = 0x2f,
107         [RES_VPLL2]     = 0x33,
108         [RES_VSIM]      = 0x37,
109         [RES_VDAC]      = 0x3b,
110         [RES_VINTANA1]  = 0x3f,
111         [RES_VINTANA2]  = 0x43,
112         [RES_VINTDIG]   = 0x47,
113         [RES_VIO]       = 0x4b,
114         [RES_VDD1]      = 0x55,
115         [RES_VDD2]      = 0x63,
116         [RES_VUSB_1V5]  = 0x71,
117         [RES_VUSB_1V8]  = 0x74,
118         [RES_VUSB_3V1]  = 0x77,
119         [RES_VUSBCP]    = 0x7a,
120         [RES_REGEN]     = 0x7f,
121         [RES_NRES_PWRON] = 0x82,
122         [RES_CLKEN]     = 0x85,
123         [RES_SYSEN]     = 0x88,
124         [RES_HFCLKOUT]  = 0x8b,
125         [RES_32KCLKOUT] = 0x8e,
126         [RES_RESET]     = 0x91,
127         [RES_Main_Ref]  = 0x94,
128 };
129
130 static int __init twl4030_write_script_byte(u8 address, u8 byte)
131 {
132         int err;
133
134         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
135                                 R_MEMORY_ADDRESS);
136         if (err)
137                 goto out;
138         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
139                                 R_MEMORY_DATA);
140 out:
141         return err;
142 }
143
144 static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
145                                            u8 delay, u8 next)
146 {
147         int err;
148
149         address *= 4;
150         err = twl4030_write_script_byte(address++, pmb_message >> 8);
151         if (err)
152                 goto out;
153         err = twl4030_write_script_byte(address++, pmb_message & 0xff);
154         if (err)
155                 goto out;
156         err = twl4030_write_script_byte(address++, delay);
157         if (err)
158                 goto out;
159         err = twl4030_write_script_byte(address++, next);
160 out:
161         return err;
162 }
163
164 static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
165                                        int len)
166 {
167         int err;
168
169         for (; len; len--, address++, script++) {
170                 if (len == 1) {
171                         err = twl4030_write_script_ins(address,
172                                                 script->pmb_message,
173                                                 script->delay,
174                                                 END_OF_SCRIPT);
175                         if (err)
176                                 break;
177                 } else {
178                         err = twl4030_write_script_ins(address,
179                                                 script->pmb_message,
180                                                 script->delay,
181                                                 address + 1);
182                         if (err)
183                                 break;
184                 }
185         }
186         return err;
187 }
188
189 static int __init twl4030_config_wakeup3_sequence(u8 address)
190 {
191         int err;
192         u8 data;
193
194         /* Set SLEEP to ACTIVE SEQ address for P3 */
195         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
196                                 R_SEQ_ADD_S2A3);
197         if (err)
198                 goto out;
199
200         /* P3 LVL_WAKEUP should be on LEVEL */
201         err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
202                                 R_P3_SW_EVENTS);
203         if (err)
204                 goto out;
205         data |= LVL_WAKEUP;
206         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
207                                 R_P3_SW_EVENTS);
208 out:
209         if (err)
210                 pr_err("TWL4030 wakeup sequence for P3 config error\n");
211         return err;
212 }
213
214 static int __init twl4030_config_wakeup12_sequence(u8 address)
215 {
216         int err = 0;
217         u8 data;
218
219         /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
220         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
221                                 R_SEQ_ADD_S2A12);
222         if (err)
223                 goto out;
224
225         /* P1/P2 LVL_WAKEUP should be on LEVEL */
226         err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
227                                 R_P1_SW_EVENTS);
228         if (err)
229                 goto out;
230
231         data |= LVL_WAKEUP;
232         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
233                                 R_P1_SW_EVENTS);
234         if (err)
235                 goto out;
236
237         err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
238                                 R_P2_SW_EVENTS);
239         if (err)
240                 goto out;
241
242         data |= LVL_WAKEUP;
243         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data,
244                                 R_P2_SW_EVENTS);
245         if (err)
246                 goto out;
247
248         if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
249                 /* Disabling AC charger effect on sleep-active transitions */
250                 err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
251                                         R_CFG_P1_TRANSITION);
252                 if (err)
253                         goto out;
254                 data &= ~(1<<1);
255                 err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
256                                         R_CFG_P1_TRANSITION);
257                 if (err)
258                         goto out;
259         }
260
261 out:
262         if (err)
263                 pr_err("TWL4030 wakeup sequence for P1 and P2" \
264                         "config error\n");
265         return err;
266 }
267
268 static int __init twl4030_config_sleep_sequence(u8 address)
269 {
270         int err;
271
272         /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
273         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
274                                 R_SEQ_ADD_A2S);
275
276         if (err)
277                 pr_err("TWL4030 sleep sequence config error\n");
278
279         return err;
280 }
281
282 static int __init twl4030_config_warmreset_sequence(u8 address)
283 {
284         int err;
285         u8 rd_data;
286
287         /* Set WARM RESET SEQ address for P1 */
288         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
289                                 R_SEQ_ADD_WARM);
290         if (err)
291                 goto out;
292
293         /* P1/P2/P3 enable WARMRESET */
294         err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
295                                 R_P1_SW_EVENTS);
296         if (err)
297                 goto out;
298
299         rd_data |= ENABLE_WARMRESET;
300         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
301                                 R_P1_SW_EVENTS);
302         if (err)
303                 goto out;
304
305         err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
306                                 R_P2_SW_EVENTS);
307         if (err)
308                 goto out;
309
310         rd_data |= ENABLE_WARMRESET;
311         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
312                                 R_P2_SW_EVENTS);
313         if (err)
314                 goto out;
315
316         err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
317                                 R_P3_SW_EVENTS);
318         if (err)
319                 goto out;
320
321         rd_data |= ENABLE_WARMRESET;
322         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
323                                 R_P3_SW_EVENTS);
324 out:
325         if (err)
326                 pr_err("TWL4030 warmreset seq config error\n");
327         return err;
328 }
329
330 static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
331 {
332         int rconfig_addr;
333         int err;
334         u8 type;
335         u8 grp;
336         u8 remap;
337
338         if (rconfig->resource > TOTAL_RESOURCES) {
339                 pr_err("TWL4030 Resource %d does not exist\n",
340                         rconfig->resource);
341                 return -EINVAL;
342         }
343
344         rconfig_addr = res_config_addrs[rconfig->resource];
345
346         /* Set resource group */
347         err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
348                               rconfig_addr + DEV_GRP_OFFSET);
349         if (err) {
350                 pr_err("TWL4030 Resource %d group could not be read\n",
351                         rconfig->resource);
352                 return err;
353         }
354
355         if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
356                 grp &= ~DEV_GRP_MASK;
357                 grp |= rconfig->devgroup << DEV_GRP_SHIFT;
358                 err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
359                                        grp, rconfig_addr + DEV_GRP_OFFSET);
360                 if (err < 0) {
361                         pr_err("TWL4030 failed to program devgroup\n");
362                         return err;
363                 }
364         }
365
366         /* Set resource types */
367         err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
368                                 rconfig_addr + TYPE_OFFSET);
369         if (err < 0) {
370                 pr_err("TWL4030 Resource %d type could not be read\n",
371                         rconfig->resource);
372                 return err;
373         }
374
375         if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
376                 type &= ~TYPE_MASK;
377                 type |= rconfig->type << TYPE_SHIFT;
378         }
379
380         if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
381                 type &= ~TYPE2_MASK;
382                 type |= rconfig->type2 << TYPE2_SHIFT;
383         }
384
385         err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
386                                 type, rconfig_addr + TYPE_OFFSET);
387         if (err < 0) {
388                 pr_err("TWL4030 failed to program resource type\n");
389                 return err;
390         }
391
392         /* Set remap states */
393         err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
394                               rconfig_addr + REMAP_OFFSET);
395         if (err < 0) {
396                 pr_err("TWL4030 Resource %d remap could not be read\n",
397                         rconfig->resource);
398                 return err;
399         }
400
401         if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
402                 remap &= ~OFF_STATE_MASK;
403                 remap |= rconfig->remap_off << OFF_STATE_SHIFT;
404         }
405
406         if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
407                 remap &= ~SLEEP_STATE_MASK;
408                 remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
409         }
410
411         err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
412                                remap,
413                                rconfig_addr + REMAP_OFFSET);
414         if (err < 0) {
415                 pr_err("TWL4030 failed to program remap\n");
416                 return err;
417         }
418
419         return 0;
420 }
421
422 static int __init load_twl4030_script(struct twl4030_script *tscript,
423                u8 address)
424 {
425         int err;
426         static int order;
427
428         /* Make sure the script isn't going beyond last valid address (0x3f) */
429         if ((address + tscript->size) > END_OF_SCRIPT) {
430                 pr_err("TWL4030 scripts too big error\n");
431                 return -EINVAL;
432         }
433
434         err = twl4030_write_script(address, tscript->script, tscript->size);
435         if (err)
436                 goto out;
437
438         if (tscript->flags & TWL4030_WRST_SCRIPT) {
439                 err = twl4030_config_warmreset_sequence(address);
440                 if (err)
441                         goto out;
442         }
443         if (tscript->flags & TWL4030_WAKEUP12_SCRIPT) {
444                 err = twl4030_config_wakeup12_sequence(address);
445                 if (err)
446                         goto out;
447                 order = 1;
448         }
449         if (tscript->flags & TWL4030_WAKEUP3_SCRIPT) {
450                 err = twl4030_config_wakeup3_sequence(address);
451                 if (err)
452                         goto out;
453         }
454         if (tscript->flags & TWL4030_SLEEP_SCRIPT)
455                 if (order)
456                         pr_warning("TWL4030: Bad order of scripts (sleep "\
457                                         "script before wakeup) Leads to boot"\
458                                         "failure on some boards\n");
459                 err = twl4030_config_sleep_sequence(address);
460 out:
461         return err;
462 }
463
464 int twl4030_remove_script(u8 flags)
465 {
466         int err = 0;
467
468         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
469                         R_PROTECT_KEY);
470         if (err) {
471                 pr_err("twl4030: unable to unlock PROTECT_KEY\n");
472                 return err;
473         }
474
475         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
476                         R_PROTECT_KEY);
477         if (err) {
478                 pr_err("twl4030: unable to unlock PROTECT_KEY\n");
479                 return err;
480         }
481
482         if (flags & TWL4030_WRST_SCRIPT) {
483                 err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
484                                 R_SEQ_ADD_WARM);
485                 if (err)
486                         return err;
487         }
488         if (flags & TWL4030_WAKEUP12_SCRIPT) {
489                 if (err)
490                 err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
491                                 R_SEQ_ADD_S2A12);
492                         return err;
493         }
494         if (flags & TWL4030_WAKEUP3_SCRIPT) {
495                 err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
496                                 R_SEQ_ADD_S2A3);
497                 if (err)
498                         return err;
499         }
500         if (flags & TWL4030_SLEEP_SCRIPT) {
501                 err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
502                                 R_SEQ_ADD_A2S);
503                 if (err)
504                         return err;
505         }
506
507         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
508         if (err)
509                 pr_err("TWL4030 Unable to relock registers\n");
510
511         return err;
512 }
513
514 void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
515 {
516         int err = 0;
517         int i;
518         struct twl4030_resconfig *resconfig;
519         u8 address = twl4030_start_script_address;
520
521         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1,
522                                 R_PROTECT_KEY);
523         if (err)
524                 goto unlock;
525
526         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2,
527                                 R_PROTECT_KEY);
528         if (err)
529                 goto unlock;
530
531         for (i = 0; i < twl4030_scripts->num; i++) {
532                 err = load_twl4030_script(twl4030_scripts->scripts[i], address);
533                 if (err)
534                         goto load;
535                 address += twl4030_scripts->scripts[i]->size;
536         }
537
538         resconfig = twl4030_scripts->resource_config;
539         if (resconfig) {
540                 while (resconfig->resource) {
541                         err = twl4030_configure_resource(resconfig);
542                         if (err)
543                                 goto resource;
544                         resconfig++;
545
546                 }
547         }
548
549         err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
550         if (err)
551                 pr_err("TWL4030 Unable to relock registers\n");
552         return;
553
554 unlock:
555         if (err)
556                 pr_err("TWL4030 Unable to unlock registers\n");
557         return;
558 load:
559         if (err)
560                 pr_err("TWL4030 failed to load scripts\n");
561         return;
562 resource:
563         if (err)
564                 pr_err("TWL4030 failed to configure resource\n");
565         return;
566 }