]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/i2c/chips/twl4030-power.c
Add missing variable to twl4030-power.c
[linux-2.6-omap-h63xx.git] / drivers / i2c / chips / 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
30 #define PWR_P1_SW_EVENTS        0x10
31 #define PWR_DEVOFF      (1<<0)
32
33 #define PHY_TO_OFF_PM_MASTER(p)         (p - 0x36)
34 #define PHY_TO_OFF_PM_RECIEVER(p)       (p - 0x5b)
35
36 /* resource - hfclk */
37 #define R_HFCLKOUT_DEV_GRP      PHY_TO_OFF_PM_RECIEVER(0xe6)
38
39 /* PM events */
40 #define R_P1_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x46)
41 #define R_P2_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x47)
42 #define R_P3_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x48)
43 #define R_CFG_P1_TRANSITION     PHY_TO_OFF_PM_MASTER(0x36)
44 #define R_CFG_P2_TRANSITION     PHY_TO_OFF_PM_MASTER(0x37)
45 #define R_CFG_P3_TRANSITION     PHY_TO_OFF_PM_MASTER(0x38)
46
47 #define LVL_WAKEUP      0x08
48
49 #define ENABLE_WARMRESET (1<<4)
50
51 /* sequence script */
52
53 #define END_OF_SCRIPT           0x3f
54
55 #define R_SEQ_ADD_A2S           PHY_TO_OFF_PM_MASTER(0x55)
56 #define R_SEQ_ADD_SA12          PHY_TO_OFF_PM_MASTER(0x56)
57 #define R_SEQ_ADD_S2A3          PHY_TO_OFF_PM_MASTER(0x57)
58 #define R_SEQ_ADD_WARM          PHY_TO_OFF_PM_MASTER(0x58)
59 #define R_MEMORY_ADDRESS        PHY_TO_OFF_PM_MASTER(0x59)
60 #define R_MEMORY_DATA           PHY_TO_OFF_PM_MASTER(0x5a)
61
62 /* Power bus message definitions */
63
64 #define DEV_GRP_NULL            0x0
65 #define DEV_GRP_P1              0x1
66 #define DEV_GRP_P2              0x2
67 #define DEV_GRP_P3              0x4
68
69 #define RES_GRP_RES             0x0
70 #define RES_GRP_PP              0x1
71 #define RES_GRP_RC              0x2
72 #define RES_GRP_PP_RC           0x3
73 #define RES_GRP_PR              0x4
74 #define RES_GRP_PP_PR           0x5
75 #define RES_GRP_RC_PR           0x6
76 #define RES_GRP_ALL             0x7
77
78 #define RES_TYPE2_R0            0x0
79
80 #define RES_TYPE_ALL            0x7
81
82 #define RES_STATE_WRST          0xF
83 #define RES_STATE_ACTIVE        0xE
84 #define RES_STATE_SLEEP         0x8
85 #define RES_STATE_OFF           0x0
86
87 /*
88 *       Power Bus Message Format
89 *
90 *       Broadcast Message (16 Bits)
91 *       DEV_GRP[15:13] MT[12]  RES_GRP[11:9]  RES_TYPE2[8:7] RES_TYPE[6:4]
92 *       RES_STATE[3:0]
93 *
94 *       Singular Message (16 Bits)
95 *       DEV_GRP[15:13] MT[12]  RES_ID[11:4]  RES_STATE[3:0]
96 *
97 */
98
99 #define MSG_BROADCAST(devgrp, grp, type, type2, state) \
100         (devgrp << 13 | 1 << 12 | grp << 9 | type2 << 7 | type << 4 | state)
101
102 #define MSG_SINGULAR(devgrp, id, state) \
103         (devgrp << 13 | 0 << 12 | id << 4 | state)
104
105 #define R_PROTECT_KEY           0x0E
106 #define KEY_1                   0xC0
107 #define KEY_2                   0x0C
108
109 struct triton_ins {
110         u16 pmb_message;
111         u8 delay;
112 };
113
114
115 #define CONFIG_DISABLE_HFCLK    1
116
117 #if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP_3430LABRADOR)
118
119 struct triton_ins sleep_on_seq[] __initdata = {
120         {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4},
121         {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
122 #ifdef CONFIG_DISABLE_HFCLK
123         {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3},
124         {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 3},
125 #endif /* #ifdef CONFIG_DISABLE_HFCLK */
126 };
127
128 struct triton_ins sleep_off_seq[] __initdata = {
129 #ifndef CONFIG_DISABLE_HFCLK
130         {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 4},
131         {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
132 #else
133         {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30},
134         {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30},
135         {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37},
136         {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3},
137 #endif /* #ifndef CONFIG_DISABLE_HFCLK */
138 };
139
140 struct triton_ins t2_wrst_seq[] __initdata = {
141         {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
142         {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
143         {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
144         {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
145         {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
146         {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
147 };
148 #else
149 struct triton_ins sleep_on_seq[] __initdata = {
150         {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0,
151                         RES_STATE_SLEEP), 4},
152         {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_ALL, RES_TYPE2_R0,
153                         RES_STATE_SLEEP), 4},
154 };
155
156 struct triton_ins sleep_off_seq[] __initdata = {
157         {MSG_SINGULAR(DEV_GRP_NULL, 0x17, RES_STATE_ACTIVE), 0x30},
158         {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP_PR, RES_TYPE_ALL, RES_TYPE2_R0,
159                         RES_STATE_ACTIVE), 0x37},
160         {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_ALL, RES_TYPE2_R0,
161                         RES_STATE_ACTIVE), 0x2},
162 };
163
164 struct triton_ins t2_wrst_seq[] __initdata = { };
165
166 #endif
167
168 static int __init twl4030_write_script_byte(u8 address, u8 byte)
169 {
170         int err;
171
172         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
173                                         R_MEMORY_ADDRESS);
174         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
175                                         R_MEMORY_DATA);
176
177         return err;
178 }
179
180 static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
181                                                 u8 delay, u8 next)
182 {
183         int err = 0;
184
185         address *= 4;
186         err |= twl4030_write_script_byte(address++, pmb_message >> 8);
187         err |= twl4030_write_script_byte(address++, pmb_message & 0xff);
188         err |= twl4030_write_script_byte(address++, delay);
189         err |= twl4030_write_script_byte(address++, next);
190
191         return err;
192 }
193
194 static int __init twl4030_write_script(u8 address, struct triton_ins *script,
195                                         int len)
196 {
197         int err = 0;
198
199         for (; len; len--, address++, script++) {
200                 if (len == 1)
201                         err |= twl4030_write_script_ins(address,
202                                                         script->pmb_message,
203                                                         script->delay,
204                                                         END_OF_SCRIPT);
205                 else
206                         err |= twl4030_write_script_ins(address,
207                                                         script->pmb_message,
208                                                         script->delay,
209                                                         address + 1);
210         }
211
212         return err;
213 }
214
215 static int __init config_sleep_wake_sequence(void)
216 {
217         int err = 0;
218         u8 data;
219
220         /*
221          * CLKREQ is pulled high on the 2430SDP, therefore, we need to take
222          * it out of the HFCLKOUT DEV_GRP for P1 else HFCLKOUT can't be stopped.
223          */
224
225         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
226                                   0x20, R_HFCLKOUT_DEV_GRP);
227
228         /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
229         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x2B,
230                                   R_SEQ_ADD_A2S);
231
232         /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
233         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x2F,
234                                   R_SEQ_ADD_SA12);
235
236         /* Set SLEEP to ACTIVE SEQ address for P3 */
237         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x2F,
238                                   R_SEQ_ADD_S2A3);
239
240         /* Install Active->Sleep (A2S) sequence */
241         err |= twl4030_write_script(0x2B, sleep_on_seq,
242                                         ARRAY_SIZE(sleep_on_seq));
243
244         /* Install Sleep->Active (S2A) sequence */
245         err |= twl4030_write_script(0x2F, sleep_off_seq,
246                                         ARRAY_SIZE(sleep_off_seq));
247
248 #if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP_3430LABRADOR)
249         /* Disabling AC charger effect on sleep-active transitions */
250         err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
251                                         R_CFG_P1_TRANSITION);
252         data &= 0x0;
253         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
254                                         R_CFG_P1_TRANSITION);
255 #endif
256         /* P1/P2/P3 LVL_WAKEUP should be on LEVEL */
257         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
258                                         R_P1_SW_EVENTS);
259         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
260                                         R_P2_SW_EVENTS);
261         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
262                                 R_P3_SW_EVENTS);
263
264         if (err)
265                 printk(KERN_ERR "TWL4030 sleep-wake sequence config error\n");
266
267         return err;
268 }
269
270
271 /* Programming the WARMRESET Sequence on TRITON */
272 static int __init config_warmreset_sequence(void)
273 {
274
275         int e = 0;
276         u8 rd_data;
277
278         if (!ARRAY_SIZE(t2_wrst_seq))
279                 return 0;
280
281         /* Set WARM RESET SEQ address for P1 */
282         e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x38,
283                                 R_SEQ_ADD_WARM);
284
285         /* Install Warm Reset sequence */
286         e |= twl4030_write_script(0x38, t2_wrst_seq,
287                                         ARRAY_SIZE(t2_wrst_seq));
288
289         /* P1/P2/P3 enable WARMRESET */
290         e |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
291                                 R_P1_SW_EVENTS);
292         rd_data |= ENABLE_WARMRESET;
293         e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
294                                 R_P1_SW_EVENTS);
295
296         e |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
297                                 R_P2_SW_EVENTS);
298         rd_data |= ENABLE_WARMRESET;
299         e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
300                                 R_P2_SW_EVENTS);
301
302         e |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
303                                 R_P3_SW_EVENTS);
304         rd_data |= ENABLE_WARMRESET;
305         e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
306                                 R_P3_SW_EVENTS);
307
308         if (e)
309                 printk(KERN_ERR
310                         "TWL4030 Power Companion Warmreset seq config error\n");
311         return e;
312 }
313
314 static int __init twl4030_power_init(void)
315 {
316         int err = 0;
317
318         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
319                                 R_PROTECT_KEY);
320         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
321                                 R_PROTECT_KEY);
322
323         if (err)
324                 return err;
325
326         err = config_sleep_wake_sequence();
327         if (err)
328                 return err;
329
330         err = config_warmreset_sequence();
331         if (err)
332                 return err;
333
334         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
335
336         return err;
337
338 }
339
340 module_init(twl4030_power_init);