]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/mfd/twl4030-power.c
h63xx: nfs mount works, gpe image boots to ts config screen.
[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 /* resource - hfclk */
42 #define R_HFCLKOUT_DEV_GRP      PHY_TO_OFF_PM_RECEIVER(0xe6)
43
44 /* PM events */
45 #define R_P1_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x46)
46 #define R_P2_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x47)
47 #define R_P3_SW_EVENTS          PHY_TO_OFF_PM_MASTER(0x48)
48 #define R_CFG_P1_TRANSITION     PHY_TO_OFF_PM_MASTER(0x36)
49 #define R_CFG_P2_TRANSITION     PHY_TO_OFF_PM_MASTER(0x37)
50 #define R_CFG_P3_TRANSITION     PHY_TO_OFF_PM_MASTER(0x38)
51
52 #define LVL_WAKEUP      0x08
53
54 #define ENABLE_WARMRESET (1<<4)
55
56 #define END_OF_SCRIPT           0x3f
57
58 #define R_SEQ_ADD_A2S           PHY_TO_OFF_PM_MASTER(0x55)
59 #define R_SEQ_ADD_SA12          PHY_TO_OFF_PM_MASTER(0x56)
60 #define R_SEQ_ADD_S2A3          PHY_TO_OFF_PM_MASTER(0x57)
61 #define R_SEQ_ADD_WARM          PHY_TO_OFF_PM_MASTER(0x58)
62 #define R_MEMORY_ADDRESS        PHY_TO_OFF_PM_MASTER(0x59)
63 #define R_MEMORY_DATA           PHY_TO_OFF_PM_MASTER(0x5a)
64
65 #define R_PROTECT_KEY           0x0E
66 #define KEY_1                   0xC0
67 #define KEY_2                   0x0C
68
69 static int __init twl4030_write_script_byte(u8 address, u8 byte)
70 {
71         int err;
72
73         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
74                                         R_MEMORY_ADDRESS);
75         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
76                                         R_MEMORY_DATA);
77
78         return err;
79 }
80
81 static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
82                                                 u8 delay, u8 next)
83 {
84         int err = 0;
85
86         address *= 4;
87         err |= twl4030_write_script_byte(address++, pmb_message >> 8);
88         err |= twl4030_write_script_byte(address++, pmb_message & 0xff);
89         err |= twl4030_write_script_byte(address++, delay);
90         err |= twl4030_write_script_byte(address++, next);
91
92         return err;
93 }
94
95 static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
96                                         int len)
97 {
98         int err = 0;
99
100         for (; len; len--, address++, script++) {
101                 if (len == 1)
102                         err |= twl4030_write_script_ins(address,
103                                                         script->pmb_message,
104                                                         script->delay,
105                                                         END_OF_SCRIPT);
106                 else
107                         err |= twl4030_write_script_ins(address,
108                                                         script->pmb_message,
109                                                         script->delay,
110                                                         address + 1);
111         }
112
113         return err;
114 }
115
116 static int __init config_wakeup3_sequence(u8 address)
117 {
118
119         int err = 0;
120
121         /* Set SLEEP to ACTIVE SEQ address for P3 */
122         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
123                                   R_SEQ_ADD_S2A3);
124
125         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
126                                         R_P3_SW_EVENTS);
127         if (err)
128                 printk(KERN_ERR "TWL4030 wakeup sequence for P3" \
129                                 "config error\n");
130
131         return err;
132 }
133
134 static int __init config_wakeup12_sequence(u8 address)
135 {
136         int err = 0;
137
138         /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
139         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
140                                   R_SEQ_ADD_SA12);
141
142         /* P1/P2/P3 LVL_WAKEUP should be on LEVEL */
143         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
144                                         R_P1_SW_EVENTS);
145         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
146                                         R_P2_SW_EVENTS);
147
148         if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
149                 u8 data;
150                 /* Disabling AC charger effect on sleep-active transitions */
151                 err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
152                                                 R_CFG_P1_TRANSITION);
153                 data &= ~(1<<1);
154                 err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
155                                                 R_CFG_P1_TRANSITION);
156         }
157
158         if (err)
159                 printk(KERN_ERR "TWL4030 wakeup sequence for P1 and P2" \
160                                 "config error\n");
161
162         return err;
163 }
164
165 static int __init config_sleep_sequence(u8 address)
166 {
167         int err = 0;
168
169         /*
170          * CLKREQ is pulled high on the 2430SDP, therefore, we need to take
171          * it out of the HFCLKOUT DEV_GRP for P1 else HFCLKOUT can't be stopped.
172          */
173
174         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
175                                   0x20, R_HFCLKOUT_DEV_GRP);
176
177         /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
178         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
179                                   R_SEQ_ADD_A2S);
180
181         if (err)
182                 printk(KERN_ERR "TWL4030 sleep sequence config error\n");
183
184         return err;
185 }
186
187 static int __init config_warmreset_sequence(u8 address)
188 {
189
190         int err = 0;
191         u8 rd_data;
192
193         /* Set WARM RESET SEQ address for P1 */
194         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
195                                         R_SEQ_ADD_WARM);
196
197         /* P1/P2/P3 enable WARMRESET */
198         err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
199                                         R_P1_SW_EVENTS);
200         rd_data |= ENABLE_WARMRESET;
201         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
202                                         R_P1_SW_EVENTS);
203
204         err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
205                                         R_P2_SW_EVENTS);
206         rd_data |= ENABLE_WARMRESET;
207         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
208                                         R_P2_SW_EVENTS);
209
210         err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
211                                         R_P3_SW_EVENTS);
212         rd_data |= ENABLE_WARMRESET;
213         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
214                                         R_P3_SW_EVENTS);
215
216         if (err)
217                 printk(KERN_ERR
218                         "TWL4030 warmreset seq config error\n");
219         return err;
220 }
221
222 static int __init load_triton_script(struct twl4030_script *tscript)
223 {
224         u8 address = triton_next_free_address;
225         int err;
226
227         err = twl4030_write_script(address, tscript->script, tscript->size);
228         if (err)
229                 return err;
230
231         triton_next_free_address += tscript->size;
232
233         if (tscript->flags & TRITON_WRST_SCRIPT)
234                 err |= config_warmreset_sequence(address);
235
236         if (tscript->flags & TRITON_WAKEUP12_SCRIPT)
237                 err |= config_wakeup12_sequence(address);
238
239         if (tscript->flags & TRITON_WAKEUP3_SCRIPT)
240                 err |= config_wakeup3_sequence(address);
241
242         if (tscript->flags & TRITON_SLEEP_SCRIPT)
243                 err |= config_sleep_sequence(address);
244
245         return err;
246 }
247
248 void __init twl4030_power_init(struct twl4030_power_data *triton2_scripts)
249 {
250         int err = 0;
251         int i;
252
253         err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
254                                 R_PROTECT_KEY);
255         err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
256                                 R_PROTECT_KEY);
257         if (err)
258                 printk(KERN_ERR
259                         "TWL4030 Unable to unlock registers\n");
260
261         for (i = 0; i < triton2_scripts->size; i++) {
262                 err = load_triton_script(triton2_scripts->scripts[i]);
263                 if (err)
264                         break;
265         }
266
267         if (twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY))
268                 printk(KERN_ERR
269                         "TWL4030 Unable to relock registers\n");
270 }