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 struct twl4030_i2c_s {
46 struct twl4030_s *twl4030;
50 struct twl4030_i2c_s *i2c[5];
55 uint8_t seq_mem[64][4]; /* power-management sequencing memory */
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 */
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 */
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 */
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, 0x60, 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 */
198 static uint8_t twl4030_48_read(void *opaque, uint8_t addr)
200 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
202 TRACE("addr=0x%02x", 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 */
227 if (s->reg_data[0xfe] & 1) /* REQ_PHY_DPLL_CLK */
229 return (s->reg_data[0x04] >> 6) & 1; /* SUSPENDM */
231 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
232 __FUNCTION__, addr, cpu_single_env->regs[15]);
238 static void twl4030_48_write(void *opaque, uint8_t addr, uint8_t value)
240 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
242 TRACE("addr=0x%02x, value=0x%02x", addr, value);
244 case 0x04: /* FUNC_CTRL */
245 s->reg_data[0x04] = value & 0x7f;
247 case 0x05: /* FUNC_CRTL_SET */
248 s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x7f;
250 case 0x06: /* FUNC_CTRL_CLEAR */
251 s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x7f;
253 case 0x07: /* IFC_CTRL */
254 s->reg_data[0x07] = value & 0x9e;
256 case 0x08: /* IFC_CRTL_SET */
257 s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x9e;
259 case 0x09: /* IFC_CRTL_CLEAR */
260 s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x9e;
262 case 0xa1: /* CARKIT_SM_CTRL */
263 s->reg_data[0xa1] = value & 0x3f;
265 case 0xa2: /* CARKIT_SM_CTRL_SET */
266 s->reg_data[0xa1] = (s->reg_data[0xa1] | value) & 0x3f;
268 case 0xa3: /* CARKIT_SM_CTRL_CLR */
269 s->reg_data[0xa1] = (s->reg_data[0xa1] & ~value) & 0x3f;
271 case 0xac: /* POWER_CTRL */
272 s->reg_data[0xac] = value & 0x20;
274 case 0xad: /* POWER_SET */
275 s->reg_data[0xac] = (s->reg_data[0xac] | value) & 0x20;
277 case 0xae: /* POWER_CLEAR */
278 s->reg_data[0xac] = (s->reg_data[0xac] & ~value) & 0x20;
280 case 0xbb: /* CARKIT_ANA_CTRL */
281 s->reg_data[0xbb] = value;
283 case 0xbc: /* CARKIT_ANA_CTRL_SET */
284 s->reg_data[0xbb] |= value;
286 case 0xbd: /* CARKIT_ANA_CTRL_CLR */
287 s->reg_data[0xbb] &= ~value;
289 case 0xfd: /* PHY_PWR_CTRL */
290 s->reg_data[addr] = value & 0x1;
292 case 0xfe: /* PHY_CLK_CTRL */
293 s->reg_data[addr] = value & 0x7;
296 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
297 __FUNCTION__, addr, cpu_single_env->regs[15]);
302 static int twl4030_48_tx(i2c_slave *i2c, uint8_t data)
304 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
305 /* Interpret register address byte */
310 twl4030_48_write(s, s->reg++, data);
315 static int twl4030_48_rx(i2c_slave *i2c)
317 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
319 return twl4030_48_read(s, s->reg++);
322 static void twl4030_48_reset(i2c_slave *i2c)
324 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
326 memcpy(s->reg_data, addr_48_reset_values, 256);
329 static void twl4030_48_event(i2c_slave *i2c, enum i2c_event event)
331 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
333 if (event == I2C_START_SEND)
337 static uint8_t twl4030_49_read(void *opaque, uint8_t addr)
339 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
341 TRACE("addr=0x%02x", addr);
343 /* AUDIO_VOICE region */
345 return s->reg_data[addr];
348 return s->reg_data[addr];
350 case 0x81: /* PIH_ISR_P1 */
351 case 0x82: /* PIH_ISR_P2 */
352 case 0x83: /* PIH_SIR */
353 return s->reg_data[addr];
356 return s->reg_data[addr];
359 return s->reg_data[addr];
361 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
362 __FUNCTION__, addr, cpu_single_env->regs[15]);
368 static void twl4030_49_write(void *opaque, uint8_t addr, uint8_t value)
370 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
372 TRACE("addr=0x%02x, value=0x%02x", addr, value);
374 /* AUDIO_VOICE region */
376 s->reg_data[addr] = value;
380 s->reg_data[addr] = value;
383 /* read-only, ignore */
386 case 0x81: /* PIH_ISR_P1 */
387 case 0x82: /* PIH_ISR_P2 */
388 case 0x83: /* PIH_SIR */
389 s->reg_data[addr] = value;
393 /* read-only, ignore */
396 s->reg_data[addr] = value;
400 /* read-only, ignore */
403 s->reg_data[addr] = value;
405 case 0xaf: /* GPIOPUPDCTR5 */
406 s->reg_data[addr] = value & 0x0f;
409 s->reg_data[addr] = value;
411 case 0xb6: /* GPIO_IMR3A */
412 s->reg_data[addr] = value & 0x03;
415 s->reg_data[addr] = value;
417 case 0xc5: /* GPIO_SIH_CTRL */
418 s->reg_data[addr] = value & 0x07;
421 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
422 __FUNCTION__, addr, cpu_single_env->regs[15]);
428 static int twl4030_49_tx(i2c_slave *i2c, uint8_t data)
430 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
431 /* Interpret register address byte */
436 twl4030_49_write(s, s->reg++, data);
441 static int twl4030_49_rx(i2c_slave *i2c)
443 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
445 return twl4030_49_read(s, s->reg++);
448 static void twl4030_49_reset(i2c_slave *i2c)
450 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
452 memcpy(s->reg_data, addr_49_reset_values, 256);
455 static void twl4030_49_event(i2c_slave *i2c, enum i2c_event event)
457 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
459 if (event == I2C_START_SEND)
463 static uint8_t twl4030_4a_read(void *opaque, uint8_t addr)
465 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
467 TRACE("addr=0x%02x", addr);
472 return s->reg_data[addr];
473 case 0x17 ... 0x36: /* RT conversion registers */
474 case 0x37 ... 0x56: /* GP conversion registers */
475 case 0x57 ... 0x60: /* BCI conversion registers */
476 return (addr & 1) ? 0 : 0x60;
477 /* MAIN_CHARGE region */
479 return s->reg_data[addr];
480 /* Interrupt region */
482 return s->reg_data[addr];
485 return s->reg_data[addr];
487 case 0xee: /* LEDEN */
488 return s->reg_data[addr];
490 case 0xef: /* PWMAON */
491 case 0xf0: /* PWMAOFF */
492 return s->reg_data[addr];
494 case 0xf1: /* PWMBON */
495 case 0xf2: /* PWMBOFF */
496 return s->reg_data[addr];
498 case 0xf8: /* PWM0ON */
499 case 0xf9: /* PWM0OFF */
500 return s->reg_data[addr];
502 case 0xfb: /* PWM1ON */
503 case 0xfc: /* PWM1OFF */
504 return s->reg_data[addr];
506 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
507 __FUNCTION__, addr, cpu_single_env->regs[15] );
513 static void twl4030_4a_write(void *opaque, uint8_t addr, uint8_t value)
515 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
517 TRACE("addr=0x%02x, value=0x%02x", addr, value);
519 case 0x00: /* CTRL1 */
520 s->reg_data[addr] = value;
522 case 0x06: /* SW1SELECT_LSB */
523 case 0x07: /* SW1SELECT_MSB */
524 case 0x08: /* SW1AVERAGE_LSB */
525 case 0x09: /* SW1AVERAGE_MSB */
526 s->reg_data[addr] = value;
528 case 0x12: /* CTRL_SW1 */
529 s->reg_data[addr] = 0xde;
531 case 0x61: /* MADC_ISR1 */
532 s->reg_data[addr] &= ~(value & 0x0f);
534 case 0x62: /* MADC_IMR1 */
535 s->reg_data[addr] = value & 0x0f;
537 case 0x97: /* BCICTL1 */
538 s->reg_data[addr] = value;
540 case 0xb9: /* BCIISR1A */
541 s->reg_data[addr] &= ~value;
543 case 0xba: /* BCIISR2A */
544 s->reg_data[addr] &= ~(value & 0x0f);
546 case 0xbb: /* BCIIMR1A */
547 s->reg_data[addr] = value;
549 case 0xbc: /* BCIIMR2A */
550 s->reg_data[addr] = value & 0x0f;
552 case 0xd2: /* KEYP_CTRL_REG */
553 s->reg_data[addr] = value & 0x7f;
555 case 0xe4: /* KEYP_IMR1 */
556 s->reg_data[addr] = value & 0x0f;
558 case 0xe9: /* KEYP_SIH_CTRL */
559 s->reg_data[addr] = value & 0x07;
561 case 0xee: /* LEDEN */
562 s->reg_data[addr] = value;
563 TRACE("LEDA power=%s/enable=%s, LEDB power=%s/enable=%s",
564 value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",
565 value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");
567 case 0xef: /* PWMAON */
568 case 0xf8: /* PWM0ON */
569 case 0xfb: /* PWM1ON */
570 s->reg_data[addr] = value;
572 case 0xf0: /* PWMAOFF */
573 case 0xf9: /* PWM0OFF */
574 case 0xfc: /* PWM1OFF */
575 s->reg_data[addr] = value & 0x7f;
578 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
579 __FUNCTION__, addr, cpu_single_env->regs[15]);
584 static int twl4030_4a_tx(i2c_slave *i2c, uint8_t data)
586 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
587 /* Interpret register address byte */
592 twl4030_4a_write(s, s->reg++, data);
597 static int twl4030_4a_rx(i2c_slave *i2c)
599 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
601 return twl4030_4a_read(s, s->reg++);
604 static void twl4030_4a_reset(i2c_slave *i2c)
606 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
608 memcpy(s->reg_data, addr_4a_reset_values, 256);
611 static void twl4030_4a_event(i2c_slave *i2c, enum i2c_event event)
613 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
615 if (event == I2C_START_SEND)
619 static uint8_t twl4030_4b_read(void *opaque, uint8_t addr)
621 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
623 TRACE("addr=0x%02x", addr);
625 /* SECURED_REG region */
627 return s->reg_data[addr];
628 /* BACKUP_REG region */
630 return s->reg_data[addr];
633 return s->reg_data[addr];
636 return s->reg_data[addr];
637 /* PM_MASTER region */
639 return s->reg_data[addr];
640 case 0x45: /* STS_HW_CONDITIONS - USB plugged, no VBUS -> host usb */
643 return s->reg_data[addr];
644 /* PM_RECEIVER region */
646 return s->reg_data[addr];
648 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
649 __FUNCTION__, addr, cpu_single_env->regs[15] );
656 static void twl4030_4b_write(void *opaque, uint8_t addr, uint8_t value)
658 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
659 uint8_t seq_addr, seq_sub;
661 TRACE("addr=0x%02x, value=0x%02x", addr, value);
663 case 0x1c: /* SECONDS_REG */
664 case 0x1d: /* MINUTES_REG */
665 case 0x23: /* ALARM_SECONDS_REG */
666 case 0x24: /* ALARM_MINUTES_REG */
667 s->reg_data[addr] = value & 0x7f;
669 case 0x1e: /* HOURS_REG */
670 case 0x25: /* ALARM_HOURS_REG */
671 s->reg_data[addr] = value & 0xbf;
673 case 0x1f: /* DAYS_REG */
674 case 0x26: /* ALARM_DAYS_REG */
675 s->reg_data[addr] = value & 0x3f;
677 case 0x20: /* MONTHS_REG */
678 case 0x27: /* ALARM_MONTHS_REG */
679 s->reg_data[addr] = value & 0x1f;
681 case 0x21: /* YEARS_REG */
682 case 0x28: /* ALARM_YEARS_REG */
683 s->reg_data[addr] = value;
685 case 0x22: /* WEEKS_REG */
686 s->reg_data[addr] = value & 0x07;
688 case 0x29: /* RTC_CTRL_REG */
689 s->reg_data[addr] = value & 0x7f;
691 case 0x2a: /* RTC_STATUS_REG */
692 s->reg_data[addr] = value & 0xfe;
694 case 0x2b: /* RTC_INTERRUPTS_REG */
695 s->reg_data[addr] = value & 0x0f;
697 case 0x2c: /* RTC_COMP_LSB_REG */
698 case 0x2d: /* RTC_COMP_MSB_REG */
699 s->reg_data[addr] = value;
701 case 0x2e: /* PWR_ISR1 */
702 case 0x2f: /* PWR_IMR1 */
703 s->reg_data[addr] = value;
705 case 0x33: /* PWR_EDR1 */
706 case 0x34: /* PWR_EDR2 */
707 s->reg_data[addr] = value;
709 case 0x35: /* PWR_SIH_CTRL */
710 s->reg_data[addr] = value & 0x07;
712 case 0x3b: /* CFG_BOOT */
713 if (s->twl4030->key_cfg)
714 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
716 case 0x44: /* PROTECT_KEY */
717 s->twl4030->key_cfg = 0;
718 s->twl4030->key_tst = 0;
721 if (s->reg_data[addr] == 0xC0)
722 s->twl4030->key_cfg = 1;
725 if (s->reg_data[addr] == 0x0E)
726 s->twl4030->key_tst = 1;
729 if (s->reg_data[addr] == 0xCE) {
730 s->twl4030->key_cfg = 1;
731 s->twl4030->key_tst = 1;
737 s->reg_data[addr] = value;
739 case 0x46: /* P1_SW_EVENTS */
740 case 0x47: /* P2_SW_EVENTS */
741 case 0x48: /* P3_SW_EVENTS */
742 s->reg_data[addr] = value & 0x78;
744 case 0x52: /* SEQ_ADD_W2P */
745 case 0x53: /* SEQ_ADD_P2A */
746 case 0x54: /* SEQ_ADD_A2W */
747 case 0x55: /* SEQ_ADD_A2S */
748 case 0x56: /* SEQ_ADD_S2A12 */
749 case 0x57: /* SEQ_ADD_S2A3 */
750 case 0x58: /* SEQ_ADD_WARM */
751 if (s->twl4030->key_cfg)
752 s->reg_data[addr] = value & 0x3f;
754 case 0x59: /* MEMORY_ADDRESS */
755 if (s->twl4030->key_cfg)
756 s->reg_data[addr] = value;
758 case 0x5a: /* MEMORY_DATA */
759 if (s->twl4030->key_cfg) {
760 s->reg_data[addr] = value;
761 seq_addr = s->reg_data[0x59];
762 seq_sub = seq_addr & 3;
764 if ((seq_addr >= 0x2b && seq_addr <= 0x3e) ||
765 (seq_addr <= 0x0e && seq_sub == 3))
766 s->twl4030->seq_mem[seq_addr][seq_sub] = value;
768 /* TODO: check if autoincrement is write-protected as well */
771 case 0x68: /* MISC_CFG */
772 s->reg_data[addr] = value;
774 case 0x7a: /* VAUX3_DEV_GRP */
775 case 0x82: /* VMMC1_DEV_GRP */
776 case 0x8e: /* VPLL2_DEV_GRP */
777 case 0x96: /* VDAC_DEV_GRP */
778 case 0xcc: /* VUSB1V5_DEV_GRP */
779 case 0xcf: /* VUSB1V8_DEV_GRP */
780 case 0xd2: /* VUSB3V1_DEV_GRP */
781 case 0xe6: /* HFCLKOUT_DEV_GRP */
782 s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0);
784 case 0x75: /* VAUX1_DEDICATED */
785 case 0x7d: /* VAUX3_DEDICATED */
786 if (s->twl4030->key_tst)
787 s->reg_data[addr] = value & 0x77;
789 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
791 case 0x79: /* VAUX2_DEDICATED */
792 case 0x81: /* VAUX4_DEDICATED */
793 case 0x91: /* VPLL2_DEDICATED */
794 if (s->twl4030->key_tst)
795 s->reg_data[addr] = value & 0x7f;
797 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
799 case 0x85: /* VMMC1_DEDICATED */
800 case 0x99: /* VDAC_DEDICATED */
801 if (s->twl4030->key_tst)
802 s->reg_data[addr] = value & 0x73;
804 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
806 case 0x74: /* VAUX1_REMAP */
807 case 0x78: /* VAUX2_REMAP */
808 case 0x7c: /* VAUX3_REMAP */
809 case 0x80: /* VAUX4_REMAP */
810 case 0x90: /* VPLL2_REMAP */
811 s->reg_data[addr] = value;
813 case 0xcd: /* VUSB1V5_TYPE */
814 case 0xd0: /* VUSB1V8_TYPE */
815 case 0xd3: /* VUSB3V1_TYPE */
816 s->reg_data[addr] = value & 0x1f;
818 case 0xd8: /* VUSB_DEDICATED1 */
819 s->reg_data[addr] = value & 0x1f;
821 case 0xd9: /* VUSB_DEDICATED2 */
822 s->reg_data[addr] = value & 0x08;
827 "%s: unknown register 0x%02x value 0x%02x pc 0x%x\n",
828 __FUNCTION__, addr, value, cpu_single_env->regs[15]);
833 static int twl4030_4b_tx(i2c_slave *i2c, uint8_t data)
835 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
836 /* Interpret register address byte */
841 twl4030_4b_write(s, s->reg++, data);
846 static int twl4030_4b_rx(i2c_slave *i2c)
848 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
850 return twl4030_4b_read(s, s->reg++);
853 static void twl4030_4b_reset(i2c_slave *i2c)
855 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
857 memcpy(s->reg_data, addr_4b_reset_values, 256);
858 s->twl4030->key_cfg = 0;
859 s->twl4030->key_tst = 0;
862 static void twl4030_4b_event(i2c_slave *i2c, enum i2c_event event)
864 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
866 if (event == I2C_START_SEND)
870 static void twl4030_save_state(QEMUFile *f, void *opaque)
872 struct twl4030_s *s = (struct twl4030_s *)opaque;
875 qemu_put_sbe32(f, s->key_cfg);
876 qemu_put_sbe32(f, s->key_tst);
877 for (i = 0; i < 64; i++)
878 qemu_put_buffer(f, s->seq_mem[i], 4);
879 for (i = 0; i < 5; i++) {
880 qemu_put_sbe32(f, s->i2c[i]->firstbyte);
881 qemu_put_byte(f, s->i2c[i]->reg);
882 qemu_put_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
886 static int twl4030_load_state(QEMUFile *f, void *opaque, int version_id)
888 struct twl4030_s *s = (struct twl4030_s *)opaque;
894 s->key_cfg = qemu_get_sbe32(f);
895 s->key_tst = qemu_get_sbe32(f);
896 for (i = 0; i < 64; i++)
897 qemu_get_buffer(f, s->seq_mem[i], 4);
898 for (i = 0; i < 5; i++) {
899 s->i2c[i]->firstbyte = qemu_get_sbe32(f);
900 s->i2c[i]->reg = qemu_get_byte(f);
901 qemu_get_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
907 struct twl4030_s *twl4030_init(i2c_bus *bus, qemu_irq irq)
911 struct twl4030_s *s = (struct twl4030_s *) qemu_mallocz(sizeof(*s));
913 for (i = 0; i < 5; i++) {
914 s->i2c[i]=(struct twl4030_i2c_s *)i2c_slave_init(
915 bus, 0, sizeof(struct twl4030_i2c_s));
916 s->i2c[i]->irq = irq;
917 s->i2c[i]->twl4030 = s;
919 s->i2c[0]->i2c.event = twl4030_48_event;
920 s->i2c[0]->i2c.recv = twl4030_48_rx;
921 s->i2c[0]->i2c.send = twl4030_48_tx;
922 twl4030_48_reset(&s->i2c[0]->i2c);
923 i2c_set_slave_address((i2c_slave *)&s->i2c[0]->i2c,0x48);
925 s->i2c[1]->i2c.event = twl4030_49_event;
926 s->i2c[1]->i2c.recv = twl4030_49_rx;
927 s->i2c[1]->i2c.send = twl4030_49_tx;
928 twl4030_49_reset(&s->i2c[1]->i2c);
929 i2c_set_slave_address((i2c_slave *)&s->i2c[1]->i2c,0x49);
931 s->i2c[2]->i2c.event = twl4030_4a_event;
932 s->i2c[2]->i2c.recv = twl4030_4a_rx;
933 s->i2c[2]->i2c.send = twl4030_4a_tx;
934 twl4030_4a_reset(&s->i2c[2]->i2c);
935 i2c_set_slave_address((i2c_slave *)&s->i2c[2]->i2c,0x4a);
937 s->i2c[3]->i2c.event = twl4030_4b_event;
938 s->i2c[3]->i2c.recv = twl4030_4b_rx;
939 s->i2c[3]->i2c.send = twl4030_4b_tx;
940 twl4030_4b_reset(&s->i2c[3]->i2c);
941 i2c_set_slave_address((i2c_slave *)&s->i2c[3]->i2c,0x4b);
943 register_savevm("twl4030", -1, 0,
944 twl4030_save_state, twl4030_load_state, s);