]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/mfd/twl4030-power.c
Merge branch 'omap-fixes'
[linux-2.6-omap-h63xx.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  *
12  * This file is subject to the terms and conditions of the GNU General
13  * Public License. See the file "COPYING" in the main directory of this
14  * archive for more details.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 #include <linux/module.h>
27 #include <linux/pm.h>
28 #include <linux/i2c/twl4030.h>
29 #include <linux/platform_device.h>
30
31 #include <asm/mach-types.h>
32
33 static u8 triton_next_free_address = 0x2b;
34
35 #define PWR_P1_SW_EVENTS        0x10
36 #define PWR_DEVOFF      (1<<0)
37
38 #define PHY_TO_OFF_PM_MASTER(p)         (p - 0x36)
39 #define PHY_TO_OFF_PM_RECEIVER(p)       (p - 0x5b)
40
41 #define NUM_OF_RESOURCES        28
42
43 /* resource - hfclk */
44 #define R_HFCLKOUT_DEV_GRP      PHY_TO_OFF_PM_RECEIVER(0xe6)
45
46 /* PM events */
47 #define R_P1_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x46)
48 #define R_P2_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x47)
49 #define R_P3_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x48)
50 #define R_CFG_P1_TRANSITION     PHY_TO_OFF_PM_MASTER(0x36)
51 #define R_CFG_P2_TRANSITION     PHY_TO_OFF_PM_MASTER(0x37)
52 #define R_CFG_P3_TRANSITION     PHY_TO_OFF_PM_MASTER(0x38)
53
54 #define LVL_WAKEUP      0x08
55
56 #define ENABLE_WARMRESET (1<<4)
57
58 #define END_OF_SCRIPT           0x3f
59
60 #define R_SEQ_ADD_A2S           PHY_TO_OFF_PM_MASTER(0x55)
61 #define R_SEQ_ADD_SA12          PHY_TO_OFF_PM_MASTER(0x56)
62 #define R_SEQ_ADD_S2A3          PHY_TO_OFF_PM_MASTER(0x57)
63 #define R_SEQ_ADD_WARM          PHY_TO_OFF_PM_MASTER(0x58)
64 #define R_MEMORY_ADDRESS        PHY_TO_OFF_PM_MASTER(0x59)
65 #define R_MEMORY_DATA           PHY_TO_OFF_PM_MASTER(0x5a)
66
67 #define R_PROTECT_KEY           0x0E
68 #define KEY_1                   0xC0
69 #define KEY_2                   0x0C
70
71 /* resource configuration registers */
72
73 #define DEVGROUP_OFFSET         0
74 #define TYPE_OFFSET             1
75
76 static u8 res_config_addrs[] = {
77         [RES_VAUX1]     = 0x17,
78         [RES_VAUX2]     = 0x1b,
79         [RES_VAUX3]     = 0x1f,
80         [RES_VAUX4]     = 0x23,
81         [RES_VMMC1]     = 0x27,
82         [RES_VMMC2]     = 0x2b,
83         [RES_VPLL1]     = 0x2f,
84         [RES_VPLL2]     = 0x33,
85         [RES_VSIM]      = 0x37,
86         [RES_VDAC]      = 0x3b,
87         [RES_VINTANA1]  = 0x3f,
88         [RES_VINTANA2]  = 0x43,
89         [RES_VINTDIG]   = 0x47,
90         [RES_VIO]       = 0x4b,
91         [RES_VDD1]      = 0x55,
92         [RES_VDD2]      = 0x63,
93         [RES_VUSB_1V5]  = 0x71,
94         [RES_VUSB_1V8]  = 0x74,
95         [RES_VUSB_3V1]  = 0x77,
96         [RES_VUSBCP]    = 0x7a,
97         [RES_REGEN]     = 0x7f,
98         [RES_NRES_PWRON] = 0x82,
99         [RES_CLKEN]     = 0x85,
100         [RES_SYSEN]     = 0x88,
101         [RES_HFCLKOUT]  = 0x8b,
102         [RES_32KCLKOUT] = 0x8e,
103         [RES_RESET]     = 0x91,
104         [RES_Main_Ref]  = 0x94,
105 };
106
107 static int __init twl4030_write_script_byte(u8 address, u8 byte)
108 {
109         int err;
110
111         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
112                                         R_MEMORY_ADDRESS);
113         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
114                                         R_MEMORY_DATA);
115
116         return err;
117 }
118
119 static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
120                                                 u8 delay, u8 next)
121 {
122         int err = 0;
123
124         address *= 4;
125         err |= twl4030_write_script_byte(address++, pmb_message >> 8);
126         err |= twl4030_write_script_byte(address++, pmb_message & 0xff);
127         err |= twl4030_write_script_byte(address++, delay);
128         err |= twl4030_write_script_byte(address++, next);
129
130         return err;
131 }
132
133 static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
134                                         int len)
135 {
136         int err = 0;
137
138         for (; len; len--, address++, script++) {
139                 if (len == 1)
140                         err |= twl4030_write_script_ins(address,
141                                                         script->pmb_message,
142                                                         script->delay,
143                                                         END_OF_SCRIPT);
144                 else
145                         err |= twl4030_write_script_ins(address,
146                                                         script->pmb_message,
147                                                         script->delay,
148                                                         address + 1);
149         }
150
151         return err;
152 }
153
154 static int __init config_wakeup3_sequence(u8 address)
155 {
156
157         int err = 0;
158
159         /* Set SLEEP to ACTIVE SEQ address for P3 */
160         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
161                                   R_SEQ_ADD_S2A3);
162
163         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
164                                         R_P3_SW_EVENTS);
165         if (err)
166                 printk(KERN_ERR "TWL4030 wakeup sequence for P3" \
167                                 "config error\n");
168
169         return err;
170 }
171
172 static int __init config_wakeup12_sequence(u8 address)
173 {
174         int err = 0;
175
176         /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
177         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
178                                   R_SEQ_ADD_SA12);
179
180         /* P1/P2/P3 LVL_WAKEUP should be on LEVEL */
181         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
182                                         R_P1_SW_EVENTS);
183         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
184                                         R_P2_SW_EVENTS);
185
186         if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
187                 u8 data;
188                 /* Disabling AC charger effect on sleep-active transitions */
189                 err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
190                                                 R_CFG_P1_TRANSITION);
191                 data &= ~(1<<1);
192                 err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
193                                                 R_CFG_P1_TRANSITION);
194         }
195
196         if (err)
197                 printk(KERN_ERR "TWL4030 wakeup sequence for P1 and P2" \
198                                 "config error\n");
199
200         return err;
201 }
202
203 static int __init config_sleep_sequence(u8 address)
204 {
205         int err = 0;
206
207         /*
208          * CLKREQ is pulled high on the 2430SDP, therefore, we need to take
209          * it out of the HFCLKOUT DEV_GRP for P1 else HFCLKOUT can't be stopped.
210          */
211
212         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
213                                   0x20, R_HFCLKOUT_DEV_GRP);
214
215         /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
216         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
217                                   R_SEQ_ADD_A2S);
218
219         if (err)
220                 printk(KERN_ERR "TWL4030 sleep sequence config error\n");
221
222         return err;
223 }
224
225 static int __init config_warmreset_sequence(u8 address)
226 {
227
228         int err = 0;
229         u8 rd_data;
230
231         /* Set WARM RESET SEQ address for P1 */
232         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
233                                         R_SEQ_ADD_WARM);
234
235         /* P1/P2/P3 enable WARMRESET */
236         err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
237                                         R_P1_SW_EVENTS);
238         rd_data |= ENABLE_WARMRESET;
239         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
240                                         R_P1_SW_EVENTS);
241
242         err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
243                                         R_P2_SW_EVENTS);
244         rd_data |= ENABLE_WARMRESET;
245         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
246                                         R_P2_SW_EVENTS);
247
248         err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
249                                         R_P3_SW_EVENTS);
250         rd_data |= ENABLE_WARMRESET;
251         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
252                                         R_P3_SW_EVENTS);
253
254         if (err)
255                 printk(KERN_ERR
256                         "TWL4030 warmreset seq config error\n");
257         return err;
258 }
259
260 void twl4030_configure_resource(struct twl4030_resconfig *rconfig)
261 {
262         int rconfig_addr;
263         u8 type;
264
265         if (rconfig->resource > NUM_OF_RESOURCES) {
266                 printk(KERN_ERR
267                         "TWL4030 Resource %d does not exist\n",
268                         rconfig->resource);
269                 return;
270         }
271
272         rconfig_addr = res_config_addrs[rconfig->resource];
273
274         /* Set resource group */
275
276         if (rconfig->devgroup >= 0)
277                 twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
278                                         rconfig->devgroup << 5,
279                                         rconfig_addr + DEVGROUP_OFFSET);
280
281         /* Set resource types */
282
283         if (twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER,
284                                         &type,
285                                         rconfig_addr + TYPE_OFFSET) < 0) {
286                 printk(KERN_ERR
287                         "TWL4030 Resource %d type could not read\n",
288                         rconfig->resource);
289                 return;
290         }
291
292         if (rconfig->type >= 0) {
293                 type &= ~7;
294                 type |= rconfig->type;
295         }
296
297         if (rconfig->type2 >= 0) {
298                 type &= ~(3 << 3);
299                 type |= rconfig->type2 << 3;
300         }
301
302         twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
303                                 type, rconfig_addr + TYPE_OFFSET);
304
305 }
306
307 static int __init load_triton_script(struct twl4030_script *tscript)
308 {
309         u8 address = triton_next_free_address;
310         int err;
311
312         err = twl4030_write_script(address, tscript->script, tscript->size);
313         if (err)
314                 return err;
315
316         triton_next_free_address += tscript->size;
317
318         if (tscript->flags & TRITON_WRST_SCRIPT)
319                 err |= config_warmreset_sequence(address);
320
321         if (tscript->flags & TRITON_WAKEUP12_SCRIPT)
322                 err |= config_wakeup12_sequence(address);
323
324         if (tscript->flags & TRITON_WAKEUP3_SCRIPT)
325                 err |= config_wakeup3_sequence(address);
326
327         if (tscript->flags & TRITON_SLEEP_SCRIPT)
328                 err |= config_sleep_sequence(address);
329
330         return err;
331 }
332
333 void __init twl4030_power_init(struct twl4030_power_data *triton2_scripts)
334 {
335         int err = 0;
336         int i;
337         struct twl4030_resconfig *resconfig;
338
339         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
340                                 R_PROTECT_KEY);
341         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
342                                 R_PROTECT_KEY);
343         if (err)
344                 printk(KERN_ERR
345                         "TWL4030 Unable to unlock registers\n");
346
347         for (i = 0; i < triton2_scripts->size; i++) {
348                 err = load_triton_script(triton2_scripts->scripts[i]);
349                 if (err)
350                         break;
351         }
352
353         resconfig = triton2_scripts->resource_config;
354         if (resconfig) {
355                 while (resconfig->resource) {
356                         twl4030_configure_resource(resconfig);
357                         resconfig++;
358                 }
359         }
360
361         if (twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY))
362                 printk(KERN_ERR
363                         "TWL4030 Unable to relock registers\n");
364 }