Statistics
| Branch: | Revision:

root / hw / twl92230.c @ c1ded3dc

History | View | Annotate | Download (24.3 kB)

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