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