4
* Copyright (C) 2008 yajin<yajin@vm-kernel.org>
5
* Copyright (C) 2009-2010 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"
27
#include "hw/i2c/i2c.h"
28
#include "sysemu/sysemu.h"
29
#include "ui/console.h"
30
#include "exec/cpu-all.h"
32
//#define DEBUG_GENERAL
35
#define DEBUG_TRACE(fmt, ...) fprintf(stderr, "%s@%d: " fmt "\n", \
36
__FUNCTION__, __LINE__, ##__VA_ARGS__)
39
#define TRACE(...) DEBUG_TRACE(__VA_ARGS__)
45
#define TRACE_RTC(...) DEBUG_TRACE(__VA_ARGS__)
47
#define TRACE_RTC(...)
50
typedef struct TWL4030State TWL4030State;
51
typedef struct TWL4030NodeState TWL4030NodeState;
53
typedef uint8_t (*twl4030_read_func)(TWL4030NodeState *s,
55
typedef void (*twl4030_write_func)(TWL4030NodeState *s,
56
uint8_t addr, uint8_t value);
58
struct TWL4030NodeState {
63
twl4030_read_func read_func;
64
twl4030_write_func write_func;
65
TWL4030State *twl4030;
73
QEMUTimer *alarm_timer;
74
QEMUTimer *periodic_timer;
75
const TWL4030KeyMap *keymap;
78
uint8_t twl5031_aciid;
79
twl4030_madc_callback madc_cb;
84
TWL4030NodeState *i2c[4];
86
uint8_t seq_mem[64][4]; /* power-management sequencing memory */
89
static const uint8_t addr_48_reset_values[256] = {
90
0x51, 0x04, 0x02, 0xc0, 0x41, 0x41, 0x41, 0x10, /* 0x00...0x07 */
91
0x10, 0x10, 0x06, 0x06, 0x06, 0x1f, 0x1f, 0x1f, /* 0x08...0x0f */
92
0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
93
0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, /* 0x18...0x1f */
94
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x03, /* 0x20...0x27 */
95
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
96
0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, /* 0x30...0x37 */
97
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
98
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
99
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
100
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
101
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
102
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
103
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
104
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
105
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
106
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, /* 0x80...0x87 */
107
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
108
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90...0x97 */
109
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
110
0x00, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
111
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
112
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
113
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8...0xb8 */
114
0xa0, 0xa0, 0x64, 0x7f, 0x6c, 0x75, 0x64, 0x20, /* 0xc0...0xc7 */
115
0x01, 0x17, 0x01, 0x02, 0x00, 0x36, 0x44, 0x07, /* 0xc8...0xcf */
116
0x3b, 0x17, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
117
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
118
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
119
0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
120
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
121
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 /* 0xf8...0xff */
124
static const uint8_t addr_49_reset_values[256] = {
125
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
126
0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, /* 0x08...0x0f */
127
0x3f, 0x3f, 0x3f, 0x3f, 0x25, 0x00, 0x00, 0x00, /* 0x10...0x17 */
128
0x00, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x55, /* 0x18...0x1f */
129
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
130
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
131
0x13, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x00, /* 0x30...0x37 */
132
0x00, 0x00, 0x06, 0x00, 0x44, 0x69, 0x00, 0x00, /* 0x38...0x3f */
133
0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x40...0x47 */
134
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
135
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
136
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
137
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
138
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
139
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
140
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
141
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80...0x87 */
142
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
143
0x00, 0x90, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, /* 0x90...0x97 */
144
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
145
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
146
0x00, 0x00, 0x04, 0x00, 0x55, 0x01, 0x55, 0x05, /* 0xa8...0xaf */
147
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, /* 0xb0...0xb7 */
148
0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, /* 0xb8...0xbf */
149
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0xc0...0xc7 */
150
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
151
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
152
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
153
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
154
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
155
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
156
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8...0xff */
159
static const uint8_t addr_4a_reset_values[256] = {
160
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
161
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
162
0xc0, 0x8c, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
163
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18...0x1f */
164
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
165
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
166
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30...0x37 */
167
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
168
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
169
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
170
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
171
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
172
0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x07, /* 0x60...0x67 */
173
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
174
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
175
0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
176
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0x80...0x87 */
177
0x00, 0x68, 0x9b, 0x86, 0x48, 0x2a, 0x07, 0x28, /* 0x88...0x8f */
178
0x09, 0x69, 0x90, 0x00, 0x2a, 0x00, 0x02, 0x00, /* 0x90...0x97 */
179
0x10, 0xcd, 0x02, 0x68, 0x03, 0x00, 0x00, 0x00, /* 0x98...0x9f */
180
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
181
0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
182
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
183
0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, /* 0xb8...0xbf */
184
0x0f, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x01, 0x00, /* 0xc0...0xc7 */
185
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
186
0x00, 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, /* 0xd0...0xd7 */
187
0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
188
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, /* 0xe0...0xe7 */
189
0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
190
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
191
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xf8...0xff */
194
static const uint8_t addr_4b_reset_values[256] = {
195
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
196
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
197
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
198
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x18...0x1f */
199
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* 0x20...0x27 */
200
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, /* 0x28...0x2f */
201
0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xbf, 0xbf, /* 0x30...0x37 */
202
0xbf, 0xab, 0x00, 0x08, 0x3f, 0x15, 0x40, 0x0e, /* 0x38...0x3f */
203
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
204
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, /* 0x48...0x4f */
205
0x00, 0x02, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, /* 0x50...0x57 */
206
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
207
0x00, 0x00, 0x2f, 0x18, 0x0f, 0x08, 0x0f, 0x08, /* 0x60...0x67 */
208
0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
209
0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x03, /* 0x70...0x77 */
210
0x08, 0x09, 0x00, 0x00, 0x08, 0x03, 0x80, 0x03, /* 0x78...0x7f */
211
0x08, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, /* 0x80...0x87 */
212
0x08, 0x08, 0x20, 0x00, 0x00, 0x02, 0x80, 0x04, /* 0x88...0x8f */
213
0x08, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, /* 0x90...0x97 */
214
0x08, 0x02, 0xe0, 0x01, 0x08, 0x00, 0xe0, 0x00, /* 0x98...0x9f */
215
0x08, 0x01, 0xe0, 0x01, 0x08, 0x04, 0xe0, 0x03, /* 0xa0...0xa7 */
216
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
217
0x20, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
218
0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, /* 0xb8...0xbf */
219
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, /* 0xc0...0xc7 */
220
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, /* 0xc8...0xcf */
221
0x00, 0x08, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
222
0x14, 0x08, 0xe0, 0x02, 0x08, 0xe0, 0x00, 0x08, /* 0xd8...0xdf */
223
0xe0, 0x05, 0x08, 0xe0, 0x06, 0x08, 0xe0, 0x00, /* 0xe0...0xe7 */
224
0x08, 0xe0, 0x00, 0x08, 0xe0, 0x06, 0x06, 0xe0, /* 0xe8...0xef */
225
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
226
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xf8...0xff */
229
static void twl4030_interrupt_update(TWL4030State *s)
232
/* TODO: USB, BCI and GPIO interrupts */
235
if (((s->i2c[2]->reg_data[0xda] & 0x10) && /* SIR_EN */
236
s->i2c[2]->reg_data[0xe7]) || /* KEYP_SIR */
237
(s->i2c[2]->reg_data[0xe3] & /* KEYP_ISR1 */
238
~s->i2c[2]->reg_data[0xe4])) /* KEYP_IMR1 */
239
x |= 0x02; /* PIH_ISR1 */
241
if (s->i2c[2]->reg_data[0x65] || /* MADC_SIR */
242
(s->i2c[2]->reg_data[0x61] & /* MADC_ISR1 */
243
~s->i2c[2]->reg_data[0x62])) /* MADC_IMR1 */
244
x |= 0x08; /* PIH_ISR3 */
246
if ((s->i2c[3]->reg_data[0x2e] & /* PWR_ISR1 */
247
~s->i2c[3]->reg_data[0x2f])) /* PWR_IMR1 */
248
x |= 0x20; /* PIH_ISR5 */
250
s->i2c[1]->reg_data[0x81] = x; /* PIH_ISR_P1 */
251
qemu_set_irq(s->irq1, x);
255
if (((s->i2c[2]->reg_data[0xda] & 0x10) && /* SIR_EN */
256
s->i2c[2]->reg_data[0xe7]) || /* KEYP_SIR */
257
(s->i2c[2]->reg_data[0xe5] & /* KEYP_ISR2 */
258
~s->i2c[2]->reg_data[0xe6])) /* KEYP_IMR2 */
259
x |= 0x02; /* PIH_ISR1 */
261
if (s->i2c[2]->reg_data[0x65] || /* MADC_SIR */
262
(s->i2c[2]->reg_data[0x63] & /* MADC_ISR2 */
263
~s->i2c[2]->reg_data[0x64])) /* MADC_IMR2 */
264
x |= 0x08; /* PIH_ISR3 */
266
if ((s->i2c[3]->reg_data[0x30] & /* PWR_ISR2 */
267
~s->i2c[3]->reg_data[0x31])) /* PWR_IMR2 */
268
x |= 0x20; /* PIH_ISR5 */
270
s->i2c[1]->reg_data[0x82] = x; /* PIH_ISR_P2 */
271
qemu_set_irq(s->irq2, x);
275
static uint8_t twl4030_48_read(TWL4030NodeState *s, uint8_t addr)
277
TRACE("addr=0x%02x", addr);
279
case 0x00: /* VENDOR_ID_LO */
280
case 0x01: /* VENDOR_ID_HI */
281
case 0x02: /* PRODUCT_ID_LO */
282
case 0x03: /* PRODUCT_ID_HI */
283
return s->reg_data[addr];
284
case 0x04: /* FUNC_CTRL */
285
case 0x05: /* FUNC_CRTL_SET */
286
case 0x06: /* FUNC_CRTL_CLR */
287
return s->reg_data[0x04];
288
case 0x07: /* IFC_CTRL */
289
case 0x08: /* IFC_CRTL_SET */
290
case 0x09: /* IFC_CRTL_CLR */
291
return s->reg_data[0x07];
292
case 0x13: /* USB_INT_STS */
293
case 0x16: /* SCRATCH_REG */
294
return s->reg_data[addr];
295
case 0xac: /* POWER_CTRL */
296
case 0xad: /* POWER_SET */
297
case 0xae: /* POWER_CLR */
298
return s->reg_data[0xac];
299
case 0xbb: /* CARKIT_AND_CTRL */
300
case 0xbc: /* CARKIT_ANA_SET */
301
case 0xbd: /* CARKIT_ANA_CLR */
302
return s->reg_data[0xbb];
303
case 0xfd: /* PHY_PWR_CTRL */
304
case 0xfe: /* PHY_CLK_CTRL */
305
return s->reg_data[addr];
306
case 0xff: /* PHY_CLK_CTRL_STS */
307
if (s->reg_data[0xfd] & 1) /* PHY_PWR_CTRL */
309
if (s->reg_data[0xfe] & 1) /* REQ_PHY_DPLL_CLK */
311
return (s->reg_data[0x04] >> 6) & 1; /* SUSPENDM */
313
hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
319
static void twl4030_48_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
321
TRACE("addr=0x%02x, value=0x%02x", addr, value);
323
case 0x04: /* FUNC_CTRL */
324
s->reg_data[0x04] = value & 0x7f;
326
case 0x05: /* FUNC_CRTL_SET */
327
s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x7f;
329
case 0x06: /* FUNC_CTRL_CLEAR */
330
s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x7f;
332
case 0x07: /* IFC_CTRL */
333
s->reg_data[0x07] = value & 0x9e;
335
case 0x08: /* IFC_CRTL_SET */
336
s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x9e;
338
case 0x09: /* IFC_CRTL_CLEAR */
339
s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x9e;
341
case 0x16: /* SCRATCH_REG */
342
s->reg_data[0x16] = value;
344
case 0xa1: /* CARKIT_SM_CTRL */
345
s->reg_data[0xa1] = value & 0x3f;
347
case 0xa2: /* CARKIT_SM_CTRL_SET */
348
s->reg_data[0xa1] = (s->reg_data[0xa1] | value) & 0x3f;
350
case 0xa3: /* CARKIT_SM_CTRL_CLR */
351
s->reg_data[0xa1] = (s->reg_data[0xa1] & ~value) & 0x3f;
353
case 0xac: /* POWER_CTRL */
354
s->reg_data[0xac] = value & 0x20;
356
case 0xad: /* POWER_SET */
357
s->reg_data[0xac] = (s->reg_data[0xac] | value) & 0x20;
359
case 0xae: /* POWER_CLEAR */
360
s->reg_data[0xac] = (s->reg_data[0xac] & ~value) & 0x20;
362
case 0xbb: /* CARKIT_ANA_CTRL */
363
s->reg_data[0xbb] = value;
365
case 0xbc: /* CARKIT_ANA_CTRL_SET */
366
s->reg_data[0xbb] |= value;
368
case 0xbd: /* CARKIT_ANA_CTRL_CLR */
369
s->reg_data[0xbb] &= ~value;
371
case 0xfd: /* PHY_PWR_CTRL */
372
s->reg_data[addr] = value & 0x1;
374
case 0xfe: /* PHY_CLK_CTRL */
375
s->reg_data[addr] = value & 0x7;
378
hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
383
static uint8_t twl4030_49_read(TWL4030NodeState *s, uint8_t addr)
385
TRACE("addr=0x%02x", addr);
387
/* AUDIO_VOICE region */
389
return s->reg_data[addr];
392
return s->reg_data[addr];
394
case 0x81: /* PIH_ISR_P1 */
395
case 0x82: /* PIH_ISR_P2 */
396
case 0x83: /* PIH_SIR */
397
return s->reg_data[addr];
400
if (s->reg_data[0x97] != 0x49) {
405
return s->reg_data[addr];
408
return s->reg_data[addr];
410
hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
416
static void twl4030_49_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
418
TRACE("addr=0x%02x, value=0x%02x", addr, value);
420
/* AUDIO_VOICE region */
422
s->reg_data[addr] = value;
426
s->reg_data[addr] = value;
429
/* read-only, ignore */
432
case 0x81: /* PIH_ISR_P1 */
433
case 0x82: /* PIH_ISR_P2 */
434
case 0x83: /* PIH_SIR */
435
s->reg_data[addr] = value;
436
twl4030_interrupt_update(s->twl4030);
440
/* read-only, ignore */
443
s->reg_data[addr] = value;
447
/* read-only, ignore */
450
s->reg_data[addr] = value;
452
case 0xaf: /* GPIOPUPDCTR5 */
453
s->reg_data[addr] = value & 0x0f;
456
s->reg_data[addr] = value;
458
case 0xb6: /* GPIO_IMR3A */
459
s->reg_data[addr] = value & 0x03;
462
s->reg_data[addr] = value;
464
case 0xc5: /* GPIO_SIH_CTRL */
465
s->reg_data[addr] = value & 0x07;
468
hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
473
static uint8_t twl4030_4a_read(TWL4030NodeState *s, uint8_t addr)
475
static const uint8_t twl5031_aciid_data[] = {
476
0x55, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
478
TRACE("addr=0x%02x", addr);
484
return s->reg_data[addr];
485
case 0x17 ... 0x36: /* RT conversion result */
486
if (s->twl4030->madc_cb) {
487
uint16_t x = s->twl4030->madc_cb(TWL4030_ADC_RT,
489
return (addr & 1) ? (uint8_t)((x & 3) << 6)
490
: (uint8_t)((x >> 2) & 0xff);
492
return s->reg_data[addr];
493
case 0x37 ... 0x56: /* GP conversion result */
494
if (s->twl4030->madc_cb) {
495
uint16_t x = s->twl4030->madc_cb(TWL4030_ADC_GP,
497
return (addr & 1) ? (uint8_t)((x & 3) << 6)
498
: (uint8_t)((x >> 2) & 0xff);
500
return s->reg_data[addr];
501
case 0x57 ... 0x60: /* BCI conversion result */
502
if (s->twl4030->madc_cb) {
503
uint16_t x = s->twl4030->madc_cb(TWL4030_ADC_BCI,
505
return (addr & 1) ? (uint8_t)((x & 3) << 6)
506
: (uint8_t)((x >> 2) & 0xff);
508
return s->reg_data[addr];
509
case 0x61: /* MADC_ISR1 */
510
case 0x63: /* MADC_ISR2 */
512
uint8_t data = s->reg_data[addr];
513
if (s->reg_data[0x67] & 0x04) { /* COR */
514
s->reg_data[addr] = 0x00;
515
twl4030_interrupt_update(s->twl4030);
519
/* MAIN_CHARGE(TWL4030) / ACCESSORY(TWL5031) region */
521
if (s->twl4030->twl5031) {
523
case 0x74: /* ACIID */
524
if (s->twl4030->twl5031_aciid >=
525
sizeof(twl5031_aciid_data)) {
526
s->twl4030->twl5031_aciid = 0;
528
return twl5031_aciid_data[s->twl4030->twl5031_aciid++];
529
case 0x79: /* ACIIMR_LSB */
530
case 0x7a: /* ACIIMR_MSB */
531
case 0x7b: /* ACIIDR_LSB */
532
case 0x7c: /* ACIIDR_MSB */
533
case 0x80: /* AV_CTRL */
534
case 0x82: /* BCIA_CTRL */
535
case 0x83: /* ACCISR1 */
536
return s->reg_data[addr];
538
hw_error("%s: unknown twl5031 register 0x%02x",
543
return s->reg_data[addr];
544
/* PRECHARGE region */
546
return s->reg_data[addr];
547
/* Interrupt region */
549
return s->reg_data[addr];
554
return s->reg_data[addr];
555
case 0xe3: /* KEYP_ISR1 */
556
case 0xe5: /* KEYP_ISR2 */
558
uint8_t data = s->reg_data[addr];
559
if (s->reg_data[0xe9] & 0x04) { /* COR */
560
s->reg_data[addr] = 0x00;
561
twl4030_interrupt_update(s->twl4030);
566
case 0xee: /* LEDEN */
567
return s->reg_data[addr];
569
case 0xef: /* PWMAON */
570
case 0xf0: /* PWMAOFF */
571
return s->reg_data[addr];
573
case 0xf1: /* PWMBON */
574
case 0xf2: /* PWMBOFF */
575
return s->reg_data[addr];
577
case 0xf8: /* PWM0ON */
578
case 0xf9: /* PWM0OFF */
579
return s->reg_data[addr];
581
case 0xfb: /* PWM1ON */
582
case 0xfc: /* PWM1OFF */
583
return s->reg_data[addr];
585
hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
591
static void twl4030_4a_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
593
TRACE("addr=0x%02x, value=0x%02x", addr, value);
597
case 0x00: /* CTRL1 */
598
case 0x01: /* CTRL2 */
599
s->reg_data[addr] = value;
601
case 0x06: /* SW1SELECT_LSB */
602
case 0x07: /* SW1SELECT_MSB */
603
case 0x08: /* SW1AVERAGE_LSB */
604
case 0x09: /* SW1AVERAGE_MSB */
605
case 0x0a: /* SW2SELECT_LSB */
606
case 0x0b: /* SW2SELECT_MSB */
607
case 0x0c: /* SW2AVERAGE_LSB */
608
case 0x0d: /* SW2AVERAGE_MSB */
609
s->reg_data[addr] = value;
611
case 0x12: /* CTRL_SW1 */
612
case 0x13: /* CTRL_SW2 */
613
/* always set all conversions ready, not busy */
614
s->reg_data[addr] = 0x3e;
615
if (value & 0x20) { /* SW1/SW2 */
616
s->reg_data[0x61] |= 2 << (addr - 0x12); /* SW1_ISR/SW2_ISR */
617
s->reg_data[0x63] |= 2 << (addr - 0x12); /* SW1_ISR/SW2_ISR */
618
twl4030_interrupt_update(s->twl4030);
621
case 0x17 ... 0x60: /* conversion results */
622
/* read-only, ignore */
624
case 0x61: /* MADC_ISR1 */
625
case 0x63: /* MADC_ISR2 */
626
if (!(s->reg_data[0x67] & 0x04)) { /* COR */
627
s->reg_data[addr] &= ~(value & 0x0f);
628
twl4030_interrupt_update(s->twl4030);
631
case 0x62: /* MADC_IMR1 */
632
case 0x64: /* MADC_IMR2 */
633
case 0x65: /* MADC_SIR */
634
s->reg_data[addr] = value & 0x0f;
635
twl4030_interrupt_update(s->twl4030);
637
case 0x66: /* MADC_EDR */
638
s->reg_data[addr] = value;
640
case 0x67: /* MADC_SIH_CTRL */
641
s->reg_data[addr] = value & 0x07;
644
/* MAIN_CHARGE(TWL4030) / ACCESSORY(TWL5031) region */
646
case 0x74: /* BCIMDEN(TWL4030) / ACIID(TWL5031) */
647
if (s->twl4030->twl5031) {
648
s->twl4030->twl5031_aciid = 0;
653
case 0x75: /* BCIMDKEY(TWL4030) / ACICOMR_LSB(TWL5031) */
654
s->reg_data[addr] = value;
655
if (!s->twl4030->twl5031) {
657
case 0x25: s->reg_data[0x74] = 0x12; break;
658
case 0x26: s->reg_data[0x74] = 0x11; break;
659
case 0x27: s->reg_data[0x74] = 0x0a; break;
660
case 0x28: s->reg_data[0x74] = 0x06; break;
661
case 0x29: s->reg_data[0x74] = 0x05; break;
662
default: s->reg_data[0x74] = 0; break;
667
if (s->twl4030->twl5031) {
669
case 0x79: /* ACIIMR_LSB */
670
s->reg_data[addr] = value;
671
twl4030_interrupt_update(s->twl4030);
673
case 0x7a: /* ACIIMR_MSB */
674
s->reg_data[addr] = value & 0x01;
675
twl4030_interrupt_update(s->twl4030);
677
case 0x7b: /* ACIIDR_LSB */
678
s->reg_data[addr] &= ~value;
679
twl4030_interrupt_update(s->twl4030);
681
case 0x7c: /* ACIIDR_MSB */
682
s->reg_data[addr] &= ~(value & 0x01);
683
twl4030_interrupt_update(s->twl4030);
685
case 0x7f: /* ECI_DBI_CTRL */
686
s->reg_data[addr] = value;
687
twl4030_interrupt_update(s->twl4030);
689
case 0x80: /* ACI_AV_CTRL */
690
s->reg_data[addr] = (s->reg_data[addr] & 0x18) |
692
twl4030_interrupt_update(s->twl4030);
694
case 0x82: /* BCIA_CTRL */
695
s->reg_data[addr] = value & 0x07;
697
case 0x83: /* ACCISR1 */
698
s->reg_data[addr] &= ~(value & 0x03);
699
twl4030_interrupt_update(s->twl4030);
701
case 0x84: /* ACCIMR1 */
702
s->reg_data[addr] = value & 0x03;
703
twl4030_interrupt_update(s->twl4030);
706
hw_error("%s: unknown twl5031 register 0x%02x",
711
/* read-only registers */
714
case 0x97: /* BCICTL1 */
715
if (!s->twl4030->twl5031) {
716
s->reg_data[addr] = value;
718
hw_error("%s: unknown twl5031 register 0x%02x",
723
/* PRECHARGE region */
725
case 0xaa ... 0xb8: /* FIXME: unknown registers */
726
s->reg_data[addr] = value;
729
/* Interrupt region */
731
case 0xb9: /* BCIISR1A */
732
s->reg_data[addr] &= ~value;
734
case 0xba: /* BCIISR2A */
735
s->reg_data[addr] &= ~(value & 0x0f);
737
case 0xbb: /* BCIIMR1A */
738
s->reg_data[addr] = value;
740
case 0xbc: /* BCIIMR2A */
741
s->reg_data[addr] = value & 0x0f;
743
case 0xc6: /* BCISIHCTRL */
744
s->reg_data[addr] = value & 0x07;
749
case 0xd2: /* KEYP_CTRL_REG */
750
s->reg_data[addr] = value & 0x7f;
752
case 0xd3: /* KEYP_DEB_REG */
753
s->reg_data[addr] = value & 0x3f;
755
case 0xd5: /* LK_PTV_REG */
756
s->reg_data[addr] = value & 0xef;
758
case 0xda: /* KEYP_SMS */
759
s->reg_data[addr] = (s->reg_data[addr] & ~0x30) | (value & 0x30);
760
twl4030_interrupt_update(s->twl4030);
762
case 0xe3: /* KEYP_ISR1 */
763
case 0xe5: /* KEYP_ISR2 */
764
if (!(s->reg_data[0xe9] & 0x04)) { /* COR */
765
s->reg_data[addr] &= ~value;
766
twl4030_interrupt_update(s->twl4030);
769
case 0xe4: /* KEYP_IMR1 */
770
case 0xe6: /* KEYP_IMR2 */
771
case 0xe7: /* KEYP_SIR */
772
s->reg_data[addr] = value & 0x0f;
773
twl4030_interrupt_update(s->twl4030);
775
case 0xe9: /* KEYP_SIH_CTRL */
776
s->reg_data[addr] = value & 0x07;
778
case 0xd4: /* LONG_KEY_REG1 */
779
case 0xd6: /* TIME_OUT_REG1 */
780
case 0xd7: /* TIME_OUT_REG2 */
781
case 0xd8: /* KBC_REG */
782
case 0xe8: /* KEYP_EDR */
783
s->reg_data[addr] = value;
785
case 0xd9: /* KBR_REG */
786
case 0xdb ... 0xe2: /* FULL_CODE_xx_yy */
787
/* read-only, ignore */
792
case 0xee: /* LEDEN */
793
s->reg_data[addr] = value;
794
TRACE("LEDA power=%s/enable=%s, LEDB power=%s/enable=%s",
795
value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",
796
value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");
799
/* PWMA/B/0/1 regions */
801
case 0xef: /* PWMAON */
802
case 0xf1: /* PWMBON */
803
case 0xf8: /* PWM0ON */
804
case 0xfb: /* PWM1ON */
805
s->reg_data[addr] = value;
807
case 0xf0: /* PWMAOFF */
808
case 0xf2: /* PWMBOFF */
809
case 0xf9: /* PWM0OFF */
810
case 0xfc: /* PWM1OFF */
811
s->reg_data[addr] = value & 0x7f;
815
hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
820
static inline struct tm *twl4030_gettime(void)
822
time_t epoch_time = time(NULL);
823
return gmtime(&epoch_time);//localtime(&epoch_time);
826
static uint8_t twl4030_4b_read(TWL4030NodeState *s, uint8_t addr)
829
TRACE("addr=0x%02x value=0x%02x", addr, s->reg_data[addr]);
831
/* SECURED_REG region */
833
return s->reg_data[addr];
834
/* BACKUP_REG region */
836
return s->reg_data[addr];
838
case 0x1c: /* SECONDS_REG */
839
x = s->reg_data[addr];
841
struct tm *t = twl4030_gettime();
842
x = ((t->tm_sec / 10) << 4) | (t->tm_sec % 10);
844
s->reg_data[addr] = 0xff;
846
TRACE_RTC("SECONDS_REG returns 0x%02x", x);
848
case 0x1d: /* MINUTES_REG */
849
x = s->reg_data[addr];
851
struct tm *t = twl4030_gettime();
852
x = ((t->tm_min / 10) << 4) | (t->tm_min % 10);
854
s->reg_data[addr] = 0xff;
856
TRACE_RTC("MINUTES_REG returns 0x%02x", x);
858
case 0x1e: /* HOURS_REG */
859
x = s->reg_data[addr];
861
struct tm *t = twl4030_gettime();
862
if (s->reg_data[0x29] & 0x08) { /* MODE_12_24 */
863
int h12 = t->tm_hour;
866
x = ((h12 / 10) << 4) | (h12 % 10) | 0x80; /* PM_NAM */
868
x = ((h12 / 10) << 4) | (h12 % 10);
871
x = ((t->tm_hour / 10) << 4) | (t->tm_hour % 10);
874
s->reg_data[addr] = 0xff;
876
TRACE_RTC("HOURS_REG returns 0x%02x", x);
878
case 0x1f: /* DAYS_REG */
879
x = s->reg_data[addr];
881
struct tm *t = twl4030_gettime();
882
x = ((t->tm_mday / 10) << 4) | (t->tm_mday % 10);
884
s->reg_data[addr] = 0xff;
886
TRACE_RTC("DAYS_REG returns 0x%02x", x);
888
case 0x20: /* MONTHS_REG */
889
x = s->reg_data[addr];
891
struct tm *t = twl4030_gettime();
892
x = (((t->tm_mon + 1) / 10) << 4) | ((t->tm_mon + 1) % 10);
894
s->reg_data[addr] = 0xff;
896
TRACE_RTC("MONTHS_REG returns 0x%02x", x);
898
case 0x21: /* YEARS_REG */
899
x = s->reg_data[addr];
901
struct tm *t = twl4030_gettime();
902
x = (((t->tm_year % 100) / 10) << 4) | (t->tm_year % 10);
904
s->reg_data[addr] = 0xff;
906
TRACE_RTC("YEARS_REG returns 0x%02x", x);
908
case 0x22: /* WEEKS_REG */
909
x = s->reg_data[addr];
911
struct tm *t = twl4030_gettime();
914
s->reg_data[addr] = 0xff;
916
TRACE_RTC("WEEKS_REG returns 0x%02x", x);
918
case 0x23: /* ALARM_SECONDS_REG */
919
x = s->reg_data[addr];
920
TRACE_RTC("ALARM_SECONDS_REG returns 0x%02x", x);
922
case 0x24: /* ALARM_MINUTES_REG */
923
x = s->reg_data[addr];
924
TRACE_RTC("ALARM_MINUTES_REG returns 0x%02x", x);
926
case 0x25: /* ALARM_HOURS_REG */
927
x = s->reg_data[addr];
928
TRACE_RTC("ALARM_HOURS_REG returns 0x%02x", x);
930
case 0x26: /* ALARM_DAYS_REG */
931
x = s->reg_data[addr];
932
TRACE_RTC("ALARM_DAYS_REG returns 0x%02x", x);
934
case 0x27: /* ALARM_MONTHS_REG */
935
x = s->reg_data[addr];
936
TRACE_RTC("ALARM_MONTHS_REG returns 0x%02x", x);
938
case 0x28: /* ALARM_YEARS_REG */
939
x = s->reg_data[addr];
940
TRACE_RTC("ALARM_YEARS_REG returns 0x%02x", x);
942
case 0x29: /* RTC_CTRL_REG */
943
x = s->reg_data[addr];
944
TRACE_RTC("RTC_CTRL_REG returns 0x%02x", x);
946
case 0x2a: /* RTC_STATUS_REG */
947
x = s->reg_data[addr];
948
TRACE_RTC("RTC_STATUS_REG returns 0x%02x", x);
950
case 0x2b: /* RTC_INTERRUPTS_REG */
951
x = s->reg_data[addr];
952
TRACE_RTC("RTC_INTERRUPTS_REG returns 0x%02x", x);
954
case 0x2c: /* RTC_COMP_LSB_REG */
955
x = s->reg_data[addr];
956
TRACE_RTC("RTC_COMP_LSB_REG returns 0x%02x", x);
958
case 0x2d: /* RTC_COMP_MSB_REG */
959
x = s->reg_data[addr];
960
TRACE_RTC("RTC_CTRL_REG returns 0x%02x", x);
965
return s->reg_data[addr];
966
case 0x2e: /* PWR_ISR1 */
967
case 0x30: /* PWR_ISR2 */
969
uint8_t data = s->reg_data[addr];
970
if (s->reg_data[0x35] & 0x04) { /* COR */
971
s->reg_data[addr] = 0x00;
972
twl4030_interrupt_update(s->twl4030);
976
/* PM_MASTER region */
978
return s->reg_data[addr];
979
case 0x45: /* STS_HW_CONDITIONS */
980
/* FIXME: force USB always connected, no VBUS (host usb) */
981
return (s->reg_data[addr] & ~0x80) | 0x04;
983
return s->reg_data[addr];
984
/* PM_RECEIVER region */
986
return s->reg_data[addr];
988
hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
994
static void twl4030_setup_alarm(TWL4030NodeState *s)
996
if (s->reg_data[0x2b] & 0x08) { /* IT_ALARM */
998
.tm_sec = ((s->reg_data[0x23] >> 4) & 7) * 10
999
+ (s->reg_data[0x23] & 0x0f),
1000
.tm_min = ((s->reg_data[0x24] >> 4) & 7) * 10
1001
+ (s->reg_data[0x24] & 0x0f),
1002
.tm_hour = ((s->reg_data[0x29] & 0x08)
1003
? (s->reg_data[0x25] >> 7) * 12 : 0)
1004
+ ((s->reg_data[0x25] >> 4) & 3) * 10
1005
+ (s->reg_data[0x25] & 0x0f),
1006
.tm_mday = ((s->reg_data[0x26] >> 4) & 3) * 10
1007
+ (s->reg_data[0x26] & 0x0f),
1008
.tm_mon = ((s->reg_data[0x27] >> 4) & 1) * 10
1009
+ (s->reg_data[0x27] & 0x0f)
1011
.tm_year = (s->reg_data[0x28] >> 4) * 10
1012
+ (s->reg_data[0x28] & 0x0f)
1016
TRACE_RTC("enable alarm on %02d/%02d/%04d at %02d:%02d:%02d (UTC)",
1017
a.tm_mday, a.tm_mon + 1, a.tm_year + 1900,
1018
a.tm_hour, a.tm_min, a.tm_sec);
1019
time_t at = mktime(&a); /* alarm time interpreted in local time */
1021
TRACE_RTC("unable to parse alarm calendar time");
1023
/* fix alarm time to utc */
1026
if (!gettimeofday(&tv, &tz)) {
1027
at -= tz.tz_minuteswest * 60;
1029
int64_t delta = (int64_t)difftime(at, time(NULL));
1031
TRACE_RTC("alarm is in the past");
1033
TRACE_RTC("new alarm interrupt in %" PRId64 " seconds", delta);
1034
timer_mod(s->twl4030->alarm_timer,
1035
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
1036
+ get_ticks_per_sec() * delta);
1040
timer_del(s->twl4030->alarm_timer);
1044
static void twl4030_setup_periodic(TWL4030NodeState *s)
1046
if (s->reg_data[0x2b] & 0x04) { /* IT_TIMER */
1048
switch (s->reg_data[0x2b] & 3) {
1049
case 0: t = 1; break;
1050
case 1: t = 60; break;
1051
case 2: t = 60 * 60; break;
1052
case 3: t = 24 * 60 * 60; break;
1054
TRACE_RTC("new periodic interrupt in %u seconds", t);
1055
timer_mod(s->twl4030->periodic_timer,
1056
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
1057
+ get_ticks_per_sec() * t);
1059
timer_del(s->twl4030->periodic_timer);
1063
static void twl4030_alarm(void *opaque)
1065
TWL4030State *s = opaque;
1066
s->i2c[3]->reg_data[0x2a] |= 0x40; /* RTC_STATUS_REG |= ALARM */
1067
if (s->i2c[3]->reg_data[0x33] & 0xc0) { /* RTC_IT_RISING|RTC_IT_FALLING */
1068
TRACE_RTC("triggering RTC alarm interrupt");
1069
s->i2c[3]->reg_data[0x2e] |= 0x08; /* PWR_ISR1 |= RTC_IT */
1070
s->i2c[3]->reg_data[0x30] |= 0x08; /* PWR_ISR2 |= RTC_IT */
1071
twl4030_interrupt_update(s);
1073
timer_del(s->alarm_timer);
1076
static void twl4030_periodic(void *opaque)
1078
TWL4030State *s = opaque;
1079
uint8_t b = 0x04 << (s->i2c[3]->reg_data[0x2b] & 3);
1080
s->i2c[3]->reg_data[0x2a] |= b; /* TODO: when are these cleared? */
1081
if (s->i2c[3]->reg_data[0x33] & 0xc0) { /* RTC_IT_RISING|RTC_IT_FALLING */
1082
TRACE_RTC("triggering RTC periodic interrupt");
1083
s->i2c[3]->reg_data[0x2e] |= 0x08; /* PWR_ISR1 |= RTC_IT */
1084
s->i2c[3]->reg_data[0x30] |= 0x08; /* PWR_ISR2 |= RTC_IT */
1085
twl4030_interrupt_update(s);
1087
twl4030_setup_periodic(s->i2c[3]);
1090
static void twl4030_4b_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
1092
uint8_t seq_addr, seq_sub;
1094
TRACE("addr=0x%02x, value=0x%02x", addr, value);
1096
case 0x1c: /* SECONDS_REG */
1097
TRACE_RTC("SECONDS_REG = 0x%02x", value);
1098
s->reg_data[addr] = value & 0x7f;
1100
case 0x1d: /* MINUTES_REG */
1101
TRACE_RTC("MINUTES_REG = 0x%02x", value);
1102
s->reg_data[addr] = value & 0x7f;
1104
case 0x1e: /* HOURS_REG */
1105
TRACE_RTC("HOURS_REG = 0x%02x", value);
1106
s->reg_data[addr] = value & 0xbf;
1108
case 0x1f: /* DAYS_REG */
1109
TRACE_RTC("DAYS_REG = 0x%02x", value);
1110
s->reg_data[addr] = value & 0x3f;
1112
case 0x20: /* MONTHS_REG */
1113
TRACE_RTC("MONTHS_REG = 0x%02x", value);
1114
s->reg_data[addr] = value & 0x1f;
1116
case 0x21: /* YEARS_REG */
1117
TRACE_RTC("YEARS_REG = 0x%02x", value);
1118
s->reg_data[addr] = value;
1120
case 0x22: /* WEEKS_REG */
1121
TRACE_RTC("WEEKS_REG = 0x%02x", value);
1122
s->reg_data[addr] = value & 0x07;
1124
case 0x23: /* ALARM_SECONDS_REG */
1125
TRACE_RTC("ALARM_SECONDS_REG = 0x%02x", value);
1126
s->reg_data[addr] = value & 0x7f;
1127
twl4030_setup_alarm(s);
1129
case 0x24: /* ALARM_MINUTES_REG */
1130
TRACE_RTC("ALARM_MINUTES_REG = 0x%02x", value);
1131
s->reg_data[addr] = value & 0x7f;
1132
twl4030_setup_alarm(s);
1134
case 0x25: /* ALARM_HOURS_REG */
1135
TRACE_RTC("ALARM_HOURS_REG = 0x%02x", value);
1136
s->reg_data[addr] = value & 0xbf;
1137
twl4030_setup_alarm(s);
1139
case 0x26: /* ALARM_DAYS_REG */
1140
TRACE_RTC("ALARM_DAYS_REG = 0x%02x", value);
1141
s->reg_data[addr] = value & 0x3f;
1142
twl4030_setup_alarm(s);
1144
case 0x27: /* ALARM_MONTHS_REG */
1145
TRACE_RTC("ALARM_MONTHS_REG = 0x%02x", value);
1146
s->reg_data[addr] = value & 0x1f;
1147
twl4030_setup_alarm(s);
1149
case 0x28: /* ALARM_YEARS_REG */
1150
TRACE_RTC("ALARM_YEARS_REG = 0x%02x", value);
1151
s->reg_data[addr] = value;
1152
twl4030_setup_alarm(s);
1154
case 0x29: /* RTC_CTRL_REG */
1155
TRACE_RTC("RTC_CTRL_REG = 0x%02x", value);
1156
s->reg_data[addr] = value & 0x3f;
1157
s->reg_data[0x2a] = (s->reg_data[0x2a] & ~0x02) |
1158
((value & 0x01) << 1);
1159
if (value & 0x40) { /* GET_TIME */
1160
struct tm *t = twl4030_gettime();
1161
s->reg_data[0x1c] = ((t->tm_sec / 10) << 4) | (t->tm_sec % 10);
1162
s->reg_data[0x1d] = ((t->tm_min / 10) << 4) | (t->tm_min % 10);
1163
if (value & 0x08) { /* MODE_12_24 */
1164
int h12 = t->tm_hour;
1165
/* TODO: should we report hours 0-11 or 1-12? */
1168
s->reg_data[0x1e] = ((h12 / 10) << 4) | (h12 % 10) |
1171
s->reg_data[0x1e] = ((h12 / 10) << 4) | (h12 % 10);
1174
s->reg_data[0x1e] = ((t->tm_hour / 10) << 4) |
1177
s->reg_data[0x1f] = ((t->tm_mday / 10) << 4) |
1179
s->reg_data[0x20] = (((t->tm_mon + 1) / 10) << 4) |
1180
((t->tm_mon + 1) % 10);
1181
s->reg_data[0x21] = (((t->tm_year % 100) / 10) << 4) |
1183
s->reg_data[0x22] = t->tm_wday;
1185
/* TODO: support bits 1, 2, 4 and 5 */
1187
case 0x2a: /* RTC_STATUS_REG */
1188
TRACE_RTC("RTC_STATUS_REG = 0x%02x", value);
1189
s->reg_data[addr] &= ~(value & 0xc0);
1191
case 0x2b: /* RTC_INTERRUPTS_REG */
1192
TRACE_RTC("RTC_INTERRUPTS_REG = 0x%02x", value);
1194
uint8_t change = s->reg_data[addr] ^ value;
1195
s->reg_data[addr] = value & 0x0f;
1196
if (change & 0x08) { /* IT_ALARM */
1197
twl4030_setup_alarm(s);
1199
if (change & 0x04) { /* IT_TIMER */
1200
twl4030_setup_periodic(s);
1204
case 0x2c: /* RTC_COMP_LSB_REG */
1205
case 0x2d: /* RTC_COMP_MSB_REG */
1206
TRACE_RTC("RTC_COMP_%s_REG = 0x%02x",
1207
(addr == 0x2c) ? "LSB" : "MSB", value);
1208
s->reg_data[addr] = value;
1210
case 0x2e: /* PWR_ISR1 */
1211
case 0x30: /* PWR_ISR2 */
1212
if (!(s->reg_data[0x35] & 0x04)) { /* COR */
1213
s->reg_data[addr] &= ~value;
1214
twl4030_interrupt_update(s->twl4030);
1217
case 0x2f: /* PWR_IMR1 */
1218
case 0x31: /* PWR_IMR2 */
1219
s->reg_data[addr] = value;
1220
twl4030_interrupt_update(s->twl4030);
1222
case 0x33: /* PWR_EDR1 */
1223
case 0x34: /* PWR_EDR2 */
1224
s->reg_data[addr] = value;
1226
case 0x35: /* PWR_SIH_CTRL */
1227
s->reg_data[addr] = value & 0x07;
1229
case 0x36: /* CFG_P1_TRANSITION */
1230
case 0x37: /* CFG_P2_TRANSITION */
1231
case 0x38: /* CFG_P3_TRANSITION */
1232
if (s->twl4030->key_cfg)
1233
s->reg_data[addr] = (s->reg_data[addr] & 0x40) | (value & 0xbf);
1235
case 0x39: /* CFG_P123_TRANSITION */
1236
if (s->twl4030->key_cfg)
1237
s->reg_data[addr] = value;
1239
case 0x3a: /* STS_BOOT */
1240
s->reg_data[addr] = value;
1242
case 0x3b: /* CFG_BOOT */
1243
if (s->twl4030->key_cfg)
1244
s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
1246
case 0x3c: /* SHUNDAN */
1247
s->reg_data[addr] = value & 0x3f;
1249
case 0x3d: /* BOOT_BCI */
1250
s->reg_data[addr] = (s->reg_data[addr] & 0x20) | (value & 0x17);
1252
case 0x3e: /* CFG_PWRANA1 */
1253
if (s->twl4030->key_tst)
1254
s->reg_data[addr] = value & 0x7f;
1256
case 0x3f: /* CFG_PWRANA2 */
1257
if (s->twl4030->key_tst)
1258
s->reg_data[addr] = value;
1260
case 0x44: /* PROTECT_KEY */
1261
s->twl4030->key_cfg = 0;
1262
s->twl4030->key_tst = 0;
1265
if (s->reg_data[addr] == 0xC0)
1266
s->twl4030->key_cfg = 1;
1269
if (s->reg_data[addr] == 0x0E)
1270
s->twl4030->key_tst = 1;
1273
if (s->reg_data[addr] == 0xCE) {
1274
s->twl4030->key_cfg = 1;
1275
s->twl4030->key_tst = 1;
1281
s->reg_data[addr] = value;
1283
case 0x46: /* P1_SW_EVENTS */
1284
case 0x47: /* P2_SW_EVENTS */
1285
case 0x48: /* P3_SW_EVENTS */
1286
s->reg_data[addr] = value & 0x78;
1287
if (value & 0x01) { /* DEVOFF */
1288
TRACE("device power off sequence requested");
1289
qemu_system_shutdown_request();
1292
case 0x4a: /* PB_CFG */
1293
s->reg_data[addr] = value & 0xf;
1295
case 0x4b: /* PB_MSB */
1296
case 0x4c: /* PB_LSB */
1297
s->reg_data[addr] = value;
1299
case 0x52: /* SEQ_ADD_W2P */
1300
case 0x53: /* SEQ_ADD_P2A */
1301
case 0x54: /* SEQ_ADD_A2W */
1302
case 0x55: /* SEQ_ADD_A2S */
1303
case 0x56: /* SEQ_ADD_S2A12 */
1304
case 0x57: /* SEQ_ADD_S2A3 */
1305
case 0x58: /* SEQ_ADD_WARM */
1306
if (s->twl4030->key_cfg)
1307
s->reg_data[addr] = value & 0x3f;
1309
case 0x59: /* MEMORY_ADDRESS */
1310
if (s->twl4030->key_cfg)
1311
s->reg_data[addr] = value;
1313
case 0x5a: /* MEMORY_DATA */
1314
if (s->twl4030->key_cfg) {
1315
s->reg_data[addr] = value;
1316
seq_addr = s->reg_data[0x59];
1317
seq_sub = seq_addr & 3;
1319
if ((seq_addr >= 0x2b && seq_addr <= 0x3e) ||
1320
(seq_addr <= 0x0e && seq_sub == 3))
1321
s->twl4030->seq_mem[seq_addr][seq_sub] = value;
1323
/* TODO: check if autoincrement is write-protected as well */
1324
s->reg_data[0x59]++;
1326
case 0x5e: /* WATCHDOG_CFG */
1327
case 0x60: /* VIBRATOR_CFG */
1328
case 0x6d: /* BB_CFG */
1329
case 0x73: /* VAUX1_TYPE */
1330
case 0x77: /* VAUX2_TYPE */
1331
case 0x7b: /* VAUX3_TYPE */
1332
case 0x7f: /* VAUX4_TYPE */
1333
case 0x83: /* VMMC1_TYPE */
1334
case 0x87: /* VMMC2_TYPE */
1335
case 0x8b: /* VPLL1_TYPE */
1336
case 0x8f: /* VPLL2_TYPE */
1337
case 0x93: /* VSIM_TYPE */
1338
case 0x97: /* VDAC_TYPE */
1339
case 0x9b: /* VINTANA1_TYPE */
1340
case 0x9f: /* VINTANA2_TYPE */
1341
case 0xa3: /* VINTDIG_TYPE */
1342
case 0xa7: /* VIO_TYPE */
1343
case 0xaa: /* VIO_MISC_CFG */
1344
case 0xb1: /* VDD1_TYPE */
1345
case 0xb4: /* VDD1_MISC_CFG */
1346
case 0xbd: /* VDD1_STEP */
1347
case 0xbf: /* VDD2_TYPE */
1348
case 0xc2: /* VDD2_MISC_CFG */
1349
case 0xcb: /* VDD2_STEP */
1350
case 0xcd: /* VUSB1V5_TYPE */
1351
case 0xd0: /* VUSB1V8_TYPE */
1352
case 0xd3: /* VUSB3V1_TYPE */
1353
case 0xdb: /* REGEN_TYPE */
1354
case 0xde: /* NRESPWRON_TYPE */
1355
case 0xe1: /* CLKEN_TYPE */
1356
case 0xe4: /* SYSEN_TYPE */
1357
case 0xe7: /* HFCLKOUT_TYPE */
1358
case 0xea: /* 2KCLKOUT_TYPE */
1359
case 0xed: /* TRITON_RESET_TYPE */
1360
case 0xf0: /* MAINREF_TYPE */
1361
s->reg_data[addr] = value & 0x1f;
1363
case 0x5f: /* IT_CHECK_CFG */
1364
case 0xb9: /* VDD1_VSEL */
1365
case 0xbb: /* VDD1_VFLOOR */
1366
case 0xbc: /* VDD1_VROOF */
1367
case 0xc7: /* VDD2_VSEL */
1368
case 0xc9: /* VDD2_VFLOOR */
1369
case 0xca: /* VDD2_VROOF */
1370
s->reg_data[addr] = value & 0x7f;
1372
case 0x61: /* DC/DC_GLOBAL_CFG */
1373
case 0x68: /* MISC_CFG */
1374
s->reg_data[addr] = value;
1376
case 0x62: /* VDD1_TRIM1 */
1377
case 0x64: /* VDD2_TRIM1 */
1378
case 0x66: /* VIO_TRIM1 */
1379
case 0xac: /* VIO_TEST2 */
1380
case 0xb6: /* VDD1_TEST2 */
1381
case 0xc4: /* VDD2_TEST2 */
1382
if (s->twl4030->key_tst)
1383
s->reg_data[addr] = value & 0x7f;
1385
case 0x63: /* VDD1_TRIM2 */
1386
case 0x65: /* VDD2_TRIM2 */
1387
case 0x67: /* VIO_TRIM2 */
1388
if (s->twl4030->key_tst)
1389
s->reg_data[addr] = value & 0x3f;
1391
case 0x72: /* VAUX1_DEV_GRP */
1392
case 0x76: /* VAUX2_DEV_GRP */
1393
case 0x7a: /* VAUX3_DEV_GRP */
1394
case 0x7e: /* VAUX4_DEV_GRP */
1395
case 0x82: /* VMMC1_DEV_GRP */
1396
case 0x86: /* VMMC2_DEV_GRP */
1397
case 0x8a: /* VPLL1_DEV_GRP */
1398
case 0x8e: /* VPLL2_DEV_GRP */
1399
case 0x92: /* VSIM_DEV_GRP */
1400
case 0x96: /* VDAC_DEV_GRP */
1401
case 0x9a: /* VINTANA1_DEV_GRP */
1402
case 0x9e: /* VINTANA2_DEV_GRP */
1403
case 0xa2: /* VINTDIG_DEV_GRP */
1404
case 0xa6: /* VIO_DEV_GRP */
1405
case 0xb0: /* VDD1_DEV_GRP */
1406
case 0xbe: /* VDD2_DEV_GRP */
1407
case 0xcc: /* VUSB1V5_DEV_GRP */
1408
case 0xcf: /* VUSB1V8_DEV_GRP */
1409
case 0xd2: /* VUSB3V1_DEV_GRP */
1410
case 0xda: /* REGEN_DEV_GRP */
1411
case 0xdd: /* NRESPWRON_DEV_GRP */
1412
case 0xe0: /* CLKEN_DEV_GRP */
1413
case 0xe3: /* SYSEN_DEV_GRP */
1414
case 0xe6: /* HFCLKOUT_DEV_GRP */
1415
case 0xe9: /* 2KCLKOUT_DEV_GRP */
1416
case 0xec: /* TRITON_RESET_DEV_GRP */
1417
case 0xef: /* MAINREF_DEV_GRP */
1418
s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0);
1420
case 0x75: /* VAUX1_DEDICATED */
1421
case 0x7d: /* VAUX3_DEDICATED */
1422
case 0x8d: /* VPLL1_DEDICATED */
1423
case 0x95: /* VSIM_DEDICATED */
1424
if (s->twl4030->key_tst)
1425
s->reg_data[addr] = value & 0x77;
1427
s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
1429
case 0x79: /* VAUX2_DEDICATED */
1430
case 0x81: /* VAUX4_DEDICATED */
1431
case 0x91: /* VPLL2_DEDICATED */
1432
case 0xa5: /* VINTDIG_DEDICATED */
1433
if (s->twl4030->key_tst)
1434
s->reg_data[addr] = value & 0x7f;
1436
s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
1438
case 0x85: /* VMMC1_DEDICATED */
1439
case 0x99: /* VDAC_DEDICATED */
1440
if (s->twl4030->key_tst)
1441
s->reg_data[addr] = value & 0x73;
1443
s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
1445
case 0x89: /* VMMC2_DEDICATED */
1446
if (s->twl4030->key_tst)
1447
s->reg_data[addr] = value & 0x7f;
1449
s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
1451
case 0x9d: /* VINTANA1_DEDICATED */
1452
if (s->twl4030->key_tst)
1453
s->reg_data[addr] = value & 0x70;
1455
case 0xa1: /* VINTANA2_DEDICATED */
1456
if (s->twl4030->key_tst)
1457
s->reg_data[addr] = value & 0x71;
1459
s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x01);
1461
case 0x74: /* VAUX1_REMAP */
1462
case 0x78: /* VAUX2_REMAP */
1463
case 0x7c: /* VAUX3_REMAP */
1464
case 0x80: /* VAUX4_REMAP */
1465
case 0x84: /* VMMC1_REMAP */
1466
case 0x88: /* VMMC2_REMAP */
1467
case 0x8c: /* VPLL1_REMAP */
1468
case 0x90: /* VPLL2_REMAP */
1469
case 0x94: /* VSIM_REMAP */
1470
case 0x98: /* VDAC_REMAP */
1471
case 0x9c: /* VINTANA1_REMAP */
1472
case 0xa0: /* VINTANA2_REMAP */
1473
case 0xa4: /* VINTDIG_REMAP */
1474
case 0xa8: /* VIO_REMAP */
1475
case 0xb2: /* VDD1_REMAP */
1476
case 0xc0: /* VDD2_REMAP */
1477
case 0xce: /* VUSB1V5_REMAP */
1478
case 0xd1: /* VUSB1V8_REMAP */
1479
case 0xd4: /* VUSB3V1_REMAP */
1480
case 0xdc: /* REGEN_REMAP */
1481
case 0xdf: /* NRESPWRON_REMAP */
1482
case 0xe2: /* CLKEN_REMAP */
1483
case 0xe5: /* SYSEN_REMAP */
1484
case 0xe8: /* HFCLKOUT_REMAP */
1485
case 0xeb: /* 2KCLKOUT_REMAP */
1486
case 0xee: /* TRITON_RESET_REMAP */
1487
case 0xf1: /* MAINREF_REMAP */
1488
s->reg_data[addr] = value;
1490
case 0xa9: /* VIO_CFG */
1491
case 0xb3: /* VDD1_CFG */
1492
case 0xc1: /* VDD2_CFG */
1493
s->reg_data[addr] = value & 0x03;
1495
case 0xab: /* VIO_TEST1 */
1496
case 0xb5: /* VDD1_TEST1 */
1497
case 0xc3: /* VDD2_TEST1 */
1498
if (s->twl4030->key_tst)
1499
s->reg_data[addr] = value;
1501
case 0xad: /* VIO_OSC */
1502
case 0xb7: /* VDD1_OSC */
1503
case 0xc5: /* VDD2_OSC */
1504
s->reg_data[addr] = value & 0x5f;
1506
case 0xae: /* VIO_RESERVED */
1507
case 0xb8: /* VDD1_RESERVED */
1508
case 0xc6: /* VDD2_RESERVED */
1510
case 0xaf: /* VIO_VSEL */
1511
s->reg_data[addr] = value & 0x01;
1513
case 0xba: /* VDD1_VMODE_CFG */
1514
case 0xc8: /* VDD2_VMODE_CFG */
1515
s->reg_data[addr] = (s->reg_data[addr] & 0x38) | (value & 0x07);
1517
case 0xd8: /* VUSB_DEDICATED1 */
1518
s->reg_data[addr] = value & 0x1f;
1520
case 0xd9: /* VUSB_DEDICATED2 */
1521
s->reg_data[addr] = value & 0x08;
1525
hw_error("%s: unknown register 0x%02x value 0x%02x",
1526
__FUNCTION__, addr, value);
1531
static void twl4030_key_setstate(TWL4030NodeState *s,
1532
int col, int row, int state)
1534
TRACE("col=%d, row=%d, state=%d", col, row, state);
1535
if (col >= 0 && col < 8 && row >= 0 && row < 8) {
1536
s->reg_data[0xd8] = col; /* KBC_REG */
1537
s->reg_data[0xd9] = row; /* KBR_REG */
1540
s->reg_data[0xdb + row] |= 1 << col; /* FULL_CODE_xx_yy */
1541
gen_int = s->reg_data[0xe8] & 0x02; /* ITKPRISING */
1543
s->reg_data[0xdb + row] &= ~(1 << col); /* FULL_CODE_xx_yy */
1544
gen_int = s->reg_data[0xe8] & 0x01; /* ITKPFALLING */
1547
s->reg_data[0xe3] |= 0x01; /* ITKPISR1 */
1548
s->reg_data[0xe5] |= 0x01; /* ITKPISR2 */
1549
twl4030_interrupt_update(s->twl4030);
1554
static void twl4030_key_handler(void *opaque, int keycode)
1556
TWL4030NodeState *s = (TWL4030NodeState *)opaque;
1557
if (!s->twl4030->extended_key && keycode == 0xe0) {
1558
s->twl4030->extended_key = 0x80;
1560
const TWL4030KeyMap *k = s->twl4030->keymap;
1561
int fullcode = (keycode & 0x7f) | (s->twl4030->extended_key);
1562
for (; k && k->code >= 0; k++) {
1563
if (k->code == fullcode) {
1564
twl4030_key_setstate(s, k->column, k->row, !(keycode & 0x80));
1567
s->twl4030->extended_key = 0;
1571
static void twl4030_node_reset(TWL4030NodeState *s,
1572
const uint8_t *reset_values)
1576
memcpy(s->reg_data, reset_values, 256);
1579
static void twl4030_node_init(TWL4030NodeState *s,
1580
twl4030_read_func read,
1581
twl4030_write_func write,
1582
const uint8_t *reset_values)
1584
s->read_func = read;
1585
s->write_func = write;
1586
twl4030_node_reset(s, reset_values);
1589
static int twl4030_48_init(I2CSlave *i2c)
1591
twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
1592
twl4030_48_read, twl4030_48_write,
1593
addr_48_reset_values);
1597
static int twl4030_49_init(I2CSlave *i2c)
1599
twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
1600
twl4030_49_read, twl4030_49_write,
1601
addr_49_reset_values);
1605
static int twl4030_4a_init(I2CSlave *i2c)
1607
TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1608
twl4030_node_init(s,
1609
twl4030_4a_read, twl4030_4a_write,
1610
addr_4a_reset_values);
1611
qemu_add_kbd_event_handler(twl4030_key_handler, s);
1615
static int twl4030_4b_init(I2CSlave *i2c)
1617
twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
1618
twl4030_4b_read, twl4030_4b_write,
1619
addr_4b_reset_values);
1623
static void twl4030_event(I2CSlave *i2c, enum i2c_event event)
1625
if (event == I2C_START_SEND) {
1626
TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1631
static int twl4030_rx(I2CSlave *i2c)
1633
TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1634
return s->read_func(s, s->reg++);
1637
static int twl4030_tx(I2CSlave *i2c, uint8_t data)
1639
TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1644
s->write_func(s, s->reg++, data);
1649
static void twl4030_reset(void *opaque)
1651
TWL4030State *s = opaque;
1653
timer_del(s->alarm_timer);
1654
timer_del(s->periodic_timer);
1656
twl4030_node_reset(s->i2c[0], addr_48_reset_values);
1657
twl4030_node_reset(s->i2c[1], addr_49_reset_values);
1658
twl4030_node_reset(s->i2c[2], addr_4a_reset_values);
1659
twl4030_node_reset(s->i2c[3], addr_4b_reset_values);
1661
s->extended_key = 0;
1665
memset(s->seq_mem, 0, sizeof(s->seq_mem));
1667
/* TODO: indicate correct reset reason */
1670
static void twl4030_48_class_init(ObjectClass *klass, void *data)
1672
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1673
k->init = twl4030_48_init;
1674
k->event = twl4030_event;
1675
k->recv = twl4030_rx;
1676
k->send = twl4030_tx;
1679
static void twl4030_49_class_init(ObjectClass *klass, void *data)
1681
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1682
k->init = twl4030_49_init;
1683
k->event = twl4030_event;
1684
k->recv = twl4030_rx;
1685
k->send = twl4030_tx;
1688
static void twl4030_4a_class_init(ObjectClass *klass, void *data)
1690
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1691
k->init = twl4030_4a_init;
1692
k->event = twl4030_event;
1693
k->recv = twl4030_rx;
1694
k->send = twl4030_tx;
1696
static void twl4030_4b_class_init(ObjectClass *klass, void *data)
1698
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1699
k->init = twl4030_4b_init;
1700
k->event = twl4030_event;
1701
k->recv = twl4030_rx;
1702
k->send = twl4030_tx;
1705
static TypeInfo twl4030_info[] = {
1707
.name = "twl4030_48",
1708
.parent = TYPE_I2C_SLAVE,
1709
.instance_size = sizeof(TWL4030NodeState),
1710
.class_init = twl4030_48_class_init,
1713
.name = "twl4030_49",
1714
.parent = TYPE_I2C_SLAVE,
1715
.instance_size = sizeof(TWL4030NodeState),
1716
.class_init = twl4030_49_class_init,
1719
.name = "twl4030_4a",
1720
.parent = TYPE_I2C_SLAVE,
1721
.instance_size = sizeof(TWL4030NodeState),
1722
.class_init = twl4030_4a_class_init,
1725
.name = "twl4030_4b",
1726
.parent = TYPE_I2C_SLAVE,
1727
.instance_size = sizeof(TWL4030NodeState),
1728
.class_init = twl4030_4b_class_init,
1732
void *twl4030_init(i2c_bus *bus, qemu_irq irq1, qemu_irq irq2,
1733
const TWL4030KeyMap *keymap)
1735
TWL4030State *s = (TWL4030State *)g_malloc0(sizeof(*s));
1743
s->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, twl4030_alarm, s);
1744
s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, twl4030_periodic, s);
1747
for (i = 0; i < ARRAY_SIZE(twl4030_info); i++) {
1748
DeviceState *ds = i2c_create_slave(bus, twl4030_info[i].name,
1750
s->i2c[i] = FROM_I2C_SLAVE(TWL4030NodeState, I2C_SLAVE(ds));
1751
s->i2c[i]->twl4030 = s;
1754
qemu_register_reset(twl4030_reset, s);
1758
void *twl5031_init(i2c_bus *bus, qemu_irq irq1, qemu_irq irq2,
1759
const TWL4030KeyMap *keymap)
1761
TWL4030State *s = twl4030_init(bus, irq1, irq2, keymap);
1766
void twl4030_set_powerbutton_state(void *opaque, int pressed)
1768
TWL4030State *s = opaque;
1770
if (!(s->i2c[3]->reg_data[0x45] & 0x01) && /* STS_PWON */
1771
(s->i2c[3]->reg_data[0x33] & 0x02)) { /* PWRON_RISING */
1772
s->i2c[3]->reg_data[0x2e] |= 0x01; /* PWRON */
1773
s->i2c[3]->reg_data[0x30] |= 0x01; /* PWRON */
1774
twl4030_interrupt_update(s);
1776
s->i2c[3]->reg_data[0x45] |= 0x01; /* STS_PWON */
1778
if ((s->i2c[3]->reg_data[0x45] & 0x01) && /* STS_PWON */
1779
(s->i2c[3]->reg_data[0x33] & 0x01)) { /* PWRON_FALLING */
1780
s->i2c[3]->reg_data[0x2e] |= 0x01; /* PWRON */
1781
s->i2c[3]->reg_data[0x30] |= 0x01; /* PWRON */
1782
twl4030_interrupt_update(s);
1784
s->i2c[3]->reg_data[0x45] &= ~0x01; /* STS_PWON */
1788
void twl4030_madc_attach(void *opaque, twl4030_madc_callback cb)
1790
TWL4030State *s = opaque;
1793
"%s: warning - overriding previously registered callback\n",
1799
static void twl4030_register_types(void)
1801
TypeInfo *p = twl4030_info;
1803
for (i = 0; i < ARRAY_SIZE(twl4030_info); p++, i++) {
1804
type_register_static(p);
1808
type_init(twl4030_register_types);