|
1 /* |
|
2 * TI TWL92230C energy-management companion device for the OMAP24xx. |
|
3 * Aka. Menelaus (N4200 MENELAUS1_V2.2) |
|
4 * |
|
5 * Copyright (C) 2008 Nokia Corporation |
|
6 * Written by Andrzej Zaborowski <andrew@openedhand.com> |
|
7 * |
|
8 * This program is free software; you can redistribute it and/or |
|
9 * modify it under the terms of the GNU General Public License as |
|
10 * published by the Free Software Foundation; either version 2 or |
|
11 * (at your option) version 3 of the License. |
|
12 * |
|
13 * This program is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 * GNU General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU General Public License |
|
19 * along with this program; if not, write to the Free Software |
|
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
|
21 * MA 02111-1307 USA |
|
22 */ |
|
23 |
|
24 #include "hw.h" |
|
25 #include "qemu-timer.h" |
|
26 #include "i2c.h" |
|
27 #include "sysemu.h" |
|
28 #include "console.h" |
|
29 |
|
30 #define VERBOSE 1 |
|
31 |
|
32 struct menelaus_s { |
|
33 i2c_slave i2c; |
|
34 qemu_irq irq; |
|
35 |
|
36 int firstbyte; |
|
37 uint8_t reg; |
|
38 |
|
39 uint8_t vcore[5]; |
|
40 uint8_t dcdc[3]; |
|
41 uint8_t ldo[8]; |
|
42 uint8_t sleep[2]; |
|
43 uint8_t osc; |
|
44 uint8_t detect; |
|
45 uint16_t mask; |
|
46 uint16_t status; |
|
47 uint8_t dir; |
|
48 uint8_t inputs; |
|
49 uint8_t outputs; |
|
50 uint8_t bbsms; |
|
51 uint8_t pull[4]; |
|
52 uint8_t mmc_ctrl[3]; |
|
53 uint8_t mmc_debounce; |
|
54 struct { |
|
55 uint8_t ctrl; |
|
56 uint16_t comp; |
|
57 QEMUTimer *hz_tm; |
|
58 int64_t next; |
|
59 struct tm tm; |
|
60 struct tm new; |
|
61 struct tm alm; |
|
62 int sec_offset; |
|
63 int alm_sec; |
|
64 int next_comp; |
|
65 } rtc; |
|
66 qemu_irq handler[3]; |
|
67 qemu_irq *in; |
|
68 int pwrbtn_state; |
|
69 qemu_irq pwrbtn; |
|
70 }; |
|
71 |
|
72 static inline void menelaus_update(struct menelaus_s *s) |
|
73 { |
|
74 qemu_set_irq(s->irq, s->status & ~s->mask); |
|
75 } |
|
76 |
|
77 static inline void menelaus_rtc_start(struct menelaus_s *s) |
|
78 { |
|
79 s->rtc.next =+ qemu_get_clock(rt_clock); |
|
80 qemu_mod_timer(s->rtc.hz_tm, s->rtc.next); |
|
81 } |
|
82 |
|
83 static inline void menelaus_rtc_stop(struct menelaus_s *s) |
|
84 { |
|
85 qemu_del_timer(s->rtc.hz_tm); |
|
86 s->rtc.next =- qemu_get_clock(rt_clock); |
|
87 if (s->rtc.next < 1) |
|
88 s->rtc.next = 1; |
|
89 } |
|
90 |
|
91 static void menelaus_rtc_update(struct menelaus_s *s) |
|
92 { |
|
93 qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset); |
|
94 } |
|
95 |
|
96 static void menelaus_alm_update(struct menelaus_s *s) |
|
97 { |
|
98 if ((s->rtc.ctrl & 3) == 3) |
|
99 s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset; |
|
100 } |
|
101 |
|
102 static void menelaus_rtc_hz(void *opaque) |
|
103 { |
|
104 struct menelaus_s *s = (struct menelaus_s *) opaque; |
|
105 |
|
106 s->rtc.next_comp --; |
|
107 s->rtc.alm_sec --; |
|
108 s->rtc.next += 1000; |
|
109 qemu_mod_timer(s->rtc.hz_tm, s->rtc.next); |
|
110 if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */ |
|
111 menelaus_rtc_update(s); |
|
112 if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec) |
|
113 s->status |= 1 << 8; /* RTCTMR */ |
|
114 else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min) |
|
115 s->status |= 1 << 8; /* RTCTMR */ |
|
116 else if (!s->rtc.tm.tm_hour) |
|
117 s->status |= 1 << 8; /* RTCTMR */ |
|
118 } else |
|
119 s->status |= 1 << 8; /* RTCTMR */ |
|
120 if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */ |
|
121 if (s->rtc.alm_sec == 0) |
|
122 s->status |= 1 << 9; /* RTCALM */ |
|
123 /* TODO: wake-up */ |
|
124 } |
|
125 if (s->rtc.next_comp <= 0) { |
|
126 s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000); |
|
127 s->rtc.next_comp = 3600; |
|
128 } |
|
129 menelaus_update(s); |
|
130 } |
|
131 |
|
132 static void menelaus_reset(i2c_slave *i2c) |
|
133 { |
|
134 struct menelaus_s *s = (struct menelaus_s *) i2c; |
|
135 s->reg = 0x00; |
|
136 |
|
137 s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */ |
|
138 s->vcore[1] = 0x05; |
|
139 s->vcore[2] = 0x02; |
|
140 s->vcore[3] = 0x0c; |
|
141 s->vcore[4] = 0x03; |
|
142 s->dcdc[0] = 0x33; /* Depends on wiring */ |
|
143 s->dcdc[1] = 0x03; |
|
144 s->dcdc[2] = 0x00; |
|
145 s->ldo[0] = 0x95; |
|
146 s->ldo[1] = 0x7e; |
|
147 s->ldo[2] = 0x00; |
|
148 s->ldo[3] = 0x00; /* Depends on wiring */ |
|
149 s->ldo[4] = 0x03; /* Depends on wiring */ |
|
150 s->ldo[5] = 0x00; |
|
151 s->ldo[6] = 0x00; |
|
152 s->ldo[7] = 0x00; |
|
153 s->sleep[0] = 0x00; |
|
154 s->sleep[1] = 0x00; |
|
155 s->osc = 0x01; |
|
156 s->detect = 0x09; |
|
157 s->mask = 0x0fff; |
|
158 s->status = 0; |
|
159 s->dir = 0x07; |
|
160 s->outputs = 0x00; |
|
161 s->bbsms = 0x00; |
|
162 s->pull[0] = 0x00; |
|
163 s->pull[1] = 0x00; |
|
164 s->pull[2] = 0x00; |
|
165 s->pull[3] = 0x00; |
|
166 s->mmc_ctrl[0] = 0x03; |
|
167 s->mmc_ctrl[1] = 0xc0; |
|
168 s->mmc_ctrl[2] = 0x00; |
|
169 s->mmc_debounce = 0x05; |
|
170 |
|
171 if (s->rtc.ctrl & 1) |
|
172 menelaus_rtc_stop(s); |
|
173 s->rtc.ctrl = 0x00; |
|
174 s->rtc.comp = 0x0000; |
|
175 s->rtc.next = 1000; |
|
176 s->rtc.sec_offset = 0; |
|
177 s->rtc.next_comp = 1800; |
|
178 s->rtc.alm_sec = 1800; |
|
179 s->rtc.alm.tm_sec = 0x00; |
|
180 s->rtc.alm.tm_min = 0x00; |
|
181 s->rtc.alm.tm_hour = 0x00; |
|
182 s->rtc.alm.tm_mday = 0x01; |
|
183 s->rtc.alm.tm_mon = 0x00; |
|
184 s->rtc.alm.tm_year = 2004; |
|
185 menelaus_update(s); |
|
186 } |
|
187 |
|
188 static inline uint8_t to_bcd(int val) |
|
189 { |
|
190 return ((val / 10) << 4) | (val % 10); |
|
191 } |
|
192 |
|
193 static inline int from_bcd(uint8_t val) |
|
194 { |
|
195 return ((val >> 4) * 10) + (val & 0x0f); |
|
196 } |
|
197 |
|
198 static void menelaus_gpio_set(void *opaque, int line, int level) |
|
199 { |
|
200 struct menelaus_s *s = (struct menelaus_s *) opaque; |
|
201 |
|
202 /* No interrupt generated */ |
|
203 s->inputs &= ~(1 << line); |
|
204 s->inputs |= level << line; |
|
205 } |
|
206 |
|
207 static void menelaus_pwrbtn_set(void *opaque, int line, int level) |
|
208 { |
|
209 struct menelaus_s *s = (struct menelaus_s *) opaque; |
|
210 |
|
211 if (!s->pwrbtn_state && level) { |
|
212 s->status |= 1 << 11; /* PSHBTN */ |
|
213 menelaus_update(s); |
|
214 } |
|
215 s->pwrbtn_state = level; |
|
216 } |
|
217 |
|
218 #define MENELAUS_REV 0x01 |
|
219 #define MENELAUS_VCORE_CTRL1 0x02 |
|
220 #define MENELAUS_VCORE_CTRL2 0x03 |
|
221 #define MENELAUS_VCORE_CTRL3 0x04 |
|
222 #define MENELAUS_VCORE_CTRL4 0x05 |
|
223 #define MENELAUS_VCORE_CTRL5 0x06 |
|
224 #define MENELAUS_DCDC_CTRL1 0x07 |
|
225 #define MENELAUS_DCDC_CTRL2 0x08 |
|
226 #define MENELAUS_DCDC_CTRL3 0x09 |
|
227 #define MENELAUS_LDO_CTRL1 0x0a |
|
228 #define MENELAUS_LDO_CTRL2 0x0b |
|
229 #define MENELAUS_LDO_CTRL3 0x0c |
|
230 #define MENELAUS_LDO_CTRL4 0x0d |
|
231 #define MENELAUS_LDO_CTRL5 0x0e |
|
232 #define MENELAUS_LDO_CTRL6 0x0f |
|
233 #define MENELAUS_LDO_CTRL7 0x10 |
|
234 #define MENELAUS_LDO_CTRL8 0x11 |
|
235 #define MENELAUS_SLEEP_CTRL1 0x12 |
|
236 #define MENELAUS_SLEEP_CTRL2 0x13 |
|
237 #define MENELAUS_DEVICE_OFF 0x14 |
|
238 #define MENELAUS_OSC_CTRL 0x15 |
|
239 #define MENELAUS_DETECT_CTRL 0x16 |
|
240 #define MENELAUS_INT_MASK1 0x17 |
|
241 #define MENELAUS_INT_MASK2 0x18 |
|
242 #define MENELAUS_INT_STATUS1 0x19 |
|
243 #define MENELAUS_INT_STATUS2 0x1a |
|
244 #define MENELAUS_INT_ACK1 0x1b |
|
245 #define MENELAUS_INT_ACK2 0x1c |
|
246 #define MENELAUS_GPIO_CTRL 0x1d |
|
247 #define MENELAUS_GPIO_IN 0x1e |
|
248 #define MENELAUS_GPIO_OUT 0x1f |
|
249 #define MENELAUS_BBSMS 0x20 |
|
250 #define MENELAUS_RTC_CTRL 0x21 |
|
251 #define MENELAUS_RTC_UPDATE 0x22 |
|
252 #define MENELAUS_RTC_SEC 0x23 |
|
253 #define MENELAUS_RTC_MIN 0x24 |
|
254 #define MENELAUS_RTC_HR 0x25 |
|
255 #define MENELAUS_RTC_DAY 0x26 |
|
256 #define MENELAUS_RTC_MON 0x27 |
|
257 #define MENELAUS_RTC_YR 0x28 |
|
258 #define MENELAUS_RTC_WKDAY 0x29 |
|
259 #define MENELAUS_RTC_AL_SEC 0x2a |
|
260 #define MENELAUS_RTC_AL_MIN 0x2b |
|
261 #define MENELAUS_RTC_AL_HR 0x2c |
|
262 #define MENELAUS_RTC_AL_DAY 0x2d |
|
263 #define MENELAUS_RTC_AL_MON 0x2e |
|
264 #define MENELAUS_RTC_AL_YR 0x2f |
|
265 #define MENELAUS_RTC_COMP_MSB 0x30 |
|
266 #define MENELAUS_RTC_COMP_LSB 0x31 |
|
267 #define MENELAUS_S1_PULL_EN 0x32 |
|
268 #define MENELAUS_S1_PULL_DIR 0x33 |
|
269 #define MENELAUS_S2_PULL_EN 0x34 |
|
270 #define MENELAUS_S2_PULL_DIR 0x35 |
|
271 #define MENELAUS_MCT_CTRL1 0x36 |
|
272 #define MENELAUS_MCT_CTRL2 0x37 |
|
273 #define MENELAUS_MCT_CTRL3 0x38 |
|
274 #define MENELAUS_MCT_PIN_ST 0x39 |
|
275 #define MENELAUS_DEBOUNCE1 0x3a |
|
276 |
|
277 static uint8_t menelaus_read(void *opaque, uint8_t addr) |
|
278 { |
|
279 struct menelaus_s *s = (struct menelaus_s *) opaque; |
|
280 int reg = 0; |
|
281 |
|
282 switch (addr) { |
|
283 case MENELAUS_REV: |
|
284 return 0x22; |
|
285 |
|
286 case MENELAUS_VCORE_CTRL5: reg ++; |
|
287 case MENELAUS_VCORE_CTRL4: reg ++; |
|
288 case MENELAUS_VCORE_CTRL3: reg ++; |
|
289 case MENELAUS_VCORE_CTRL2: reg ++; |
|
290 case MENELAUS_VCORE_CTRL1: |
|
291 return s->vcore[reg]; |
|
292 |
|
293 case MENELAUS_DCDC_CTRL3: reg ++; |
|
294 case MENELAUS_DCDC_CTRL2: reg ++; |
|
295 case MENELAUS_DCDC_CTRL1: |
|
296 return s->dcdc[reg]; |
|
297 |
|
298 case MENELAUS_LDO_CTRL8: reg ++; |
|
299 case MENELAUS_LDO_CTRL7: reg ++; |
|
300 case MENELAUS_LDO_CTRL6: reg ++; |
|
301 case MENELAUS_LDO_CTRL5: reg ++; |
|
302 case MENELAUS_LDO_CTRL4: reg ++; |
|
303 case MENELAUS_LDO_CTRL3: reg ++; |
|
304 case MENELAUS_LDO_CTRL2: reg ++; |
|
305 case MENELAUS_LDO_CTRL1: |
|
306 return s->ldo[reg]; |
|
307 |
|
308 case MENELAUS_SLEEP_CTRL2: reg ++; |
|
309 case MENELAUS_SLEEP_CTRL1: |
|
310 return s->sleep[reg]; |
|
311 |
|
312 case MENELAUS_DEVICE_OFF: |
|
313 return 0; |
|
314 |
|
315 case MENELAUS_OSC_CTRL: |
|
316 return s->osc | (1 << 7); /* CLK32K_GOOD */ |
|
317 |
|
318 case MENELAUS_DETECT_CTRL: |
|
319 return s->detect; |
|
320 |
|
321 case MENELAUS_INT_MASK1: |
|
322 return (s->mask >> 0) & 0xff; |
|
323 case MENELAUS_INT_MASK2: |
|
324 return (s->mask >> 8) & 0xff; |
|
325 |
|
326 case MENELAUS_INT_STATUS1: |
|
327 return (s->status >> 0) & 0xff; |
|
328 case MENELAUS_INT_STATUS2: |
|
329 return (s->status >> 8) & 0xff; |
|
330 |
|
331 case MENELAUS_INT_ACK1: |
|
332 case MENELAUS_INT_ACK2: |
|
333 return 0; |
|
334 |
|
335 case MENELAUS_GPIO_CTRL: |
|
336 return s->dir; |
|
337 case MENELAUS_GPIO_IN: |
|
338 return s->inputs | (~s->dir & s->outputs); |
|
339 case MENELAUS_GPIO_OUT: |
|
340 return s->outputs; |
|
341 |
|
342 case MENELAUS_BBSMS: |
|
343 return s->bbsms; |
|
344 |
|
345 case MENELAUS_RTC_CTRL: |
|
346 return s->rtc.ctrl; |
|
347 case MENELAUS_RTC_UPDATE: |
|
348 return 0x00; |
|
349 case MENELAUS_RTC_SEC: |
|
350 menelaus_rtc_update(s); |
|
351 return to_bcd(s->rtc.tm.tm_sec); |
|
352 case MENELAUS_RTC_MIN: |
|
353 menelaus_rtc_update(s); |
|
354 return to_bcd(s->rtc.tm.tm_min); |
|
355 case MENELAUS_RTC_HR: |
|
356 menelaus_rtc_update(s); |
|
357 if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ |
|
358 return to_bcd((s->rtc.tm.tm_hour % 12) + 1) | |
|
359 (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */ |
|
360 else |
|
361 return to_bcd(s->rtc.tm.tm_hour); |
|
362 case MENELAUS_RTC_DAY: |
|
363 menelaus_rtc_update(s); |
|
364 return to_bcd(s->rtc.tm.tm_mday); |
|
365 case MENELAUS_RTC_MON: |
|
366 menelaus_rtc_update(s); |
|
367 return to_bcd(s->rtc.tm.tm_mon + 1); |
|
368 case MENELAUS_RTC_YR: |
|
369 menelaus_rtc_update(s); |
|
370 return to_bcd(s->rtc.tm.tm_year - 2000); |
|
371 case MENELAUS_RTC_WKDAY: |
|
372 menelaus_rtc_update(s); |
|
373 return to_bcd(s->rtc.tm.tm_wday); |
|
374 case MENELAUS_RTC_AL_SEC: |
|
375 return to_bcd(s->rtc.alm.tm_sec); |
|
376 case MENELAUS_RTC_AL_MIN: |
|
377 return to_bcd(s->rtc.alm.tm_min); |
|
378 case MENELAUS_RTC_AL_HR: |
|
379 if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ |
|
380 return to_bcd((s->rtc.alm.tm_hour % 12) + 1) | |
|
381 (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */ |
|
382 else |
|
383 return to_bcd(s->rtc.alm.tm_hour); |
|
384 case MENELAUS_RTC_AL_DAY: |
|
385 return to_bcd(s->rtc.alm.tm_mday); |
|
386 case MENELAUS_RTC_AL_MON: |
|
387 return to_bcd(s->rtc.alm.tm_mon + 1); |
|
388 case MENELAUS_RTC_AL_YR: |
|
389 return to_bcd(s->rtc.alm.tm_year - 2000); |
|
390 case MENELAUS_RTC_COMP_MSB: |
|
391 return (s->rtc.comp >> 8) & 0xff; |
|
392 case MENELAUS_RTC_COMP_LSB: |
|
393 return (s->rtc.comp >> 0) & 0xff; |
|
394 |
|
395 case MENELAUS_S1_PULL_EN: |
|
396 return s->pull[0]; |
|
397 case MENELAUS_S1_PULL_DIR: |
|
398 return s->pull[1]; |
|
399 case MENELAUS_S2_PULL_EN: |
|
400 return s->pull[2]; |
|
401 case MENELAUS_S2_PULL_DIR: |
|
402 return s->pull[3]; |
|
403 |
|
404 case MENELAUS_MCT_CTRL3: reg ++; |
|
405 case MENELAUS_MCT_CTRL2: reg ++; |
|
406 case MENELAUS_MCT_CTRL1: |
|
407 return s->mmc_ctrl[reg]; |
|
408 case MENELAUS_MCT_PIN_ST: |
|
409 /* TODO: return the real Card Detect */ |
|
410 return 0; |
|
411 case MENELAUS_DEBOUNCE1: |
|
412 return s->mmc_debounce; |
|
413 |
|
414 default: |
|
415 #ifdef VERBOSE |
|
416 printf("%s: unknown register %02x\n", __FUNCTION__, addr); |
|
417 #endif |
|
418 break; |
|
419 } |
|
420 return 0; |
|
421 } |
|
422 |
|
423 static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) |
|
424 { |
|
425 struct menelaus_s *s = (struct menelaus_s *) opaque; |
|
426 int line; |
|
427 int reg = 0; |
|
428 struct tm tm; |
|
429 |
|
430 switch (addr) { |
|
431 case MENELAUS_VCORE_CTRL1: |
|
432 s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12); |
|
433 break; |
|
434 case MENELAUS_VCORE_CTRL2: |
|
435 s->vcore[1] = value; |
|
436 break; |
|
437 case MENELAUS_VCORE_CTRL3: |
|
438 s->vcore[2] = MIN(value & 0x1f, 0x12); |
|
439 break; |
|
440 case MENELAUS_VCORE_CTRL4: |
|
441 s->vcore[3] = MIN(value & 0x1f, 0x12); |
|
442 break; |
|
443 case MENELAUS_VCORE_CTRL5: |
|
444 s->vcore[4] = value & 3; |
|
445 /* XXX |
|
446 * auto set to 3 on M_Active, nRESWARM |
|
447 * auto set to 0 on M_WaitOn, M_Backup |
|
448 */ |
|
449 break; |
|
450 |
|
451 case MENELAUS_DCDC_CTRL1: |
|
452 s->dcdc[0] = value & 0x3f; |
|
453 break; |
|
454 case MENELAUS_DCDC_CTRL2: |
|
455 s->dcdc[1] = value & 0x07; |
|
456 /* XXX |
|
457 * auto set to 3 on M_Active, nRESWARM |
|
458 * auto set to 0 on M_WaitOn, M_Backup |
|
459 */ |
|
460 break; |
|
461 case MENELAUS_DCDC_CTRL3: |
|
462 s->dcdc[2] = value & 0x07; |
|
463 break; |
|
464 |
|
465 case MENELAUS_LDO_CTRL1: |
|
466 s->ldo[0] = value; |
|
467 break; |
|
468 case MENELAUS_LDO_CTRL2: |
|
469 s->ldo[1] = value & 0x7f; |
|
470 /* XXX |
|
471 * auto set to 0x7e on M_WaitOn, M_Backup |
|
472 */ |
|
473 break; |
|
474 case MENELAUS_LDO_CTRL3: |
|
475 s->ldo[2] = value & 3; |
|
476 /* XXX |
|
477 * auto set to 3 on M_Active, nRESWARM |
|
478 * auto set to 0 on M_WaitOn, M_Backup |
|
479 */ |
|
480 break; |
|
481 case MENELAUS_LDO_CTRL4: |
|
482 s->ldo[3] = value & 3; |
|
483 /* XXX |
|
484 * auto set to 3 on M_Active, nRESWARM |
|
485 * auto set to 0 on M_WaitOn, M_Backup |
|
486 */ |
|
487 break; |
|
488 case MENELAUS_LDO_CTRL5: |
|
489 s->ldo[4] = value & 3; |
|
490 /* XXX |
|
491 * auto set to 3 on M_Active, nRESWARM |
|
492 * auto set to 0 on M_WaitOn, M_Backup |
|
493 */ |
|
494 break; |
|
495 case MENELAUS_LDO_CTRL6: |
|
496 s->ldo[5] = value & 3; |
|
497 break; |
|
498 case MENELAUS_LDO_CTRL7: |
|
499 s->ldo[6] = value & 3; |
|
500 break; |
|
501 case MENELAUS_LDO_CTRL8: |
|
502 s->ldo[7] = value & 3; |
|
503 break; |
|
504 |
|
505 case MENELAUS_SLEEP_CTRL2: reg ++; |
|
506 case MENELAUS_SLEEP_CTRL1: |
|
507 s->sleep[reg] = value; |
|
508 break; |
|
509 |
|
510 case MENELAUS_DEVICE_OFF: |
|
511 if (value & 1) |
|
512 menelaus_reset(&s->i2c); |
|
513 break; |
|
514 |
|
515 case MENELAUS_OSC_CTRL: |
|
516 s->osc = value & 7; |
|
517 break; |
|
518 |
|
519 case MENELAUS_DETECT_CTRL: |
|
520 s->detect = value & 0x7f; |
|
521 break; |
|
522 |
|
523 case MENELAUS_INT_MASK1: |
|
524 s->mask &= 0xf00; |
|
525 s->mask |= value << 0; |
|
526 menelaus_update(s); |
|
527 break; |
|
528 case MENELAUS_INT_MASK2: |
|
529 s->mask &= 0x0ff; |
|
530 s->mask |= value << 8; |
|
531 menelaus_update(s); |
|
532 break; |
|
533 |
|
534 case MENELAUS_INT_ACK1: |
|
535 s->status &= ~(((uint16_t) value) << 0); |
|
536 menelaus_update(s); |
|
537 break; |
|
538 case MENELAUS_INT_ACK2: |
|
539 s->status &= ~(((uint16_t) value) << 8); |
|
540 menelaus_update(s); |
|
541 break; |
|
542 |
|
543 case MENELAUS_GPIO_CTRL: |
|
544 for (line = 0; line < 3; line ++) |
|
545 if (((s->dir ^ value) >> line) & 1) |
|
546 if (s->handler[line]) |
|
547 qemu_set_irq(s->handler[line], |
|
548 ((s->outputs & ~s->dir) >> line) & 1); |
|
549 s->dir = value & 0x67; |
|
550 break; |
|
551 case MENELAUS_GPIO_OUT: |
|
552 for (line = 0; line < 3; line ++) |
|
553 if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) |
|
554 if (s->handler[line]) |
|
555 qemu_set_irq(s->handler[line], (s->outputs >> line) & 1); |
|
556 s->outputs = value & 0x07; |
|
557 break; |
|
558 |
|
559 case MENELAUS_BBSMS: |
|
560 s->bbsms = 0x0d; |
|
561 break; |
|
562 |
|
563 case MENELAUS_RTC_CTRL: |
|
564 if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */ |
|
565 if (value & 1) |
|
566 menelaus_rtc_start(s); |
|
567 else |
|
568 menelaus_rtc_stop(s); |
|
569 } |
|
570 s->rtc.ctrl = value & 0x1f; |
|
571 menelaus_alm_update(s); |
|
572 break; |
|
573 case MENELAUS_RTC_UPDATE: |
|
574 menelaus_rtc_update(s); |
|
575 memcpy(&tm, &s->rtc.tm, sizeof(tm)); |
|
576 switch (value & 0xf) { |
|
577 case 0: |
|
578 break; |
|
579 case 1: |
|
580 tm.tm_sec = s->rtc.new.tm_sec; |
|
581 break; |
|
582 case 2: |
|
583 tm.tm_min = s->rtc.new.tm_min; |
|
584 break; |
|
585 case 3: |
|
586 if (s->rtc.new.tm_hour > 23) |
|
587 goto rtc_badness; |
|
588 tm.tm_hour = s->rtc.new.tm_hour; |
|
589 break; |
|
590 case 4: |
|
591 if (s->rtc.new.tm_mday < 1) |
|
592 goto rtc_badness; |
|
593 /* TODO check range */ |
|
594 tm.tm_mday = s->rtc.new.tm_mday; |
|
595 break; |
|
596 case 5: |
|
597 if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) |
|
598 goto rtc_badness; |
|
599 tm.tm_mon = s->rtc.new.tm_mon; |
|
600 break; |
|
601 case 6: |
|
602 tm.tm_year = s->rtc.new.tm_year; |
|
603 break; |
|
604 case 7: |
|
605 /* TODO set .tm_mday instead */ |
|
606 tm.tm_wday = s->rtc.new.tm_wday; |
|
607 break; |
|
608 case 8: |
|
609 if (s->rtc.new.tm_hour > 23) |
|
610 goto rtc_badness; |
|
611 if (s->rtc.new.tm_mday < 1) |
|
612 goto rtc_badness; |
|
613 if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) |
|
614 goto rtc_badness; |
|
615 tm.tm_sec = s->rtc.new.tm_sec; |
|
616 tm.tm_min = s->rtc.new.tm_min; |
|
617 tm.tm_hour = s->rtc.new.tm_hour; |
|
618 tm.tm_mday = s->rtc.new.tm_mday; |
|
619 tm.tm_mon = s->rtc.new.tm_mon; |
|
620 tm.tm_year = s->rtc.new.tm_year; |
|
621 break; |
|
622 rtc_badness: |
|
623 default: |
|
624 fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n", |
|
625 __FUNCTION__, value); |
|
626 s->status |= 1 << 10; /* RTCERR */ |
|
627 menelaus_update(s); |
|
628 } |
|
629 s->rtc.sec_offset = qemu_timedate_diff(&tm); |
|
630 break; |
|
631 case MENELAUS_RTC_SEC: |
|
632 s->rtc.tm.tm_sec = from_bcd(value & 0x7f); |
|
633 break; |
|
634 case MENELAUS_RTC_MIN: |
|
635 s->rtc.tm.tm_min = from_bcd(value & 0x7f); |
|
636 break; |
|
637 case MENELAUS_RTC_HR: |
|
638 s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ |
|
639 MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : |
|
640 from_bcd(value & 0x3f); |
|
641 break; |
|
642 case MENELAUS_RTC_DAY: |
|
643 s->rtc.tm.tm_mday = from_bcd(value); |
|
644 break; |
|
645 case MENELAUS_RTC_MON: |
|
646 s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1; |
|
647 break; |
|
648 case MENELAUS_RTC_YR: |
|
649 s->rtc.tm.tm_year = 2000 + from_bcd(value); |
|
650 break; |
|
651 case MENELAUS_RTC_WKDAY: |
|
652 s->rtc.tm.tm_mday = from_bcd(value); |
|
653 break; |
|
654 case MENELAUS_RTC_AL_SEC: |
|
655 s->rtc.alm.tm_sec = from_bcd(value & 0x7f); |
|
656 menelaus_alm_update(s); |
|
657 break; |
|
658 case MENELAUS_RTC_AL_MIN: |
|
659 s->rtc.alm.tm_min = from_bcd(value & 0x7f); |
|
660 menelaus_alm_update(s); |
|
661 break; |
|
662 case MENELAUS_RTC_AL_HR: |
|
663 s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ |
|
664 MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : |
|
665 from_bcd(value & 0x3f); |
|
666 menelaus_alm_update(s); |
|
667 break; |
|
668 case MENELAUS_RTC_AL_DAY: |
|
669 s->rtc.alm.tm_mday = from_bcd(value); |
|
670 menelaus_alm_update(s); |
|
671 break; |
|
672 case MENELAUS_RTC_AL_MON: |
|
673 s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1; |
|
674 menelaus_alm_update(s); |
|
675 break; |
|
676 case MENELAUS_RTC_AL_YR: |
|
677 s->rtc.alm.tm_year = 2000 + from_bcd(value); |
|
678 menelaus_alm_update(s); |
|
679 break; |
|
680 case MENELAUS_RTC_COMP_MSB: |
|
681 s->rtc.comp &= 0xff; |
|
682 s->rtc.comp |= value << 8; |
|
683 break; |
|
684 case MENELAUS_RTC_COMP_LSB: |
|
685 s->rtc.comp &= 0xff << 8; |
|
686 s->rtc.comp |= value; |
|
687 break; |
|
688 |
|
689 case MENELAUS_S1_PULL_EN: |
|
690 s->pull[0] = value; |
|
691 break; |
|
692 case MENELAUS_S1_PULL_DIR: |
|
693 s->pull[1] = value & 0x1f; |
|
694 break; |
|
695 case MENELAUS_S2_PULL_EN: |
|
696 s->pull[2] = value; |
|
697 break; |
|
698 case MENELAUS_S2_PULL_DIR: |
|
699 s->pull[3] = value & 0x1f; |
|
700 break; |
|
701 |
|
702 case MENELAUS_MCT_CTRL1: |
|
703 s->mmc_ctrl[0] = value & 0x7f; |
|
704 break; |
|
705 case MENELAUS_MCT_CTRL2: |
|
706 s->mmc_ctrl[1] = value; |
|
707 /* TODO update Card Detect interrupts */ |
|
708 break; |
|
709 case MENELAUS_MCT_CTRL3: |
|
710 s->mmc_ctrl[2] = value & 0xf; |
|
711 break; |
|
712 case MENELAUS_DEBOUNCE1: |
|
713 s->mmc_debounce = value & 0x3f; |
|
714 break; |
|
715 |
|
716 default: |
|
717 #ifdef VERBOSE |
|
718 printf("%s: unknown register %02x\n", __FUNCTION__, addr); |
|
719 #endif |
|
720 } |
|
721 } |
|
722 |
|
723 static void menelaus_event(i2c_slave *i2c, enum i2c_event event) |
|
724 { |
|
725 struct menelaus_s *s = (struct menelaus_s *) i2c; |
|
726 |
|
727 if (event == I2C_START_SEND) |
|
728 s->firstbyte = 1; |
|
729 } |
|
730 |
|
731 static int menelaus_tx(i2c_slave *i2c, uint8_t data) |
|
732 { |
|
733 struct menelaus_s *s = (struct menelaus_s *) i2c; |
|
734 /* Interpret register address byte */ |
|
735 if (s->firstbyte) { |
|
736 s->reg = data; |
|
737 s->firstbyte = 0; |
|
738 } else |
|
739 menelaus_write(s, s->reg ++, data); |
|
740 |
|
741 return 0; |
|
742 } |
|
743 |
|
744 static int menelaus_rx(i2c_slave *i2c) |
|
745 { |
|
746 struct menelaus_s *s = (struct menelaus_s *) i2c; |
|
747 |
|
748 return menelaus_read(s, s->reg ++); |
|
749 } |
|
750 |
|
751 static void tm_put(QEMUFile *f, struct tm *tm) { |
|
752 qemu_put_be16(f, tm->tm_sec); |
|
753 qemu_put_be16(f, tm->tm_min); |
|
754 qemu_put_be16(f, tm->tm_hour); |
|
755 qemu_put_be16(f, tm->tm_mday); |
|
756 qemu_put_be16(f, tm->tm_min); |
|
757 qemu_put_be16(f, tm->tm_year); |
|
758 } |
|
759 |
|
760 static void tm_get(QEMUFile *f, struct tm *tm) { |
|
761 tm->tm_sec = qemu_get_be16(f); |
|
762 tm->tm_min = qemu_get_be16(f); |
|
763 tm->tm_hour = qemu_get_be16(f); |
|
764 tm->tm_mday = qemu_get_be16(f); |
|
765 tm->tm_min = qemu_get_be16(f); |
|
766 tm->tm_year = qemu_get_be16(f); |
|
767 } |
|
768 |
|
769 static void menelaus_save(QEMUFile *f, void *opaque) |
|
770 { |
|
771 struct menelaus_s *s = (struct menelaus_s *) opaque; |
|
772 |
|
773 qemu_put_be32(f, s->firstbyte); |
|
774 qemu_put_8s(f, &s->reg); |
|
775 |
|
776 qemu_put_8s(f, &s->vcore[0]); |
|
777 qemu_put_8s(f, &s->vcore[1]); |
|
778 qemu_put_8s(f, &s->vcore[2]); |
|
779 qemu_put_8s(f, &s->vcore[3]); |
|
780 qemu_put_8s(f, &s->vcore[4]); |
|
781 qemu_put_8s(f, &s->dcdc[3]); |
|
782 qemu_put_8s(f, &s->dcdc[3]); |
|
783 qemu_put_8s(f, &s->dcdc[3]); |
|
784 qemu_put_8s(f, &s->ldo[0]); |
|
785 qemu_put_8s(f, &s->ldo[1]); |
|
786 qemu_put_8s(f, &s->ldo[2]); |
|
787 qemu_put_8s(f, &s->ldo[3]); |
|
788 qemu_put_8s(f, &s->ldo[4]); |
|
789 qemu_put_8s(f, &s->ldo[5]); |
|
790 qemu_put_8s(f, &s->ldo[6]); |
|
791 qemu_put_8s(f, &s->ldo[7]); |
|
792 qemu_put_8s(f, &s->sleep[0]); |
|
793 qemu_put_8s(f, &s->sleep[1]); |
|
794 qemu_put_8s(f, &s->osc); |
|
795 qemu_put_8s(f, &s->detect); |
|
796 qemu_put_be16s(f, &s->mask); |
|
797 qemu_put_be16s(f, &s->status); |
|
798 qemu_put_8s(f, &s->dir); |
|
799 qemu_put_8s(f, &s->inputs); |
|
800 qemu_put_8s(f, &s->outputs); |
|
801 qemu_put_8s(f, &s->bbsms); |
|
802 qemu_put_8s(f, &s->pull[0]); |
|
803 qemu_put_8s(f, &s->pull[1]); |
|
804 qemu_put_8s(f, &s->pull[2]); |
|
805 qemu_put_8s(f, &s->pull[3]); |
|
806 qemu_put_8s(f, &s->mmc_ctrl[0]); |
|
807 qemu_put_8s(f, &s->mmc_ctrl[1]); |
|
808 qemu_put_8s(f, &s->mmc_ctrl[2]); |
|
809 qemu_put_8s(f, &s->mmc_debounce); |
|
810 qemu_put_8s(f, &s->rtc.ctrl); |
|
811 qemu_put_be16s(f, &s->rtc.comp); |
|
812 /* Should be <= 1000 */ |
|
813 qemu_put_be16(f, s->rtc.next - qemu_get_clock(rt_clock)); |
|
814 tm_put(f, &s->rtc.new); |
|
815 tm_put(f, &s->rtc.alm); |
|
816 qemu_put_byte(f, s->pwrbtn_state); |
|
817 |
|
818 i2c_slave_save(f, &s->i2c); |
|
819 } |
|
820 |
|
821 static int menelaus_load(QEMUFile *f, void *opaque, int version_id) |
|
822 { |
|
823 struct menelaus_s *s = (struct menelaus_s *) opaque; |
|
824 |
|
825 s->firstbyte = qemu_get_be32(f); |
|
826 qemu_get_8s(f, &s->reg); |
|
827 |
|
828 if (s->rtc.ctrl & 1) /* RTC_EN */ |
|
829 menelaus_rtc_stop(s); |
|
830 qemu_get_8s(f, &s->vcore[0]); |
|
831 qemu_get_8s(f, &s->vcore[1]); |
|
832 qemu_get_8s(f, &s->vcore[2]); |
|
833 qemu_get_8s(f, &s->vcore[3]); |
|
834 qemu_get_8s(f, &s->vcore[4]); |
|
835 qemu_get_8s(f, &s->dcdc[3]); |
|
836 qemu_get_8s(f, &s->dcdc[3]); |
|
837 qemu_get_8s(f, &s->dcdc[3]); |
|
838 qemu_get_8s(f, &s->ldo[0]); |
|
839 qemu_get_8s(f, &s->ldo[1]); |
|
840 qemu_get_8s(f, &s->ldo[2]); |
|
841 qemu_get_8s(f, &s->ldo[3]); |
|
842 qemu_get_8s(f, &s->ldo[4]); |
|
843 qemu_get_8s(f, &s->ldo[5]); |
|
844 qemu_get_8s(f, &s->ldo[6]); |
|
845 qemu_get_8s(f, &s->ldo[7]); |
|
846 qemu_get_8s(f, &s->sleep[0]); |
|
847 qemu_get_8s(f, &s->sleep[1]); |
|
848 qemu_get_8s(f, &s->osc); |
|
849 qemu_get_8s(f, &s->detect); |
|
850 qemu_get_be16s(f, &s->mask); |
|
851 qemu_get_be16s(f, &s->status); |
|
852 qemu_get_8s(f, &s->dir); |
|
853 qemu_get_8s(f, &s->inputs); |
|
854 qemu_get_8s(f, &s->outputs); |
|
855 qemu_get_8s(f, &s->bbsms); |
|
856 qemu_get_8s(f, &s->pull[0]); |
|
857 qemu_get_8s(f, &s->pull[1]); |
|
858 qemu_get_8s(f, &s->pull[2]); |
|
859 qemu_get_8s(f, &s->pull[3]); |
|
860 qemu_get_8s(f, &s->mmc_ctrl[0]); |
|
861 qemu_get_8s(f, &s->mmc_ctrl[1]); |
|
862 qemu_get_8s(f, &s->mmc_ctrl[2]); |
|
863 qemu_get_8s(f, &s->mmc_debounce); |
|
864 qemu_get_8s(f, &s->rtc.ctrl); |
|
865 qemu_get_be16s(f, &s->rtc.comp); |
|
866 s->rtc.next = qemu_get_be16(f); |
|
867 tm_get(f, &s->rtc.new); |
|
868 tm_get(f, &s->rtc.alm); |
|
869 s->pwrbtn_state = qemu_get_byte(f); |
|
870 menelaus_alm_update(s); |
|
871 menelaus_update(s); |
|
872 if (s->rtc.ctrl & 1) /* RTC_EN */ |
|
873 menelaus_rtc_start(s); |
|
874 |
|
875 i2c_slave_load(f, &s->i2c); |
|
876 return 0; |
|
877 } |
|
878 |
|
879 i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq) |
|
880 { |
|
881 struct menelaus_s *s = (struct menelaus_s *) |
|
882 i2c_slave_init(bus, 0, sizeof(struct menelaus_s)); |
|
883 |
|
884 s->i2c.event = menelaus_event; |
|
885 s->i2c.recv = menelaus_rx; |
|
886 s->i2c.send = menelaus_tx; |
|
887 |
|
888 s->irq = irq; |
|
889 s->rtc.hz_tm = qemu_new_timer(rt_clock, menelaus_rtc_hz, s); |
|
890 s->in = qemu_allocate_irqs(menelaus_gpio_set, s, 3); |
|
891 s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0]; |
|
892 |
|
893 menelaus_reset(&s->i2c); |
|
894 |
|
895 register_savevm("menelaus", -1, 0, menelaus_save, menelaus_load, s); |
|
896 |
|
897 return &s->i2c; |
|
898 } |
|
899 |
|
900 qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c) |
|
901 { |
|
902 struct menelaus_s *s = (struct menelaus_s *) i2c; |
|
903 |
|
904 return s->in; |
|
905 } |
|
906 |
|
907 void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) |
|
908 { |
|
909 struct menelaus_s *s = (struct menelaus_s *) i2c; |
|
910 |
|
911 if (line >= 3 || line < 0) { |
|
912 fprintf(stderr, "%s: No GPO line %i\n", __FUNCTION__, line); |
|
913 exit(-1); |
|
914 } |
|
915 s->handler[line] = handler; |
|
916 } |