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, 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 */
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: /* IFC_CTRL */
245 s->reg_data[0x04] = value & 0x80;
247 case 0x05: /* IFC_CRTL_SET */
248 s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x80;
250 case 0x06: /* IFC_CRTL_CLEAR */
251 s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x80;
253 case 0x07: /* IFC_CTRL */
254 s->reg_data[0x07] = value & 0x61;
256 case 0x08: /* IFC_CRTL_SET */
257 s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x61;
259 case 0x09: /* IFC_CRTL_CLEAR */
260 s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x61;
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);
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 */
479 /* MAIN_CHARGE region */
481 return s->reg_data[addr];
482 /* Interrupt region */
484 return s->reg_data[addr];
487 return s->reg_data[addr];
489 case 0xee: /* LEDEN */
490 return s->reg_data[addr];
492 case 0xef: /* PWMAON */
493 case 0xf0: /* PWMAOFF */
494 return s->reg_data[addr];
496 case 0xf1: /* PWMBON */
497 case 0xf2: /* PWMBOFF */
498 return s->reg_data[addr];
500 case 0xf8: /* PWM0ON */
501 case 0xf9: /* PWM0OFF */
502 return s->reg_data[addr];
504 case 0xfb: /* PWM1ON */
505 case 0xfc: /* PWM1OFF */
506 return s->reg_data[addr];
508 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
509 __FUNCTION__, addr, cpu_single_env->regs[15] );
515 static void twl4030_4a_write(void *opaque, uint8_t addr, uint8_t value)
517 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
519 TRACE("addr=0x%02x, value=0x%02x", addr, value);
521 case 0x00: /* CTRL1 */
522 s->reg_data[addr] = value;
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;
530 case 0x12: /* CTRL_SW1 */
531 s->reg_data[addr] = 0xde;
533 case 0x61: /* MADC_ISR1 */
534 s->reg_data[addr] &= ~(value & 0x0f);
536 case 0x62: /* MADC_IMR1 */
537 s->reg_data[addr] = value & 0x0f;
539 case 0x97: /* BCICTL1 */
540 s->reg_data[addr] = value;
542 case 0xb9: /* BCIISR1A */
543 s->reg_data[addr] &= ~value;
545 case 0xba: /* BCIISR2A */
546 s->reg_data[addr] &= ~(value & 0x0f);
548 case 0xbb: /* BCIIMR1A */
549 s->reg_data[addr] = value;
551 case 0xbc: /* BCIIMR2A */
552 s->reg_data[addr] = value & 0x0f;
554 case 0xd2: /* KEYP_CTRL_REG */
555 s->reg_data[addr] = value & 0x7f;
557 case 0xe4: /* KEYP_IMR1 */
558 s->reg_data[addr] = value & 0x0f;
560 case 0xe9: /* KEYP_SIH_CTRL */
561 s->reg_data[addr] = value & 0x07;
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");
569 case 0xef: /* PWMAON */
570 case 0xf8: /* PWM0ON */
571 case 0xfb: /* PWM1ON */
572 s->reg_data[addr] = value;
574 case 0xf0: /* PWMAOFF */
575 case 0xf9: /* PWM0OFF */
576 case 0xfc: /* PWM1OFF */
577 s->reg_data[addr] = value & 0x7f;
580 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
581 __FUNCTION__, addr, cpu_single_env->regs[15]);
586 static int twl4030_4a_tx(i2c_slave *i2c, uint8_t data)
588 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
589 /* Interpret register address byte */
594 twl4030_4a_write(s, s->reg++, data);
599 static int twl4030_4a_rx(i2c_slave *i2c)
601 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
603 return twl4030_4a_read(s, s->reg++);
606 static void twl4030_4a_reset(i2c_slave *i2c)
608 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
610 memcpy(s->reg_data, addr_4a_reset_values, 256);
613 static void twl4030_4a_event(i2c_slave *i2c, enum i2c_event event)
615 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
617 if (event == I2C_START_SEND)
621 static uint8_t twl4030_4b_read(void *opaque, uint8_t addr)
623 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
625 TRACE("addr=0x%02x", addr);
627 /* SECURED_REG region */
629 return s->reg_data[addr];
630 /* BACKUP_REG region */
632 return s->reg_data[addr];
635 return s->reg_data[addr];
638 return s->reg_data[addr];
639 /* PM_MASTER region */
641 return s->reg_data[addr];
642 case 0x45: /* STS_HW_CONDITIONS - USB plugged, no VBUS -> host usb */
645 return s->reg_data[addr];
646 /* PM_RECEIVER region */
648 return s->reg_data[addr];
650 fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n",
651 __FUNCTION__, addr, cpu_single_env->regs[15] );
658 static void twl4030_4b_write(void *opaque, uint8_t addr, uint8_t value)
660 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
661 uint8_t seq_addr, seq_sub;
663 TRACE("addr=0x%02x, value=0x%02x", addr, value);
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;
671 case 0x1e: /* HOURS_REG */
672 case 0x25: /* ALARM_HOURS_REG */
673 s->reg_data[addr] = value & 0xbf;
675 case 0x1f: /* DAYS_REG */
676 case 0x26: /* ALARM_DAYS_REG */
677 s->reg_data[addr] = value & 0x3f;
679 case 0x20: /* MONTHS_REG */
680 case 0x27: /* ALARM_MONTHS_REG */
681 s->reg_data[addr] = value & 0x1f;
683 case 0x21: /* YEARS_REG */
684 case 0x28: /* ALARM_YEARS_REG */
685 s->reg_data[addr] = value;
687 case 0x22: /* WEEKS_REG */
688 s->reg_data[addr] = value & 0x07;
690 case 0x29: /* RTC_CTRL_REG */
691 s->reg_data[addr] = value & 0x7f;
693 case 0x2a: /* RTC_STATUS_REG */
694 s->reg_data[addr] = value & 0xfe;
696 case 0x2b: /* RTC_INTERRUPTS_REG */
697 s->reg_data[addr] = value & 0x0f;
699 case 0x2c: /* RTC_COMP_LSB_REG */
700 case 0x2d: /* RTC_COMP_MSB_REG */
701 s->reg_data[addr] = value;
703 case 0x2e: /* PWR_ISR1 */
704 case 0x2f: /* PWR_IMR1 */
705 s->reg_data[addr] = value;
707 case 0x33: /* PWR_EDR1 */
708 case 0x34: /* PWR_EDR2 */
709 s->reg_data[addr] = value;
711 case 0x35: /* PWR_SIH_CTRL */
712 s->reg_data[addr] = value & 0x07;
714 case 0x3b: /* CFG_BOOT */
715 if (s->twl4030->key_cfg)
716 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
718 case 0x44: /* PROTECT_KEY */
719 s->twl4030->key_cfg = 0;
720 s->twl4030->key_tst = 0;
723 if (s->reg_data[addr] == 0xC0)
724 s->twl4030->key_cfg = 1;
727 if (s->reg_data[addr] == 0x0E)
728 s->twl4030->key_tst = 1;
731 if (s->reg_data[addr] == 0xCE) {
732 s->twl4030->key_cfg = 1;
733 s->twl4030->key_tst = 1;
739 s->reg_data[addr] = value;
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;
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;
756 case 0x59: /* MEMORY_ADDRESS */
757 if (s->twl4030->key_cfg)
758 s->reg_data[addr] = value;
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;
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;
770 /* TODO: check if autoincrement is write-protected as well */
773 case 0x68: /* MISC_CFG */
774 s->reg_data[addr] = value;
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);
786 case 0x75: /* VAUX1_DEDICATED */
787 case 0x7d: /* VAUX3_DEDICATED */
788 if (s->twl4030->key_tst)
789 s->reg_data[addr] = value & 0x77;
791 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
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;
799 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
801 case 0x85: /* VMMC1_DEDICATED */
802 case 0x99: /* VDAC_DEDICATED */
803 if (s->twl4030->key_tst)
804 s->reg_data[addr] = value & 0x73;
806 s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
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;
815 case 0xcd: /* VUSB1V5_TYPE */
816 case 0xd0: /* VUSB1V8_TYPE */
817 case 0xd3: /* VUSB3V1_TYPE */
818 s->reg_data[addr] = value & 0x1f;
820 case 0xd8: /* VUSB_DEDICATED1 */
821 s->reg_data[addr] = value & 0x1f;
823 case 0xd9: /* VUSB_DEDICATED2 */
824 s->reg_data[addr] = value & 0x08;
829 "%s: unknown register 0x%02x value 0x%02x pc 0x%x\n",
830 __FUNCTION__, addr, value, cpu_single_env->regs[15]);
835 static int twl4030_4b_tx(i2c_slave *i2c, uint8_t data)
837 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
838 /* Interpret register address byte */
843 twl4030_4b_write(s, s->reg++, data);
848 static int twl4030_4b_rx(i2c_slave *i2c)
850 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
852 return twl4030_4b_read(s, s->reg++);
855 static void twl4030_4b_reset(i2c_slave *i2c)
857 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
859 memcpy(s->reg_data, addr_4b_reset_values, 256);
860 s->twl4030->key_cfg = 0;
861 s->twl4030->key_tst = 0;
864 static void twl4030_4b_event(i2c_slave *i2c, enum i2c_event event)
866 struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
868 if (event == I2C_START_SEND)
872 static void twl4030_save_state(QEMUFile *f, void *opaque)
874 struct twl4030_s *s = (struct twl4030_s *)opaque;
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));
888 static int twl4030_load_state(QEMUFile *f, void *opaque, int version_id)
890 struct twl4030_s *s = (struct twl4030_s *)opaque;
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));
909 struct twl4030_s *twl4030_init(i2c_bus *bus, qemu_irq irq)
913 struct twl4030_s *s = (struct twl4030_s *) qemu_mallocz(sizeof(*s));
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;
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);
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);
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);
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);
945 register_savevm("twl4030", -1, 0,
946 twl4030_save_state, twl4030_load_state, s);