improved twl4030 phy pwr ctrl
[qemu] / hw / twl4030.c
1 /*
2  * TI TWL4030 emulation
3  *
4  * Copyright (C) 2008 yajin<yajin@vm-kernel.org>
5  * Copyright (C) 2009 Nokia Corporation
6  *
7  * Register implementation based on TPS65950 ES1.0 specification.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24  
25 #include "hw.h"
26 #include "qemu-timer.h"
27 #include "i2c.h"
28 #include "sysemu.h"
29 #include "console.h"
30 #include "cpu-all.h"
31
32 #define VERBOSE 1
33
34 #ifdef VERBOSE
35 #define TRACE(fmt, ...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
36 #else
37 #define TRACE(...)
38 #endif
39
40 struct twl4030_i2c_s {
41     i2c_slave i2c;
42     int firstbyte;
43     uint8_t reg;
44     qemu_irq irq;
45     uint8 reg_data[256];
46     struct twl4030_s *twl4030;
47 };
48
49 struct twl4030_s {
50     struct twl4030_i2c_s *i2c[5];
51     
52     int key_cfg;
53     int key_tst;
54     
55     uint8_t seq_mem[64][4]; /* power-management sequencing memory */
56 };
57
58 static const uint8_t addr_48_reset_values[256] = {
59     0x51, 0x04, 0x02, 0xc0, 0x41, 0x41, 0x41, 0x10, /* 0x00...0x07 */
60     0x10, 0x10, 0x06, 0x06, 0x06, 0x1f, 0x1f, 0x1f, /* 0x08...0x0f */
61     0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
62     0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, /* 0x18...0x1f */
63     0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x03, /* 0x20...0x27 */
64     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
65     0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, /* 0x30...0x37 */
66     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
67     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
68     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
69     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
70     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
71     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
72     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
73     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
74     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
75     0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, /* 0x80...0x87 */
76     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
77     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90...0x97 */
78     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
79     0x00, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
80     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
81     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
82     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8...0xb8 */
83     0xa0, 0xa0, 0x64, 0x7f, 0x6c, 0x75, 0x64, 0x20, /* 0xc0...0xc7 */
84     0x01, 0x17, 0x01, 0x02, 0x00, 0x36, 0x44, 0x07, /* 0xc8...0xcf */
85     0x3b, 0x17, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
86     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
87     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
88     0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
89     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
90     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00  /* 0xf8...0xff */
91 };
92
93 static const uint8_t addr_49_reset_values[256] = {
94     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
95     0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, /* 0x08...0x0f */
96     0x3f, 0x3f, 0x3f, 0x3f, 0x25, 0x00, 0x00, 0x00, /* 0x10...0x17 */
97     0x00, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x55, /* 0x18...0x1f */
98     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
99     0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
100     0x13, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x00, /* 0x30...0x37 */
101     0x00, 0x00, 0x06, 0x00, 0x44, 0x69, 0x00, 0x00, /* 0x38...0x3f */
102     0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x40...0x47 */
103     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
104     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
105     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
106     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
107     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
108     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
109     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
110     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80...0x87 */
111     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
112     0x00, 0x90, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, /* 0x90...0x97 */
113     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
114     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
115     0x00, 0x00, 0x04, 0x00, 0x55, 0x01, 0x55, 0x05, /* 0xa8...0xaf */
116     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, /* 0xb0...0xb7 */
117     0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, /* 0xb8...0xbf */
118     0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0xc0...0xc7 */
119     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
120     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
121     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
122     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
123     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
124     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
125     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8...0xff */
126 };
127
128 static const uint8_t addr_4a_reset_values[256] = {
129     0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
130     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
131     0xc0, 0x8c, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
132     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18...0x1f */
133     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
134     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
135     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30...0x37 */
136     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
137     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
138     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
139     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
140     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
141     0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x07, /* 0x60...0x67 */
142     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
143     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
144     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
145     0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0x80...0x87 */
146     0x00, 0x68, 0x9b, 0x86, 0x48, 0x2a, 0x07, 0x28, /* 0x88...0x8f */
147     0x09, 0x69, 0x90, 0x00, 0x2a, 0x00, 0x02, 0x00, /* 0x90...0x97 */
148     0x10, 0xcd, 0x02, 0x68, 0x03, 0x00, 0x00, 0x00, /* 0x98...0x9f */
149     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
150     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
151     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
152     0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, /* 0xb8...0xbf */
153     0x0f, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x01, 0x00, /* 0xc0...0xc7 */
154     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
155     0x00, 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, /* 0xd0...0xd7 */
156     0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
157     0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, /* 0xe0...0xe7 */
158     0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
159     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
160     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */
161 };
162
163 static const uint8_t addr_4b_reset_values[256] = {
164     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
165     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
166     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
167     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x18...0x1f */
168     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* 0x20...0x27 */
169     0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
170     0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xbf, 0xbf, /* 0x30...0x37 */
171     0xbf, 0xab, 0x00, 0x08, 0x3f, 0x15, 0x40, 0x0e, /* 0x38...0x3f */
172     0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
173     0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, /* 0x48...0x4f */
174     0x00, 0x02, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, /* 0x50...0x57 */
175     0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
176     0x00, 0x00, 0x2f, 0x18, 0x0f, 0x08, 0x0f, 0x08, /* 0x60...0x67 */
177     0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
178     0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x03, /* 0x70...0x77 */
179     0x08, 0x09, 0x00, 0x00, 0x08, 0x03, 0x80, 0x03, /* 0x78...0x7f */
180     0x08, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, /* 0x80...0x87 */
181     0x08, 0x08, 0x20, 0x00, 0x00, 0x02, 0x80, 0x04, /* 0x88...0x8f */
182     0x08, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, /* 0x90...0x97 */
183     0x08, 0x02, 0xe0, 0x01, 0x08, 0x00, 0xe0, 0x00, /* 0x98...0x9f */
184     0x08, 0x01, 0xe0, 0x01, 0x08, 0x04, 0xe0, 0x03, /* 0xa0...0xa7 */
185     0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
186     0x20, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
187     0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, /* 0xb8...0xbf */
188     0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, /* 0xc0...0xc7 */
189     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, /* 0xc8...0xcf */
190     0x00, 0x08, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
191     0x14, 0x08, 0xe0, 0x02, 0x08, 0xe0, 0x00, 0x08, /* 0xd8...0xdf */
192     0xe0, 0x05, 0x08, 0xe0, 0x06, 0x08, 0xe0, 0x00, /* 0xe0...0xe7 */
193     0x08, 0xe0, 0x00, 0x08, 0xe0, 0x06, 0x06, 0xe0, /* 0xe8...0xef */
194     0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
195     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */
196 };
197
198 static uint8_t twl4030_48_read(void *opaque, uint8_t addr)
199 {
200     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
201         
202     TRACE("addr=0x%02x", addr);
203     switch (addr) {
204         case 0x00: /* VENDOR_ID_LO */
205         case 0x01: /* VENDOR_ID_HI */
206         case 0x02: /* PRODUCT_ID_LO */
207         case 0x03: /* PRODUCT_ID_HI */
208             return s->reg_data[addr];
209         case 0x04: /* FUNC_CTRL */
210         case 0x05: /* FUNC_CRTL_SET */
211         case 0x06: /* FUNC_CRTL_CLR */
212             return s->reg_data[0x04];
213         case 0x07: /* IFC_CTRL */
214         case 0x08: /* IFC_CRTL_SET */
215         case 0x09: /* IFC_CRTL_CLR */
216             return s->reg_data[0x07];
217         case 0xac: /* POWER_CTRL */
218         case 0xad: /* POWER_SET */
219         case 0xae: /* POWER_CLR */
220             return s->reg_data[0xac];
221         case 0xfd: /* PHY_PWR_CTRL */
222         case 0xfe: /* PHY_CLK_CTRL */
223             return s->reg_data[addr];
224         case 0xff: /* PHY_CLK_CTRL_STS */
225             if (s->reg_data[0xfd] & 1) /* PHY_PWR_CTRL */
226                 return 0;
227             if (s->reg_data[0xfe] & 1) /* REQ_PHY_DPLL_CLK */
228                 return 1;
229             return (s->reg_data[0x04] >> 6) & 1; /* SUSPENDM */
230         default:
231             fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
232                     __FUNCTION__, addr, cpu_single_env->regs[15]);
233             break;
234     }
235     return 0;
236 }
237
238 static void twl4030_48_write(void *opaque, uint8_t addr, uint8_t value)
239 {
240     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
241         
242     TRACE("addr=0x%02x, value=0x%02x", addr, value);
243     switch (addr) {
244         case 0x04: /* IFC_CTRL */
245             s->reg_data[0x04] = value & 0x80;
246             break;
247         case 0x05: /* IFC_CRTL_SET */
248             s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x80;
249             break;
250         case 0x06: /* IFC_CRTL_CLEAR */
251             s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x80;
252             break;
253         case 0x07: /* IFC_CTRL */
254             s->reg_data[0x07] = value & 0x61;
255             break;
256         case 0x08: /* IFC_CRTL_SET */
257             s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x61;
258             break;
259         case 0x09: /* IFC_CRTL_CLEAR */
260             s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x61;
261             break;
262         case 0xa1: /* CARKIT_SM_CTRL */
263             s->reg_data[0xa1] = value & 0x3f;
264             break;
265         case 0xa2: /* CARKIT_SM_CTRL_SET */
266             s->reg_data[0xa1] = (s->reg_data[0xa1] | value) & 0x3f;
267             break;
268         case 0xa3: /* CARKIT_SM_CTRL_CLR */
269             s->reg_data[0xa1] = (s->reg_data[0xa1] & ~value) & 0x3f;
270             break;
271         case 0xac: /* POWER_CTRL */
272             s->reg_data[0xac] = value & 0x20;
273             break;
274         case 0xad: /* POWER_SET */
275             s->reg_data[0xac] = (s->reg_data[0xac] | value) & 0x20;
276             break;
277         case 0xae: /* POWER_CLEAR */
278             s->reg_data[0xac] = (s->reg_data[0xac] & ~value) & 0x20;
279             break;
280         case 0xbb: /* CARKIT_ANA_CTRL */
281             s->reg_data[0xbb] = value;
282             break;
283         case 0xbc: /* CARKIT_ANA_CTRL_SET */
284             s->reg_data[0xbb] |= value;
285             break;
286         case 0xbd: /* CARKIT_ANA_CTRL_CLR */
287             s->reg_data[0xbb] &= ~value;
288             break;
289         case 0xfd: /* PHY_PWR_CTRL */
290             s->reg_data[addr] = value & 0x1;
291             break;
292         case 0xfe: /* PHY_CLK_CTRL */
293             s->reg_data[addr] = value & 0x7;
294             break;
295         default:
296             fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
297                     __FUNCTION__, addr, cpu_single_env->regs[15]);
298                         break;
299     }
300 }
301
302 static int twl4030_48_tx(i2c_slave *i2c, uint8_t data)
303 {
304     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
305     /* Interpret register address byte */
306     if (s->firstbyte) {
307         s->reg = data;
308         s->firstbyte = 0;
309     } else
310         twl4030_48_write(s, s->reg++, data);
311         
312     return 0;
313 }
314
315 static int twl4030_48_rx(i2c_slave *i2c)
316 {
317     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
318         
319     return twl4030_48_read(s, s->reg++);
320 }
321
322 static void twl4030_48_reset(i2c_slave *i2c)
323 {
324     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
325     s->reg = 0x00;
326     memcpy(s->reg_data, addr_48_reset_values, 256);
327 }
328
329 static void twl4030_48_event(i2c_slave *i2c, enum i2c_event event)
330 {
331     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
332     
333     if (event == I2C_START_SEND)
334         s->firstbyte = 1;
335 }
336
337 static uint8_t twl4030_49_read(void *opaque, uint8_t addr)
338 {
339     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
340
341     TRACE("addr=0x%02x", addr);
342     switch (addr) {
343         /* AUDIO_VOICE region */
344         case 0x01 ... 0x49:
345             return s->reg_data[addr];
346         /* Test region */
347         case 0x4c ... 0x60:
348             return s->reg_data[addr];
349         /* PIH region */
350         case 0x81: /* PIH_ISR_P1 */
351         case 0x82: /* PIH_ISR_P2 */
352         case 0x83: /* PIH_SIR */
353             return s->reg_data[addr];
354         /* INTBR region */
355         case 0x85 ... 0x97:
356             return s->reg_data[addr];
357         /* GPIO region */
358         case 0x98 ... 0xc5:
359             return s->reg_data[addr];
360         default:
361             fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
362                     __FUNCTION__, addr, cpu_single_env->regs[15]);
363                         break;
364     }
365     return 0;
366 }
367
368 static void twl4030_49_write(void *opaque, uint8_t addr, uint8_t value)
369 {
370     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
371         
372     TRACE("addr=0x%02x, value=0x%02x", addr, value);
373     switch (addr) {
374         /* AUDIO_VOICE region */
375         case 0x01 ... 0x49:
376             s->reg_data[addr] = value;
377             break;
378         /* Test region */
379         case 0x4c ... 0x59:
380             s->reg_data[addr] = value;
381             break;
382         case 0x5a ... 0x60:
383             /* read-only, ignore */
384             break;
385         /* PIH region */
386         case 0x81: /* PIH_ISR_P1 */
387         case 0x82: /* PIH_ISR_P2 */
388         case 0x83: /* PIH_SIR */
389             s->reg_data[addr] = value;
390             break;
391         /* INTBR region */
392         case 0x85 ... 0x90:
393             /* read-only, ignore */
394             break;
395         case 0x91 ... 0x97:
396             s->reg_data[addr] = value;
397             break;
398         /* GPIO region */
399         case 0x98 ... 0x9a:
400             /* read-only, ignore */
401             break;
402         case 0x9b ... 0xae:
403             s->reg_data[addr] = value;
404             break;
405         case 0xaf: /* GPIOPUPDCTR5 */
406             s->reg_data[addr] = value & 0x0f;
407             break;
408         case 0xb0 ... 0xb5:
409             s->reg_data[addr] = value;
410             break;
411             case 0xb6: /* GPIO_IMR3A */
412             s->reg_data[addr] = value & 0x03;
413             break;
414         case 0xb7 ... 0xc4:
415             s->reg_data[addr] = value;
416             break;
417             case 0xc5: /* GPIO_SIH_CTRL */
418             s->reg_data[addr] = value & 0x07;
419             break;
420         default:
421             fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
422                     __FUNCTION__, addr, cpu_single_env->regs[15]);
423             break;
424     }
425 }
426
427
428 static int twl4030_49_tx(i2c_slave *i2c, uint8_t data)
429 {
430     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
431     /* Interpret register address byte */
432     if (s->firstbyte) {
433         s->reg = data;
434         s->firstbyte = 0;
435     } else
436         twl4030_49_write(s, s->reg++, data);
437         
438     return 0;
439 }
440
441 static int twl4030_49_rx(i2c_slave *i2c)
442 {
443     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
444         
445     return twl4030_49_read(s, s->reg++);
446 }
447
448 static void twl4030_49_reset(i2c_slave *i2c)
449 {
450     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
451     s->reg = 0x00;
452     memcpy(s->reg_data, addr_49_reset_values, 256);
453 }
454
455 static void twl4030_49_event(i2c_slave *i2c, enum i2c_event event)
456 {
457     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
458         
459     if (event == I2C_START_SEND)
460         s->firstbyte = 1;
461 }
462
463 static uint8_t twl4030_4a_read(void *opaque, uint8_t addr)
464 {
465     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
466         
467     TRACE("addr=0x%02x", addr);
468     switch (addr) {
469         /* MADC region */
470         case 0x00 ... 0x3e:
471         case 0x41 ... 0x4e:
472         case 0x51 ... 0x67:
473             return s->reg_data[addr];
474         case 0x3f: /* GPCH4_LSB */
475         case 0x40: /* GPCH4_MSB */
476         case 0x4f: /* GPCH12_LSB */
477         case 0x50: /* GPCH12_MSB */
478             return 1;
479         /* MAIN_CHARGE region */
480         case 0x74 ... 0xa6:
481             return s->reg_data[addr];
482         /* Interrupt region */
483         case 0xb9 ... 0xc6:
484             return s->reg_data[addr];
485         /* KEYPAD region */
486         case 0xd2 ... 0xe9:
487             return s->reg_data[addr];
488         /* LED region */
489         case 0xee: /* LEDEN */
490             return s->reg_data[addr];
491         /* PWMA region */
492         case 0xef: /* PWMAON */
493         case 0xf0: /* PWMAOFF */
494             return s->reg_data[addr];
495         /* PWMB region */
496         case 0xf1: /* PWMBON */
497         case 0xf2: /* PWMBOFF */
498             return s->reg_data[addr];
499         /* PWM0 region */
500         case 0xf8: /* PWM0ON */
501         case 0xf9: /* PWM0OFF */
502             return s->reg_data[addr];
503         /* PWM1 region */
504         case 0xfb: /* PWM1ON */
505         case 0xfc: /* PWM1OFF */
506             return s->reg_data[addr];
507         default:
508                 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
509                     __FUNCTION__, addr, cpu_single_env->regs[15] );
510             break;
511     }
512     return 0;
513 }
514
515 static void twl4030_4a_write(void *opaque, uint8_t addr, uint8_t value)
516 {
517     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
518
519     TRACE("addr=0x%02x, value=0x%02x", addr, value);
520     switch (addr) {
521         case 0x00: /* CTRL1 */
522             s->reg_data[addr] = value;
523             break;
524         case 0x06: /* SW1SELECT_LSB */
525         case 0x07: /* SW1SELECT_MSB */
526         case 0x08: /* SW1AVERAGE_LSB */
527         case 0x09: /* SW1AVERAGE_MSB */
528             s->reg_data[addr] = value;
529             break;
530         case 0x12: /* CTRL_SW1 */
531             s->reg_data[addr] = 0xde;
532             break;
533         case 0x61: /* MADC_ISR1 */
534             s->reg_data[addr] &= ~(value & 0x0f);
535             break;
536         case 0x62: /* MADC_IMR1 */
537             s->reg_data[addr] = value & 0x0f;
538             break;
539         case 0x97: /* BCICTL1 */
540             s->reg_data[addr] = value;
541             break;
542         case 0xb9: /* BCIISR1A */
543             s->reg_data[addr] &= ~value;
544             break;
545         case 0xba: /* BCIISR2A */
546             s->reg_data[addr] &= ~(value & 0x0f);
547             break;
548         case 0xbb: /* BCIIMR1A */
549             s->reg_data[addr] = value;
550             break;
551         case 0xbc: /* BCIIMR2A */
552             s->reg_data[addr] = value & 0x0f;
553             break;
554         case 0xd2: /* KEYP_CTRL_REG */
555             s->reg_data[addr] = value & 0x7f;
556             break;
557         case 0xe4: /* KEYP_IMR1 */
558             s->reg_data[addr] = value & 0x0f;
559             break;
560         case 0xe9: /* KEYP_SIH_CTRL */
561             s->reg_data[addr] = value & 0x07;
562             break;
563         case 0xee: /* LEDEN */
564             s->reg_data[addr] = value;
565             TRACE("LEDA power=%s/enable=%s, LEDB power=%s/enable=%s",
566                     value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",
567                     value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");
568             break;
569         case 0xef: /* PWMAON */
570         case 0xf8: /* PWM0ON */
571         case 0xfb: /* PWM1ON */
572             s->reg_data[addr] = value;
573             break;
574         case 0xf0: /* PWMAOFF */
575         case 0xf9: /* PWM0OFF */
576         case 0xfc: /* PWM1OFF */
577             s->reg_data[addr] = value & 0x7f;
578             break;
579         default:
580                 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
581                     __FUNCTION__, addr, cpu_single_env->regs[15]);
582             break;
583     }
584 }
585
586 static int twl4030_4a_tx(i2c_slave *i2c, uint8_t data)
587 {
588     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
589     /* Interpret register address byte */
590     if (s->firstbyte) {
591         s->reg = data;
592         s->firstbyte = 0;
593     } else
594         twl4030_4a_write(s, s->reg++, data);
595         
596     return 0;
597 }
598
599 static int twl4030_4a_rx(i2c_slave *i2c)
600 {
601     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
602         
603     return twl4030_4a_read(s, s->reg++);
604 }
605
606 static void twl4030_4a_reset(i2c_slave *i2c)
607 {
608     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
609     s->reg = 0x00;
610     memcpy(s->reg_data, addr_4a_reset_values, 256);
611 }
612
613 static void twl4030_4a_event(i2c_slave *i2c, enum i2c_event event)
614 {
615     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
616         
617     if (event == I2C_START_SEND)
618         s->firstbyte = 1;
619 }
620
621 static uint8_t twl4030_4b_read(void *opaque, uint8_t addr)
622 {
623     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
624
625         TRACE("addr=0x%02x", addr);
626     switch (addr) {
627         /* SECURED_REG region */
628         case 0x00 ... 0x13:
629             return s->reg_data[addr];
630         /* BACKUP_REG region */
631         case 0x14 ... 0x1b:
632             return s->reg_data[addr];
633         /* RTC region */
634         case 0x1c ... 0x2d:
635             return s->reg_data[addr];
636         /* INT region */
637         case 0x2e ... 0x35:
638             return s->reg_data[addr];
639         /* PM_MASTER region */
640         case 0x36 ... 0x44:
641             return s->reg_data[addr];
642         case 0x45: /* STS_HW_CONDITIONS - USB plugged, no VBUS -> host usb */
643             return 0x4;
644         case 0x46 ... 0x5a:
645             return s->reg_data[addr];
646         /* PM_RECEIVER region */
647         case 0x5b ... 0xf1: 
648             return s->reg_data[addr];
649         default:
650                 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
651                     __FUNCTION__, addr, cpu_single_env->regs[15] );
652             break;
653     }
654     return 0;
655 }
656
657
658 static void twl4030_4b_write(void *opaque, uint8_t addr, uint8_t value)
659 {
660     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
661     uint8_t seq_addr, seq_sub;
662
663         TRACE("addr=0x%02x, value=0x%02x", addr, value);
664     switch (addr) {
665         case 0x1c: /* SECONDS_REG */
666         case 0x1d: /* MINUTES_REG */
667         case 0x23: /* ALARM_SECONDS_REG */
668         case 0x24: /* ALARM_MINUTES_REG */
669             s->reg_data[addr] = value & 0x7f;
670             break;
671         case 0x1e: /* HOURS_REG */
672         case 0x25: /* ALARM_HOURS_REG */
673             s->reg_data[addr] = value & 0xbf;
674             break;
675         case 0x1f: /* DAYS_REG */
676         case 0x26: /* ALARM_DAYS_REG */
677             s->reg_data[addr] = value & 0x3f;
678             break;
679         case 0x20: /* MONTHS_REG */
680         case 0x27: /* ALARM_MONTHS_REG */
681             s->reg_data[addr] = value & 0x1f;
682             break;
683         case 0x21: /* YEARS_REG */
684         case 0x28: /* ALARM_YEARS_REG */
685             s->reg_data[addr] = value;
686             break;
687         case 0x22: /* WEEKS_REG */
688             s->reg_data[addr] = value & 0x07;
689             break;
690         case 0x29: /* RTC_CTRL_REG */
691             s->reg_data[addr] = value & 0x7f;
692             break;
693         case 0x2a: /* RTC_STATUS_REG */
694             s->reg_data[addr] = value & 0xfe;
695             break;
696         case 0x2b: /* RTC_INTERRUPTS_REG */
697             s->reg_data[addr] = value & 0x0f;
698             break;
699         case 0x2c: /* RTC_COMP_LSB_REG */
700         case 0x2d: /* RTC_COMP_MSB_REG */
701             s->reg_data[addr] = value;
702             break;
703         case 0x2e: /* PWR_ISR1 */
704         case 0x2f: /* PWR_IMR1 */
705             s->reg_data[addr] = value;
706             break;
707         case 0x33: /* PWR_EDR1 */
708         case 0x34: /* PWR_EDR2 */
709             s->reg_data[addr] = value;
710             break;
711         case 0x35: /* PWR_SIH_CTRL */
712             s->reg_data[addr] = value & 0x07;
713             break;
714         case 0x3b: /* CFG_BOOT */
715             if (s->twl4030->key_cfg)
716                 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
717             break;
718         case 0x44: /* PROTECT_KEY */
719             s->twl4030->key_cfg = 0;
720             s->twl4030->key_tst = 0;
721             switch (value) {
722                 case 0x0C: 
723                     if (s->reg_data[addr] == 0xC0)
724                         s->twl4030->key_cfg = 1;
725                     break;
726                 case 0xE0:
727                     if (s->reg_data[addr] == 0x0E)
728                         s->twl4030->key_tst = 1;
729                     break;
730                 case 0xEC:
731                     if (s->reg_data[addr] == 0xCE) {
732                         s->twl4030->key_cfg = 1;
733                         s->twl4030->key_tst = 1;
734                     }
735                     break;
736                 default:
737                     break;
738             }
739             s->reg_data[addr] = value;
740             break;
741         case 0x46: /* P1_SW_EVENTS */
742         case 0x47: /* P2_SW_EVENTS */
743         case 0x48: /* P3_SW_EVENTS */
744             s->reg_data[addr] = value & 0x78;
745             break;
746         case 0x52: /* SEQ_ADD_W2P */
747         case 0x53: /* SEQ_ADD_P2A */
748         case 0x54: /* SEQ_ADD_A2W */
749         case 0x55: /* SEQ_ADD_A2S */
750         case 0x56: /* SEQ_ADD_S2A12 */
751         case 0x57: /* SEQ_ADD_S2A3 */
752         case 0x58: /* SEQ_ADD_WARM */
753             if (s->twl4030->key_cfg)
754                 s->reg_data[addr] = value & 0x3f;
755             break;
756         case 0x59: /* MEMORY_ADDRESS */
757             if (s->twl4030->key_cfg)
758                 s->reg_data[addr] = value;
759             break;
760         case 0x5a: /* MEMORY_DATA */
761             if (s->twl4030->key_cfg) {
762                 s->reg_data[addr] = value;
763                 seq_addr = s->reg_data[0x59];
764                 seq_sub = seq_addr & 3;
765                 seq_addr >>= 2;
766                 if ((seq_addr >= 0x2b && seq_addr <= 0x3e) ||
767                     (seq_addr <= 0x0e && seq_sub == 3))
768                     s->twl4030->seq_mem[seq_addr][seq_sub] = value;
769             }
770             /* TODO: check if autoincrement is write-protected as well */
771             s->reg_data[0x59]++; 
772             break;
773         case 0x68: /* MISC_CFG */
774             s->reg_data[addr] = value;
775             break;
776         case 0x7a: /* VAUX3_DEV_GRP */
777         case 0x82: /* VMMC1_DEV_GRP */
778         case 0x8e: /* VPLL2_DEV_GRP */
779         case 0x96: /* VDAC_DEV_GRP */
780         case 0xcc: /* VUSB1V5_DEV_GRP */
781         case 0xcf: /* VUSB1V8_DEV_GRP */
782         case 0xd2: /* VUSB3V1_DEV_GRP */
783         case 0xe6: /* HFCLKOUT_DEV_GRP */
784             s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0); 
785             break;
786         case 0x75: /* VAUX1_DEDICATED */
787         case 0x7d: /* VAUX3_DEDICATED */
788             if (s->twl4030->key_tst)
789                 s->reg_data[addr] = value & 0x77;
790             else
791                 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
792             break;
793         case 0x79: /* VAUX2_DEDICATED */
794         case 0x81: /* VAUX4_DEDICATED */
795         case 0x91: /* VPLL2_DEDICATED */
796             if (s->twl4030->key_tst)
797                 s->reg_data[addr] = value & 0x7f;
798             else
799                 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
800             break;
801         case 0x85: /* VMMC1_DEDICATED */
802         case 0x99: /* VDAC_DEDICATED */
803             if (s->twl4030->key_tst) 
804                 s->reg_data[addr] = value & 0x73;
805             else
806                 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
807             break;
808         case 0x74: /* VAUX1_REMAP */
809         case 0x78: /* VAUX2_REMAP */
810         case 0x7c: /* VAUX3_REMAP */
811         case 0x80: /* VAUX4_REMAP */
812         case 0x90: /* VPLL2_REMAP */
813             s->reg_data[addr] = value;
814             break;
815         case 0xcd: /* VUSB1V5_TYPE */
816         case 0xd0: /* VUSB1V8_TYPE */
817         case 0xd3: /* VUSB3V1_TYPE */
818             s->reg_data[addr] = value & 0x1f;
819             break;
820         case 0xd8: /* VUSB_DEDICATED1 */
821             s->reg_data[addr] = value & 0x1f;
822             break;
823         case 0xd9: /* VUSB_DEDICATED2 */
824             s->reg_data[addr] = value & 0x08;
825             break;
826             
827         default:
828                 fprintf(stderr,
829                     "%s: unknown register 0x%02x value 0x%02x pc 0x%x\n",
830                     __FUNCTION__, addr, value, cpu_single_env->regs[15]);
831             break;
832     }
833 }
834
835 static int twl4030_4b_tx(i2c_slave *i2c, uint8_t data)
836 {
837     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
838     /* Interpret register address byte */
839     if (s->firstbyte) {
840         s->reg = data;
841         s->firstbyte = 0;
842     } else
843         twl4030_4b_write(s, s->reg++, data);
844         
845     return 1;
846 }
847
848 static int twl4030_4b_rx(i2c_slave *i2c)
849 {
850     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
851         
852     return twl4030_4b_read(s, s->reg++);
853 }
854
855 static void twl4030_4b_reset(i2c_slave *i2c)
856 {
857     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
858     s->reg = 0x00;
859     memcpy(s->reg_data, addr_4b_reset_values, 256);
860     s->twl4030->key_cfg = 0;
861     s->twl4030->key_tst = 0;
862 }
863
864 static void twl4030_4b_event(i2c_slave *i2c, enum i2c_event event)
865 {
866     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
867         
868     if (event == I2C_START_SEND)
869         s->firstbyte = 1;
870 }
871
872 static void twl4030_save_state(QEMUFile *f, void *opaque)
873 {
874     struct twl4030_s *s = (struct twl4030_s *)opaque;
875     int i;
876     
877     qemu_put_sbe32(f, s->key_cfg);
878     qemu_put_sbe32(f, s->key_tst);
879     for (i = 0; i < 64; i++)
880         qemu_put_buffer(f, s->seq_mem[i], 4);
881     for (i = 0; i < 5; i++) {
882         qemu_put_sbe32(f, s->i2c[i]->firstbyte);
883         qemu_put_byte(f, s->i2c[i]->reg);
884         qemu_put_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
885     }
886 }
887
888 static int twl4030_load_state(QEMUFile *f, void *opaque, int version_id)
889 {
890     struct twl4030_s *s = (struct twl4030_s *)opaque;
891     int i;
892     
893     if (version_id)
894         return -EINVAL;
895     
896     s->key_cfg = qemu_get_sbe32(f);
897     s->key_tst = qemu_get_sbe32(f);
898     for (i = 0; i < 64; i++)
899         qemu_get_buffer(f, s->seq_mem[i], 4);
900     for (i = 0; i < 5; i++) {
901         s->i2c[i]->firstbyte = qemu_get_sbe32(f);
902         s->i2c[i]->reg = qemu_get_byte(f);
903         qemu_get_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
904     }
905     
906     return 0;
907 }
908
909 struct twl4030_s *twl4030_init(i2c_bus *bus, qemu_irq irq)
910 {
911     int i;
912         
913     struct twl4030_s *s = (struct twl4030_s *) qemu_mallocz(sizeof(*s));
914         
915     for (i = 0; i < 5; i++) {
916         s->i2c[i]=(struct twl4030_i2c_s *)i2c_slave_init(
917             bus, 0, sizeof(struct twl4030_i2c_s));
918         s->i2c[i]->irq = irq;
919         s->i2c[i]->twl4030 = s;
920     }
921     s->i2c[0]->i2c.event = twl4030_48_event;
922     s->i2c[0]->i2c.recv = twl4030_48_rx;
923     s->i2c[0]->i2c.send = twl4030_48_tx;
924     twl4030_48_reset(&s->i2c[0]->i2c);
925     i2c_set_slave_address((i2c_slave *)&s->i2c[0]->i2c,0x48);
926         
927     s->i2c[1]->i2c.event = twl4030_49_event;
928     s->i2c[1]->i2c.recv = twl4030_49_rx;
929     s->i2c[1]->i2c.send = twl4030_49_tx;
930     twl4030_49_reset(&s->i2c[1]->i2c);
931     i2c_set_slave_address((i2c_slave *)&s->i2c[1]->i2c,0x49);
932         
933     s->i2c[2]->i2c.event = twl4030_4a_event;
934     s->i2c[2]->i2c.recv = twl4030_4a_rx;
935     s->i2c[2]->i2c.send = twl4030_4a_tx;
936     twl4030_4a_reset(&s->i2c[2]->i2c);
937     i2c_set_slave_address((i2c_slave *)&s->i2c[2]->i2c,0x4a);
938         
939     s->i2c[3]->i2c.event = twl4030_4b_event;
940     s->i2c[3]->i2c.recv = twl4030_4b_rx;
941     s->i2c[3]->i2c.send = twl4030_4b_tx;
942     twl4030_4b_reset(&s->i2c[3]->i2c);
943     i2c_set_slave_address((i2c_slave *)&s->i2c[3]->i2c,0x4b);
944         
945     register_savevm("twl4030", -1, 0,
946                     twl4030_save_state, twl4030_load_state, s);
947
948     return s;
949 }