4 * Copyright (C) 2008 yajin<yajin@vm-kernel.org>
5 * Copyright (C) 2009 Nokia Corporation
7 * Register implementation based on TPS65950 ES1.0 specification.
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.
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.
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,
26 #include "qemu-timer.h"
35 #define TRACE(fmt, ...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
40 typedef struct TWL4030State TWL4030State;
41 typedef struct TWL4030NodeState TWL4030NodeState;
43 typedef uint8_t (*twl4030_read_func)(TWL4030NodeState *s,
45 typedef void (*twl4030_write_func)(TWL4030NodeState *s,
46 uint8_t addr, uint8_t value);
48 struct TWL4030NodeState {
53 twl4030_read_func read_func;
54 twl4030_write_func write_func;
55 TWL4030State *twl4030;
66 TWL4030NodeState *i2c[5];
68 uint8_t seq_mem[64][4]; /* power-management sequencing memory */
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 */
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 */
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 */
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 */
211 static uint8_t twl4030_48_read(TWL4030NodeState *s, uint8_t addr)
213 TRACE("addr=0x%02x", 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 */
238 if (s->reg_data[0xfe] & 1) /* REQ_PHY_DPLL_CLK */
240 return (s->reg_data[0x04] >> 6) & 1; /* SUSPENDM */
242 fprintf(stderr, "%s: unknown register 0x%02x\n",
249 static void twl4030_48_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
251 TRACE("addr=0x%02x, value=0x%02x", addr, value);
253 case 0x04: /* FUNC_CTRL */
254 s->reg_data[0x04] = value & 0x7f;
256 case 0x05: /* FUNC_CRTL_SET */
257 s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x7f;
259 case 0x06: /* FUNC_CTRL_CLEAR */
260 s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x7f;
262 case 0x07: /* IFC_CTRL */
263 s->reg_data[0x07] = value & 0x9e;
265 case 0x08: /* IFC_CRTL_SET */
266 s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x9e;
268 case 0x09: /* IFC_CRTL_CLEAR */
269 s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x9e;
271 case 0xa1: /* CARKIT_SM_CTRL */
272 s->reg_data[0xa1] = value & 0x3f;
274 case 0xa2: /* CARKIT_SM_CTRL_SET */
275 s->reg_data[0xa1] = (s->reg_data[0xa1] | value) & 0x3f;
277 case 0xa3: /* CARKIT_SM_CTRL_CLR */
278 s->reg_data[0xa1] = (s->reg_data[0xa1] & ~value) & 0x3f;
280 case 0xac: /* POWER_CTRL */
281 s->reg_data[0xac] = value & 0x20;
283 case 0xad: /* POWER_SET */
284 s->reg_data[0xac] = (s->reg_data[0xac] | value) & 0x20;
286 case 0xae: /* POWER_CLEAR */
287 s->reg_data[0xac] = (s->reg_data[0xac] & ~value) & 0x20;
289 case 0xbb: /* CARKIT_ANA_CTRL */
290 s->reg_data[0xbb] = value;
292 case 0xbc: /* CARKIT_ANA_CTRL_SET */
293 s->reg_data[0xbb] |= value;
295 case 0xbd: /* CARKIT_ANA_CTRL_CLR */
296 s->reg_data[0xbb] &= ~value;
298 case 0xfd: /* PHY_PWR_CTRL */
299 s->reg_data[addr] = value & 0x1;
301 case 0xfe: /* PHY_CLK_CTRL */
302 s->reg_data[addr] = value & 0x7;
305 fprintf(stderr, "%s: unknown register 0x%02x\n",
311 static uint8_t twl4030_49_read(TWL4030NodeState *s, uint8_t addr)
313 TRACE("addr=0x%02x", addr);
315 /* AUDIO_VOICE region */
317 return s->reg_data[addr];
320 return s->reg_data[addr];
322 case 0x81: /* PIH_ISR_P1 */
323 case 0x82: /* PIH_ISR_P2 */
324 case 0x83: /* PIH_SIR */
325 return s->reg_data[addr];
328 return s->reg_data[addr];
331 return s->reg_data[addr];
333 fprintf(stderr, "%s: unknown register 0x%02x\n",
340 static void twl4030_49_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
342 TRACE("addr=0x%02x, value=0x%02x", addr, value);
344 /* AUDIO_VOICE region */
346 s->reg_data[addr] = value;
350 s->reg_data[addr] = value;
353 /* read-only, ignore */
356 case 0x81: /* PIH_ISR_P1 */
357 case 0x82: /* PIH_ISR_P2 */
358 case 0x83: /* PIH_SIR */
359 s->reg_data[addr] = value;
363 /* read-only, ignore */
366 s->reg_data[addr] = value;
370 /* read-only, ignore */
373 s->reg_data[addr] = value;
375 case 0xaf: /* GPIOPUPDCTR5 */
376 s->reg_data[addr] = value & 0x0f;
379 s->reg_data[addr] = value;
381 case 0xb6: /* GPIO_IMR3A */
382 s->reg_data[addr] = value & 0x03;
385 s->reg_data[addr] = value;
387 case 0xc5: /* GPIO_SIH_CTRL */
388 s->reg_data[addr] = value & 0x07;
391 fprintf(stderr, "%s: unknown register 0x%02x\n",
397 static uint8_t twl4030_4a_read(TWL4030NodeState *s, uint8_t addr)
399 TRACE("addr=0x%02x", addr);
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 */
411 return s->reg_data[addr];
412 /* Interrupt region */
414 return s->reg_data[addr];
417 return s->reg_data[addr];
419 case 0xee: /* LEDEN */
420 return s->reg_data[addr];
422 case 0xef: /* PWMAON */
423 case 0xf0: /* PWMAOFF */
424 return s->reg_data[addr];
426 case 0xf1: /* PWMBON */
427 case 0xf2: /* PWMBOFF */
428 return s->reg_data[addr];
430 case 0xf8: /* PWM0ON */
431 case 0xf9: /* PWM0OFF */
432 return s->reg_data[addr];
434 case 0xfb: /* PWM1ON */
435 case 0xfc: /* PWM1OFF */
436 return s->reg_data[addr];
438 fprintf(stderr, "%s: unknown register 0x%02x\n",
445 static void twl4030_4a_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
447 TRACE("addr=0x%02x, value=0x%02x", addr, value);
449 case 0x00: /* CTRL1 */
450 s->reg_data[addr] = value;
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;
458 case 0x12: /* CTRL_SW1 */
459 s->reg_data[addr] = 0xde;
461 case 0x61: /* MADC_ISR1 */
462 s->reg_data[addr] &= ~(value & 0x0f);
464 case 0x62: /* MADC_IMR1 */
465 s->reg_data[addr] = value & 0x0f;
467 case 0x97: /* BCICTL1 */
468 s->reg_data[addr] = value;
470 case 0xb9: /* BCIISR1A */
471 s->reg_data[addr] &= ~value;
473 case 0xba: /* BCIISR2A */
474 s->reg_data[addr] &= ~(value & 0x0f);
476 case 0xbb: /* BCIIMR1A */
477 s->reg_data[addr] = value;
479 case 0xbc: /* BCIIMR2A */
480 s->reg_data[addr] = value & 0x0f;
482 case 0xd2: /* KEYP_CTRL_REG */
483 s->reg_data[addr] = value & 0x7f;
485 case 0xe4: /* KEYP_IMR1 */
486 s->reg_data[addr] = value & 0x0f;
488 case 0xe9: /* KEYP_SIH_CTRL */
489 s->reg_data[addr] = value & 0x07;
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");
497 case 0xef: /* PWMAON */
498 case 0xf8: /* PWM0ON */
499 case 0xfb: /* PWM1ON */
500 s->reg_data[addr] = value;
502 case 0xf0: /* PWMAOFF */
503 case 0xf9: /* PWM0OFF */
504 case 0xfc: /* PWM1OFF */
505 s->reg_data[addr] = value & 0x7f;
508 fprintf(stderr, "%s: unknown register 0x%02x\n",
514 static uint8_t twl4030_4b_read(TWL4030NodeState *s, uint8_t addr)
516 TRACE("addr=0x%02x", addr);
518 /* SECURED_REG region */
520 return s->reg_data[addr];
521 /* BACKUP_REG region */
523 return s->reg_data[addr];
526 return s->reg_data[addr];
529 return s->reg_data[addr];
530 /* PM_MASTER region */
532 return s->reg_data[addr];
533 case 0x45: /* STS_HW_CONDITIONS - USB plugged, no VBUS -> host usb */
536 return s->reg_data[addr];
537 /* PM_RECEIVER region */
539 return s->reg_data[addr];
541 fprintf(stderr, "%s: unknown register 0x%02x\n",
549 static void twl4030_4b_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
551 uint8_t seq_addr, seq_sub;
553 TRACE("addr=0x%02x, value=0x%02x", addr, value);
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;
561 case 0x1e: /* HOURS_REG */
562 case 0x25: /* ALARM_HOURS_REG */
563 s->reg_data[addr] = value & 0xbf;
565 case 0x1f: /* DAYS_REG */
566 case 0x26: /* ALARM_DAYS_REG */
567 s->reg_data[addr] = value & 0x3f;
569 case 0x20: /* MONTHS_REG */
570 case 0x27: /* ALARM_MONTHS_REG */
571 s->reg_data[addr] = value & 0x1f;
573 case 0x21: /* YEARS_REG */
574 case 0x28: /* ALARM_YEARS_REG */
575 s->reg_data[addr] = value;
577 case 0x22: /* WEEKS_REG */
578 s->reg_data[addr] = value & 0x07;
580 case 0x29: /* RTC_CTRL_REG */
581 s->reg_data[addr] = value & 0x7f;
583 case 0x2a: /* RTC_STATUS_REG */
584 s->reg_data[addr] = value & 0xfe;
586 case 0x2b: /* RTC_INTERRUPTS_REG */
587 s->reg_data[addr] = value & 0x0f;
589 case 0x2c: /* RTC_COMP_LSB_REG */
590 case 0x2d: /* RTC_COMP_MSB_REG */
591 s->reg_data[addr] = value;
593 case 0x2e: /* PWR_ISR1 */
594 case 0x2f: /* PWR_IMR1 */
595 s->reg_data[addr] = value;
597 case 0x33: /* PWR_EDR1 */
598 case 0x34: /* PWR_EDR2 */
599 s->reg_data[addr] = value;
601 case 0x35: /* PWR_SIH_CTRL */
602 s->reg_data[addr] = value & 0x07;
604 case 0x3b: /* CFG_BOOT */
605 if (s->twl4030->key_cfg)
606 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
608 case 0x44: /* PROTECT_KEY */
609 s->twl4030->key_cfg = 0;
610 s->twl4030->key_tst = 0;
613 if (s->reg_data[addr] == 0xC0)
614 s->twl4030->key_cfg = 1;
617 if (s->reg_data[addr] == 0x0E)
618 s->twl4030->key_tst = 1;
621 if (s->reg_data[addr] == 0xCE) {
622 s->twl4030->key_cfg = 1;
623 s->twl4030->key_tst = 1;
629 s->reg_data[addr] = value;
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;
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;
651 case 0x59: /* MEMORY_ADDRESS */
652 if (s->twl4030->key_cfg)
653 s->reg_data[addr] = value;
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;
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;
665 /* TODO: check if autoincrement is write-protected as well */
668 case 0x5e: /* WATCHDOG_CFG */
669 s->reg_data[addr] = value & 0x1f;
670 case 0x68: /* MISC_CFG */
671 s->reg_data[addr] = value;
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);
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;
692 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
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;
700 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
702 case 0x85: /* VMMC1_DEDICATED */
703 case 0x99: /* VDAC_DEDICATED */
704 if (s->twl4030->key_tst)
705 s->reg_data[addr] = value & 0x73;
707 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
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;
716 case 0xcd: /* VUSB1V5_TYPE */
717 case 0xd0: /* VUSB1V8_TYPE */
718 case 0xd3: /* VUSB3V1_TYPE */
719 s->reg_data[addr] = value & 0x1f;
721 case 0xd8: /* VUSB_DEDICATED1 */
722 s->reg_data[addr] = value & 0x1f;
724 case 0xd9: /* VUSB_DEDICATED2 */
725 s->reg_data[addr] = value & 0x08;
730 "%s: unknown register 0x%02x value 0x%02x\n",
731 __FUNCTION__, addr, value);
736 static void twl4030_node_init(TWL4030NodeState *s,
737 twl4030_read_func read,
738 twl4030_write_func write,
739 const uint8_t *reset_values)
742 s->write_func = write;
744 memcpy(s->reg_data, reset_values, 256);
747 static void twl4030_48_init(i2c_slave *i2c)
749 twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
750 twl4030_48_read, twl4030_48_write,
751 addr_48_reset_values);
754 static void twl4030_49_init(i2c_slave *i2c)
756 twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
757 twl4030_49_read, twl4030_49_write,
758 addr_49_reset_values);
761 static void twl4030_4a_init(i2c_slave *i2c)
763 twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
764 twl4030_4a_read, twl4030_4a_write,
765 addr_4a_reset_values);
768 static void twl4030_4b_init(i2c_slave *i2c)
770 twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
771 twl4030_4b_read, twl4030_4b_write,
772 addr_4b_reset_values);
775 static void twl4030_event(i2c_slave *i2c, enum i2c_event event)
777 if (event == I2C_START_SEND) {
778 TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
783 static int twl4030_rx(i2c_slave *i2c)
785 TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
786 return s->read_func(s, s->reg++);
789 static int twl4030_tx(i2c_slave *i2c, uint8_t data)
791 TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
796 s->write_func(s, s->reg++, data);
801 static void twl4030_save_state(QEMUFile *f, void *opaque)
803 TWL4030State *s = (TWL4030State *)opaque;
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));
817 static int twl4030_load_state(QEMUFile *f, void *opaque, int version_id)
819 TWL4030State *s = (TWL4030State *)opaque;
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));
838 void *twl4030_init(i2c_bus *gp_bus, qemu_irq irq)
840 TWL4030State *s = (TWL4030State *)qemu_mallocz(sizeof(*s));
847 for (i = 0; i < 4; i++) {
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;
855 register_savevm("twl4030", -1, 0,
856 twl4030_save_state, twl4030_load_state, s);
861 static I2CSlaveInfo twl4030_info[4] = {
863 .init = twl4030_48_init,
864 .event = twl4030_event,
869 .init = twl4030_49_init,
870 .event = twl4030_event,
875 .init = twl4030_4a_init,
876 .event = twl4030_event,
881 .init = twl4030_4b_init,
882 .event = twl4030_event,
888 static void twl4030_register_devices(void)
890 I2CSlaveInfo *p = twl4030_info;
892 for (i = 0; i < 4; p++, i++) {
894 sprintf(name, "twl4030_id%d", i + 1);
895 i2c_register_slave(name, sizeof(TWL4030NodeState), p);
899 device_init(twl4030_register_devices);