Statistics
| Branch: | Revision:

root / hw / cbus.c @ 9306acb5

History | View | Annotate | Download (15.5 kB)

1 7e7c5e4c balrog
/*
2 7e7c5e4c balrog
 * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
3 7e7c5e4c balrog
 * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
4 7e7c5e4c balrog
 * Based on reverse-engineering of a linux driver.
5 7e7c5e4c balrog
 *
6 7e7c5e4c balrog
 * Copyright (C) 2008 Nokia Corporation
7 7e7c5e4c balrog
 * Written by Andrzej Zaborowski <andrew@openedhand.com>
8 7e7c5e4c balrog
 *
9 7e7c5e4c balrog
 * This program is free software; you can redistribute it and/or
10 7e7c5e4c balrog
 * modify it under the terms of the GNU General Public License as
11 7e7c5e4c balrog
 * published by the Free Software Foundation; either version 2 or
12 7e7c5e4c balrog
 * (at your option) version 3 of the License.
13 7e7c5e4c balrog
 *
14 7e7c5e4c balrog
 * This program is distributed in the hope that it will be useful,
15 7e7c5e4c balrog
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 7e7c5e4c balrog
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 7e7c5e4c balrog
 * GNU General Public License for more details.
18 7e7c5e4c balrog
 *
19 fad6cb1a aurel32
 * You should have received a copy of the GNU General Public License along
20 fad6cb1a aurel32
 * with this program; if not, write to the Free Software Foundation, Inc.,
21 fad6cb1a aurel32
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 7e7c5e4c balrog
 */
23 7e7c5e4c balrog
24 7e7c5e4c balrog
#include "qemu-common.h"
25 7e7c5e4c balrog
#include "irq.h"
26 7e7c5e4c balrog
#include "devices.h"
27 7e7c5e4c balrog
#include "sysemu.h"
28 7e7c5e4c balrog
29 7e7c5e4c balrog
//#define DEBUG
30 7e7c5e4c balrog
31 7e7c5e4c balrog
struct cbus_slave_s;
32 7e7c5e4c balrog
struct cbus_priv_s {
33 7e7c5e4c balrog
    struct cbus_s cbus;
34 7e7c5e4c balrog
35 7e7c5e4c balrog
    int sel;
36 7e7c5e4c balrog
    int dat;
37 7e7c5e4c balrog
    int clk;
38 7e7c5e4c balrog
    int bit;
39 7e7c5e4c balrog
    int dir;
40 7e7c5e4c balrog
    uint16_t val;
41 7e7c5e4c balrog
    qemu_irq dat_out;
42 7e7c5e4c balrog
43 7e7c5e4c balrog
    int addr;
44 7e7c5e4c balrog
    int reg;
45 7e7c5e4c balrog
    int rw;
46 7e7c5e4c balrog
    enum {
47 7e7c5e4c balrog
        cbus_address,
48 7e7c5e4c balrog
        cbus_value,
49 7e7c5e4c balrog
    } cycle;
50 7e7c5e4c balrog
51 7e7c5e4c balrog
    struct cbus_slave_s *slave[8];
52 7e7c5e4c balrog
};
53 7e7c5e4c balrog
54 7e7c5e4c balrog
struct cbus_slave_s {
55 7e7c5e4c balrog
    void *opaque;
56 7e7c5e4c balrog
    void (*io)(void *opaque, int rw, int reg, uint16_t *val);
57 7e7c5e4c balrog
    int addr;
58 7e7c5e4c balrog
};
59 7e7c5e4c balrog
60 7e7c5e4c balrog
static void cbus_io(struct cbus_priv_s *s)
61 7e7c5e4c balrog
{
62 7e7c5e4c balrog
    if (s->slave[s->addr])
63 7e7c5e4c balrog
        s->slave[s->addr]->io(s->slave[s->addr]->opaque,
64 7e7c5e4c balrog
                        s->rw, s->reg, &s->val);
65 7e7c5e4c balrog
    else
66 7e7c5e4c balrog
        cpu_abort(cpu_single_env, "%s: bad slave address %i\n",
67 7e7c5e4c balrog
                        __FUNCTION__, s->addr);
68 7e7c5e4c balrog
}
69 7e7c5e4c balrog
70 7e7c5e4c balrog
static void cbus_cycle(struct cbus_priv_s *s)
71 7e7c5e4c balrog
{
72 7e7c5e4c balrog
    switch (s->cycle) {
73 7e7c5e4c balrog
    case cbus_address:
74 7e7c5e4c balrog
        s->addr = (s->val >> 6) & 7;
75 7e7c5e4c balrog
        s->rw =   (s->val >> 5) & 1;
76 7e7c5e4c balrog
        s->reg =  (s->val >> 0) & 0x1f;
77 7e7c5e4c balrog
78 7e7c5e4c balrog
        s->cycle = cbus_value;
79 7e7c5e4c balrog
        s->bit = 15;
80 7e7c5e4c balrog
        s->dir = !s->rw;
81 7e7c5e4c balrog
        s->val = 0;
82 7e7c5e4c balrog
83 7e7c5e4c balrog
        if (s->rw)
84 7e7c5e4c balrog
            cbus_io(s);
85 7e7c5e4c balrog
        break;
86 7e7c5e4c balrog
87 7e7c5e4c balrog
    case cbus_value:
88 7e7c5e4c balrog
        if (!s->rw)
89 7e7c5e4c balrog
            cbus_io(s);
90 7e7c5e4c balrog
91 7e7c5e4c balrog
        s->cycle = cbus_address;
92 7e7c5e4c balrog
        s->bit = 8;
93 7e7c5e4c balrog
        s->dir = 1;
94 7e7c5e4c balrog
        s->val = 0;
95 7e7c5e4c balrog
        break;
96 7e7c5e4c balrog
    }
97 7e7c5e4c balrog
}
98 7e7c5e4c balrog
99 7e7c5e4c balrog
static void cbus_clk(void *opaque, int line, int level)
100 7e7c5e4c balrog
{
101 7e7c5e4c balrog
    struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
102 7e7c5e4c balrog
103 7e7c5e4c balrog
    if (!s->sel && level && !s->clk) {
104 7e7c5e4c balrog
        if (s->dir)
105 7e7c5e4c balrog
            s->val |= s->dat << (s->bit --);
106 7e7c5e4c balrog
        else
107 7e7c5e4c balrog
            qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
108 7e7c5e4c balrog
109 7e7c5e4c balrog
        if (s->bit < 0)
110 7e7c5e4c balrog
            cbus_cycle(s);
111 7e7c5e4c balrog
    }
112 7e7c5e4c balrog
113 7e7c5e4c balrog
    s->clk = level;
114 7e7c5e4c balrog
}
115 7e7c5e4c balrog
116 7e7c5e4c balrog
static void cbus_dat(void *opaque, int line, int level)
117 7e7c5e4c balrog
{
118 7e7c5e4c balrog
    struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
119 7e7c5e4c balrog
120 7e7c5e4c balrog
    s->dat = level;
121 7e7c5e4c balrog
}
122 7e7c5e4c balrog
123 7e7c5e4c balrog
static void cbus_sel(void *opaque, int line, int level)
124 7e7c5e4c balrog
{
125 7e7c5e4c balrog
    struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
126 7e7c5e4c balrog
127 7e7c5e4c balrog
    if (!level) {
128 7e7c5e4c balrog
        s->dir = 1;
129 7e7c5e4c balrog
        s->bit = 8;
130 7e7c5e4c balrog
        s->val = 0;
131 7e7c5e4c balrog
    }
132 7e7c5e4c balrog
133 7e7c5e4c balrog
    s->sel = level;
134 7e7c5e4c balrog
}
135 7e7c5e4c balrog
136 7e7c5e4c balrog
struct cbus_s *cbus_init(qemu_irq dat)
137 7e7c5e4c balrog
{
138 7e7c5e4c balrog
    struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s));
139 7e7c5e4c balrog
140 7e7c5e4c balrog
    s->dat_out = dat;
141 7e7c5e4c balrog
    s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
142 7e7c5e4c balrog
    s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
143 7e7c5e4c balrog
    s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
144 7e7c5e4c balrog
145 7e7c5e4c balrog
    s->sel = 1;
146 7e7c5e4c balrog
    s->clk = 0;
147 7e7c5e4c balrog
    s->dat = 0;
148 7e7c5e4c balrog
149 7e7c5e4c balrog
    return &s->cbus;
150 7e7c5e4c balrog
}
151 7e7c5e4c balrog
152 7e7c5e4c balrog
void cbus_attach(struct cbus_s *bus, void *slave_opaque)
153 7e7c5e4c balrog
{
154 7e7c5e4c balrog
    struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque;
155 7e7c5e4c balrog
    struct cbus_priv_s *s = (struct cbus_priv_s *) bus;
156 7e7c5e4c balrog
157 7e7c5e4c balrog
    s->slave[slave->addr] = slave;
158 7e7c5e4c balrog
}
159 7e7c5e4c balrog
160 7e7c5e4c balrog
/* Retu/Vilma */
161 7e7c5e4c balrog
struct cbus_retu_s {
162 7e7c5e4c balrog
    uint16_t irqst;
163 7e7c5e4c balrog
    uint16_t irqen;
164 7e7c5e4c balrog
    uint16_t cc[2];
165 7e7c5e4c balrog
    int channel;
166 7e7c5e4c balrog
    uint16_t result[16];
167 7e7c5e4c balrog
    uint16_t sample;
168 7e7c5e4c balrog
    uint16_t status;
169 7e7c5e4c balrog
170 7e7c5e4c balrog
    struct {
171 7e7c5e4c balrog
        uint16_t cal;
172 7e7c5e4c balrog
    } rtc;
173 7e7c5e4c balrog
174 7e7c5e4c balrog
    int is_vilma;
175 7e7c5e4c balrog
    qemu_irq irq;
176 7e7c5e4c balrog
    struct cbus_slave_s cbus;
177 7e7c5e4c balrog
};
178 7e7c5e4c balrog
179 7e7c5e4c balrog
static void retu_interrupt_update(struct cbus_retu_s *s)
180 7e7c5e4c balrog
{
181 7e7c5e4c balrog
    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
182 7e7c5e4c balrog
}
183 7e7c5e4c balrog
184 7e7c5e4c balrog
#define RETU_REG_ASICR                0x00        /* (RO) ASIC ID & revision */
185 7e7c5e4c balrog
#define RETU_REG_IDR                0x01        /* (T)  Interrupt ID */
186 7e7c5e4c balrog
#define RETU_REG_IMR                0x02        /* (RW) Interrupt mask */
187 7e7c5e4c balrog
#define RETU_REG_RTCDSR                0x03        /* (RW) RTC seconds register */
188 7e7c5e4c balrog
#define RETU_REG_RTCHMR                0x04        /* (RO) RTC hours and minutes reg */
189 7e7c5e4c balrog
#define RETU_REG_RTCHMAR        0x05        /* (RW) RTC hours and minutes set reg */
190 7e7c5e4c balrog
#define RETU_REG_RTCCALR        0x06        /* (RW) RTC calibration register */
191 7e7c5e4c balrog
#define RETU_REG_ADCR                0x08        /* (RW) ADC result register */
192 7e7c5e4c balrog
#define RETU_REG_ADCSCR                0x09        /* (RW) ADC sample control register */
193 7e7c5e4c balrog
#define RETU_REG_AFCR                0x0a        /* (RW) AFC register */
194 7e7c5e4c balrog
#define RETU_REG_ANTIFR                0x0b        /* (RW) AntiF register */
195 7e7c5e4c balrog
#define RETU_REG_CALIBR                0x0c        /* (RW) CalibR register*/
196 7e7c5e4c balrog
#define RETU_REG_CCR1                0x0d        /* (RW) Common control register 1 */
197 7e7c5e4c balrog
#define RETU_REG_CCR2                0x0e        /* (RW) Common control register 2 */
198 7e7c5e4c balrog
#define RETU_REG_RCTRL_CLR        0x0f        /* (T)  Regulator clear register */
199 7e7c5e4c balrog
#define RETU_REG_RCTRL_SET        0x10        /* (T)  Regulator set register */
200 7e7c5e4c balrog
#define RETU_REG_TXCR                0x11        /* (RW) TxC register */
201 7e7c5e4c balrog
#define RETU_REG_STATUS                0x16        /* (RO) Status register */
202 7e7c5e4c balrog
#define RETU_REG_WATCHDOG        0x17        /* (RW) Watchdog register */
203 7e7c5e4c balrog
#define RETU_REG_AUDTXR                0x18        /* (RW) Audio Codec Tx register */
204 7e7c5e4c balrog
#define RETU_REG_AUDPAR                0x19        /* (RW) AudioPA register */
205 7e7c5e4c balrog
#define RETU_REG_AUDRXR1        0x1a        /* (RW) Audio receive register 1 */
206 7e7c5e4c balrog
#define RETU_REG_AUDRXR2        0x1b        /* (RW) Audio receive register 2 */
207 7e7c5e4c balrog
#define RETU_REG_SGR1                0x1c        /* (RW) */
208 7e7c5e4c balrog
#define RETU_REG_SCR1                0x1d        /* (RW) */
209 7e7c5e4c balrog
#define RETU_REG_SGR2                0x1e        /* (RW) */
210 7e7c5e4c balrog
#define RETU_REG_SCR2                0x1f        /* (RW) */
211 7e7c5e4c balrog
212 7e7c5e4c balrog
/* Retu Interrupt sources */
213 7e7c5e4c balrog
enum {
214 7e7c5e4c balrog
    retu_int_pwr        = 0,        /* Power button */
215 7e7c5e4c balrog
    retu_int_char        = 1,        /* Charger */
216 7e7c5e4c balrog
    retu_int_rtcs        = 2,        /* Seconds */
217 7e7c5e4c balrog
    retu_int_rtcm        = 3,        /* Minutes */
218 7e7c5e4c balrog
    retu_int_rtcd        = 4,        /* Days */
219 7e7c5e4c balrog
    retu_int_rtca        = 5,        /* Alarm */
220 7e7c5e4c balrog
    retu_int_hook        = 6,        /* Hook */
221 7e7c5e4c balrog
    retu_int_head        = 7,        /* Headset */
222 7e7c5e4c balrog
    retu_int_adcs        = 8,        /* ADC sample */
223 7e7c5e4c balrog
};
224 7e7c5e4c balrog
225 7e7c5e4c balrog
/* Retu ADC channel wiring */
226 7e7c5e4c balrog
enum {
227 7e7c5e4c balrog
    retu_adc_bsi        = 1,        /* BSI */
228 7e7c5e4c balrog
    retu_adc_batt_temp        = 2,        /* Battery temperature */
229 7e7c5e4c balrog
    retu_adc_chg_volt        = 3,        /* Charger voltage */
230 7e7c5e4c balrog
    retu_adc_head_det        = 4,        /* Headset detection */
231 7e7c5e4c balrog
    retu_adc_hook_det        = 5,        /* Hook detection */
232 7e7c5e4c balrog
    retu_adc_rf_gp        = 6,        /* RF GP */
233 7e7c5e4c balrog
    retu_adc_tx_det        = 7,        /* Wideband Tx detection */
234 7e7c5e4c balrog
    retu_adc_batt_volt        = 8,        /* Battery voltage */
235 7e7c5e4c balrog
    retu_adc_sens        = 10,        /* Light sensor */
236 7e7c5e4c balrog
    retu_adc_sens_temp        = 11,        /* Light sensor temperature */
237 7e7c5e4c balrog
    retu_adc_bbatt_volt        = 12,        /* Backup battery voltage */
238 7e7c5e4c balrog
    retu_adc_self_temp        = 13,        /* RETU temperature */
239 7e7c5e4c balrog
};
240 7e7c5e4c balrog
241 7e7c5e4c balrog
static inline uint16_t retu_read(struct cbus_retu_s *s, int reg)
242 7e7c5e4c balrog
{
243 7e7c5e4c balrog
#ifdef DEBUG
244 7e7c5e4c balrog
    printf("RETU read at %02x\n", reg);
245 7e7c5e4c balrog
#endif
246 7e7c5e4c balrog
247 7e7c5e4c balrog
    switch (reg) {
248 7e7c5e4c balrog
    case RETU_REG_ASICR:
249 7e7c5e4c balrog
        return 0x0215 | (s->is_vilma << 7);
250 7e7c5e4c balrog
251 7e7c5e4c balrog
    case RETU_REG_IDR:        /* TODO: Or is this ffs(s->irqst)?  */
252 7e7c5e4c balrog
        return s->irqst;
253 7e7c5e4c balrog
254 7e7c5e4c balrog
    case RETU_REG_IMR:
255 7e7c5e4c balrog
        return s->irqen;
256 7e7c5e4c balrog
257 7e7c5e4c balrog
    case RETU_REG_RTCDSR:
258 7e7c5e4c balrog
    case RETU_REG_RTCHMR:
259 7e7c5e4c balrog
    case RETU_REG_RTCHMAR:
260 7e7c5e4c balrog
        /* TODO */
261 7e7c5e4c balrog
        return 0x0000;
262 7e7c5e4c balrog
263 7e7c5e4c balrog
    case RETU_REG_RTCCALR:
264 7e7c5e4c balrog
        return s->rtc.cal;
265 7e7c5e4c balrog
266 7e7c5e4c balrog
    case RETU_REG_ADCR:
267 7e7c5e4c balrog
        return (s->channel << 10) | s->result[s->channel];
268 7e7c5e4c balrog
    case RETU_REG_ADCSCR:
269 7e7c5e4c balrog
        return s->sample;
270 7e7c5e4c balrog
271 7e7c5e4c balrog
    case RETU_REG_AFCR:
272 7e7c5e4c balrog
    case RETU_REG_ANTIFR:
273 7e7c5e4c balrog
    case RETU_REG_CALIBR:
274 7e7c5e4c balrog
        /* TODO */
275 7e7c5e4c balrog
        return 0x0000;
276 7e7c5e4c balrog
277 7e7c5e4c balrog
    case RETU_REG_CCR1:
278 7e7c5e4c balrog
        return s->cc[0];
279 7e7c5e4c balrog
    case RETU_REG_CCR2:
280 7e7c5e4c balrog
        return s->cc[1];
281 7e7c5e4c balrog
282 7e7c5e4c balrog
    case RETU_REG_RCTRL_CLR:
283 7e7c5e4c balrog
    case RETU_REG_RCTRL_SET:
284 7e7c5e4c balrog
    case RETU_REG_TXCR:
285 7e7c5e4c balrog
        /* TODO */
286 7e7c5e4c balrog
        return 0x0000;
287 7e7c5e4c balrog
288 7e7c5e4c balrog
    case RETU_REG_STATUS:
289 7e7c5e4c balrog
        return s->status;
290 7e7c5e4c balrog
291 7e7c5e4c balrog
    case RETU_REG_WATCHDOG:
292 7e7c5e4c balrog
    case RETU_REG_AUDTXR:
293 7e7c5e4c balrog
    case RETU_REG_AUDPAR:
294 7e7c5e4c balrog
    case RETU_REG_AUDRXR1:
295 7e7c5e4c balrog
    case RETU_REG_AUDRXR2:
296 7e7c5e4c balrog
    case RETU_REG_SGR1:
297 7e7c5e4c balrog
    case RETU_REG_SCR1:
298 7e7c5e4c balrog
    case RETU_REG_SGR2:
299 7e7c5e4c balrog
    case RETU_REG_SCR2:
300 7e7c5e4c balrog
        /* TODO */
301 7e7c5e4c balrog
        return 0x0000;
302 7e7c5e4c balrog
303 7e7c5e4c balrog
    default:
304 7e7c5e4c balrog
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
305 7e7c5e4c balrog
                        __FUNCTION__, reg);
306 7e7c5e4c balrog
    }
307 7e7c5e4c balrog
}
308 7e7c5e4c balrog
309 7e7c5e4c balrog
static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val)
310 7e7c5e4c balrog
{
311 7e7c5e4c balrog
#ifdef DEBUG
312 7e7c5e4c balrog
    printf("RETU write of %04x at %02x\n", val, reg);
313 7e7c5e4c balrog
#endif
314 7e7c5e4c balrog
315 7e7c5e4c balrog
    switch (reg) {
316 7e7c5e4c balrog
    case RETU_REG_IDR:
317 7e7c5e4c balrog
        s->irqst ^= val;
318 7e7c5e4c balrog
        retu_interrupt_update(s);
319 7e7c5e4c balrog
        break;
320 7e7c5e4c balrog
321 7e7c5e4c balrog
    case RETU_REG_IMR:
322 7e7c5e4c balrog
        s->irqen = val;
323 7e7c5e4c balrog
        retu_interrupt_update(s);
324 7e7c5e4c balrog
        break;
325 7e7c5e4c balrog
326 7e7c5e4c balrog
    case RETU_REG_RTCDSR:
327 7e7c5e4c balrog
    case RETU_REG_RTCHMAR:
328 7e7c5e4c balrog
        /* TODO */
329 7e7c5e4c balrog
        break;
330 7e7c5e4c balrog
331 7e7c5e4c balrog
    case RETU_REG_RTCCALR:
332 7e7c5e4c balrog
        s->rtc.cal = val;
333 7e7c5e4c balrog
        break;
334 7e7c5e4c balrog
335 7e7c5e4c balrog
    case RETU_REG_ADCR:
336 7e7c5e4c balrog
        s->channel = (val >> 10) & 0xf;
337 7e7c5e4c balrog
        s->irqst |= 1 << retu_int_adcs;
338 7e7c5e4c balrog
        retu_interrupt_update(s);
339 7e7c5e4c balrog
        break;
340 7e7c5e4c balrog
    case RETU_REG_ADCSCR:
341 7e7c5e4c balrog
        s->sample &= ~val;
342 7e7c5e4c balrog
        break;
343 7e7c5e4c balrog
344 7e7c5e4c balrog
    case RETU_REG_AFCR:
345 7e7c5e4c balrog
    case RETU_REG_ANTIFR:
346 7e7c5e4c balrog
    case RETU_REG_CALIBR:
347 7e7c5e4c balrog
348 7e7c5e4c balrog
    case RETU_REG_CCR1:
349 7e7c5e4c balrog
        s->cc[0] = val;
350 7e7c5e4c balrog
        break;
351 7e7c5e4c balrog
    case RETU_REG_CCR2:
352 7e7c5e4c balrog
        s->cc[1] = val;
353 7e7c5e4c balrog
        break;
354 7e7c5e4c balrog
355 7e7c5e4c balrog
    case RETU_REG_RCTRL_CLR:
356 7e7c5e4c balrog
    case RETU_REG_RCTRL_SET:
357 7e7c5e4c balrog
        /* TODO */
358 7e7c5e4c balrog
        break;
359 7e7c5e4c balrog
360 7e7c5e4c balrog
    case RETU_REG_WATCHDOG:
361 7e7c5e4c balrog
        if (val == 0 && (s->cc[0] & 2))
362 7e7c5e4c balrog
            qemu_system_shutdown_request();
363 7e7c5e4c balrog
        break;
364 7e7c5e4c balrog
365 7e7c5e4c balrog
    case RETU_REG_TXCR:
366 7e7c5e4c balrog
    case RETU_REG_AUDTXR:
367 7e7c5e4c balrog
    case RETU_REG_AUDPAR:
368 7e7c5e4c balrog
    case RETU_REG_AUDRXR1:
369 7e7c5e4c balrog
    case RETU_REG_AUDRXR2:
370 7e7c5e4c balrog
    case RETU_REG_SGR1:
371 7e7c5e4c balrog
    case RETU_REG_SCR1:
372 7e7c5e4c balrog
    case RETU_REG_SGR2:
373 7e7c5e4c balrog
    case RETU_REG_SCR2:
374 7e7c5e4c balrog
        /* TODO */
375 7e7c5e4c balrog
        break;
376 7e7c5e4c balrog
377 7e7c5e4c balrog
    default:
378 7e7c5e4c balrog
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
379 7e7c5e4c balrog
                        __FUNCTION__, reg);
380 7e7c5e4c balrog
    }
381 7e7c5e4c balrog
}
382 7e7c5e4c balrog
383 7e7c5e4c balrog
static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
384 7e7c5e4c balrog
{
385 7e7c5e4c balrog
    struct cbus_retu_s *s = (struct cbus_retu_s *) opaque;
386 7e7c5e4c balrog
387 7e7c5e4c balrog
    if (rw)
388 7e7c5e4c balrog
        *val = retu_read(s, reg);
389 7e7c5e4c balrog
    else
390 7e7c5e4c balrog
        retu_write(s, reg, *val);
391 7e7c5e4c balrog
}
392 7e7c5e4c balrog
393 7e7c5e4c balrog
void *retu_init(qemu_irq irq, int vilma)
394 7e7c5e4c balrog
{
395 7e7c5e4c balrog
    struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s));
396 7e7c5e4c balrog
397 7e7c5e4c balrog
    s->irq = irq;
398 7e7c5e4c balrog
    s->irqen = 0xffff;
399 7e7c5e4c balrog
    s->irqst = 0x0000;
400 7e7c5e4c balrog
    s->status = 0x0020;
401 7e7c5e4c balrog
    s->is_vilma = !!vilma;
402 7e7c5e4c balrog
    s->rtc.cal = 0x01;
403 7e7c5e4c balrog
    s->result[retu_adc_bsi] = 0x3c2;
404 7e7c5e4c balrog
    s->result[retu_adc_batt_temp] = 0x0fc;
405 7e7c5e4c balrog
    s->result[retu_adc_chg_volt] = 0x165;
406 7e7c5e4c balrog
    s->result[retu_adc_head_det] = 123;
407 7e7c5e4c balrog
    s->result[retu_adc_hook_det] = 1023;
408 7e7c5e4c balrog
    s->result[retu_adc_rf_gp] = 0x11;
409 7e7c5e4c balrog
    s->result[retu_adc_tx_det] = 0x11;
410 7e7c5e4c balrog
    s->result[retu_adc_batt_volt] = 0x250;
411 7e7c5e4c balrog
    s->result[retu_adc_sens] = 2;
412 7e7c5e4c balrog
    s->result[retu_adc_sens_temp] = 0x11;
413 7e7c5e4c balrog
    s->result[retu_adc_bbatt_volt] = 0x3d0;
414 7e7c5e4c balrog
    s->result[retu_adc_self_temp] = 0x330;
415 7e7c5e4c balrog
416 7e7c5e4c balrog
    s->cbus.opaque = s;
417 7e7c5e4c balrog
    s->cbus.io = retu_io;
418 7e7c5e4c balrog
    s->cbus.addr = 1;
419 7e7c5e4c balrog
420 7e7c5e4c balrog
    return &s->cbus;
421 7e7c5e4c balrog
}
422 7e7c5e4c balrog
423 7e7c5e4c balrog
void retu_key_event(void *retu, int state)
424 7e7c5e4c balrog
{
425 7e7c5e4c balrog
    struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
426 7e7c5e4c balrog
    struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
427 7e7c5e4c balrog
428 7e7c5e4c balrog
    s->irqst |= 1 << retu_int_pwr;
429 7e7c5e4c balrog
    retu_interrupt_update(s);
430 7e7c5e4c balrog
431 7e7c5e4c balrog
    if (state)
432 7e7c5e4c balrog
        s->status &= ~(1 << 5);
433 7e7c5e4c balrog
    else
434 7e7c5e4c balrog
        s->status |= 1 << 5;
435 7e7c5e4c balrog
}
436 7e7c5e4c balrog
437 b1d8e52e blueswir1
#if 0
438 b1d8e52e blueswir1
static void retu_head_event(void *retu, int state)
439 7e7c5e4c balrog
{
440 7e7c5e4c balrog
    struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
441 7e7c5e4c balrog
    struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
442 7e7c5e4c balrog

443 7e7c5e4c balrog
    if ((s->cc[0] & 0x500) == 0x500) {        /* TODO: Which bits? */
444 7e7c5e4c balrog
        /* TODO: reissue the interrupt every 100ms or so.  */
445 7e7c5e4c balrog
        s->irqst |= 1 << retu_int_head;
446 7e7c5e4c balrog
        retu_interrupt_update(s);
447 7e7c5e4c balrog
    }
448 7e7c5e4c balrog

449 7e7c5e4c balrog
    if (state)
450 7e7c5e4c balrog
        s->result[retu_adc_head_det] = 50;
451 7e7c5e4c balrog
    else
452 7e7c5e4c balrog
        s->result[retu_adc_head_det] = 123;
453 7e7c5e4c balrog
}
454 7e7c5e4c balrog

455 b1d8e52e blueswir1
static void retu_hook_event(void *retu, int state)
456 7e7c5e4c balrog
{
457 7e7c5e4c balrog
    struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
458 7e7c5e4c balrog
    struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
459 7e7c5e4c balrog

460 7e7c5e4c balrog
    if ((s->cc[0] & 0x500) == 0x500) {
461 7e7c5e4c balrog
        /* TODO: reissue the interrupt every 100ms or so.  */
462 7e7c5e4c balrog
        s->irqst |= 1 << retu_int_hook;
463 7e7c5e4c balrog
        retu_interrupt_update(s);
464 7e7c5e4c balrog
    }
465 7e7c5e4c balrog

466 7e7c5e4c balrog
    if (state)
467 7e7c5e4c balrog
        s->result[retu_adc_hook_det] = 50;
468 7e7c5e4c balrog
    else
469 7e7c5e4c balrog
        s->result[retu_adc_hook_det] = 123;
470 7e7c5e4c balrog
}
471 b1d8e52e blueswir1
#endif
472 7e7c5e4c balrog
473 7e7c5e4c balrog
/* Tahvo/Betty */
474 7e7c5e4c balrog
struct cbus_tahvo_s {
475 7e7c5e4c balrog
    uint16_t irqst;
476 7e7c5e4c balrog
    uint16_t irqen;
477 7e7c5e4c balrog
    uint8_t charger;
478 7e7c5e4c balrog
    uint8_t backlight;
479 7e7c5e4c balrog
    uint16_t usbr;
480 7e7c5e4c balrog
    uint16_t power;
481 7e7c5e4c balrog
482 7e7c5e4c balrog
    int is_betty;
483 7e7c5e4c balrog
    qemu_irq irq;
484 7e7c5e4c balrog
    struct cbus_slave_s cbus;
485 7e7c5e4c balrog
};
486 7e7c5e4c balrog
487 7e7c5e4c balrog
static void tahvo_interrupt_update(struct cbus_tahvo_s *s)
488 7e7c5e4c balrog
{
489 7e7c5e4c balrog
    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
490 7e7c5e4c balrog
}
491 7e7c5e4c balrog
492 7e7c5e4c balrog
#define TAHVO_REG_ASICR                0x00        /* (RO) ASIC ID & revision */
493 7e7c5e4c balrog
#define TAHVO_REG_IDR                0x01        /* (T)  Interrupt ID */
494 7e7c5e4c balrog
#define TAHVO_REG_IDSR                0x02        /* (RO) Interrupt status */
495 7e7c5e4c balrog
#define TAHVO_REG_IMR                0x03        /* (RW) Interrupt mask */
496 7e7c5e4c balrog
#define TAHVO_REG_CHAPWMR        0x04        /* (RW) Charger PWM */
497 7e7c5e4c balrog
#define TAHVO_REG_LEDPWMR        0x05        /* (RW) LED PWM */
498 7e7c5e4c balrog
#define TAHVO_REG_USBR                0x06        /* (RW) USB control */
499 7e7c5e4c balrog
#define TAHVO_REG_RCR                0x07        /* (RW) Some kind of power management */
500 7e7c5e4c balrog
#define TAHVO_REG_CCR1                0x08        /* (RW) Common control register 1 */
501 7e7c5e4c balrog
#define TAHVO_REG_CCR2                0x09        /* (RW) Common control register 2 */
502 7e7c5e4c balrog
#define TAHVO_REG_TESTR1        0x0a        /* (RW) Test register 1 */
503 7e7c5e4c balrog
#define TAHVO_REG_TESTR2        0x0b        /* (RW) Test register 2 */
504 7e7c5e4c balrog
#define TAHVO_REG_NOPR                0x0c        /* (RW) Number of periods */
505 7e7c5e4c balrog
#define TAHVO_REG_FRR                0x0d        /* (RO) FR */
506 7e7c5e4c balrog
507 7e7c5e4c balrog
static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg)
508 7e7c5e4c balrog
{
509 7e7c5e4c balrog
#ifdef DEBUG
510 7e7c5e4c balrog
    printf("TAHVO read at %02x\n", reg);
511 7e7c5e4c balrog
#endif
512 7e7c5e4c balrog
513 7e7c5e4c balrog
    switch (reg) {
514 7e7c5e4c balrog
    case TAHVO_REG_ASICR:
515 7e7c5e4c balrog
        return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);        /* 22 in N810 */
516 7e7c5e4c balrog
517 7e7c5e4c balrog
    case TAHVO_REG_IDR:
518 7e7c5e4c balrog
    case TAHVO_REG_IDSR:        /* XXX: what does this do?  */
519 7e7c5e4c balrog
        return s->irqst;
520 7e7c5e4c balrog
521 7e7c5e4c balrog
    case TAHVO_REG_IMR:
522 7e7c5e4c balrog
        return s->irqen;
523 7e7c5e4c balrog
524 7e7c5e4c balrog
    case TAHVO_REG_CHAPWMR:
525 7e7c5e4c balrog
        return s->charger;
526 7e7c5e4c balrog
527 7e7c5e4c balrog
    case TAHVO_REG_LEDPWMR:
528 7e7c5e4c balrog
        return s->backlight;
529 7e7c5e4c balrog
530 7e7c5e4c balrog
    case TAHVO_REG_USBR:
531 7e7c5e4c balrog
        return s->usbr;
532 7e7c5e4c balrog
533 7e7c5e4c balrog
    case TAHVO_REG_RCR:
534 7e7c5e4c balrog
        return s->power;
535 7e7c5e4c balrog
536 7e7c5e4c balrog
    case TAHVO_REG_CCR1:
537 7e7c5e4c balrog
    case TAHVO_REG_CCR2:
538 7e7c5e4c balrog
    case TAHVO_REG_TESTR1:
539 7e7c5e4c balrog
    case TAHVO_REG_TESTR2:
540 7e7c5e4c balrog
    case TAHVO_REG_NOPR:
541 7e7c5e4c balrog
    case TAHVO_REG_FRR:
542 7e7c5e4c balrog
        return 0x0000;
543 7e7c5e4c balrog
544 7e7c5e4c balrog
    default:
545 7e7c5e4c balrog
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
546 7e7c5e4c balrog
                        __FUNCTION__, reg);
547 7e7c5e4c balrog
    }
548 7e7c5e4c balrog
}
549 7e7c5e4c balrog
550 7e7c5e4c balrog
static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val)
551 7e7c5e4c balrog
{
552 7e7c5e4c balrog
#ifdef DEBUG
553 7e7c5e4c balrog
    printf("TAHVO write of %04x at %02x\n", val, reg);
554 7e7c5e4c balrog
#endif
555 7e7c5e4c balrog
556 7e7c5e4c balrog
    switch (reg) {
557 7e7c5e4c balrog
    case TAHVO_REG_IDR:
558 7e7c5e4c balrog
        s->irqst ^= val;
559 7e7c5e4c balrog
        tahvo_interrupt_update(s);
560 7e7c5e4c balrog
        break;
561 7e7c5e4c balrog
562 7e7c5e4c balrog
    case TAHVO_REG_IMR:
563 7e7c5e4c balrog
        s->irqen = val;
564 7e7c5e4c balrog
        tahvo_interrupt_update(s);
565 7e7c5e4c balrog
        break;
566 7e7c5e4c balrog
567 7e7c5e4c balrog
    case TAHVO_REG_CHAPWMR:
568 7e7c5e4c balrog
        s->charger = val;
569 7e7c5e4c balrog
        break;
570 7e7c5e4c balrog
571 7e7c5e4c balrog
    case TAHVO_REG_LEDPWMR:
572 7e7c5e4c balrog
        if (s->backlight != (val & 0x7f)) {
573 7e7c5e4c balrog
            s->backlight = val & 0x7f;
574 7e7c5e4c balrog
            printf("%s: LCD backlight now at %i / 127\n",
575 7e7c5e4c balrog
                            __FUNCTION__, s->backlight);
576 7e7c5e4c balrog
        }
577 7e7c5e4c balrog
        break;
578 7e7c5e4c balrog
579 7e7c5e4c balrog
    case TAHVO_REG_USBR:
580 7e7c5e4c balrog
        s->usbr = val;
581 7e7c5e4c balrog
        break;
582 7e7c5e4c balrog
583 7e7c5e4c balrog
    case TAHVO_REG_RCR:
584 7e7c5e4c balrog
        s->power = val;
585 7e7c5e4c balrog
        break;
586 7e7c5e4c balrog
587 7e7c5e4c balrog
    case TAHVO_REG_CCR1:
588 7e7c5e4c balrog
    case TAHVO_REG_CCR2:
589 7e7c5e4c balrog
    case TAHVO_REG_TESTR1:
590 7e7c5e4c balrog
    case TAHVO_REG_TESTR2:
591 7e7c5e4c balrog
    case TAHVO_REG_NOPR:
592 7e7c5e4c balrog
    case TAHVO_REG_FRR:
593 7e7c5e4c balrog
        break;
594 7e7c5e4c balrog
595 7e7c5e4c balrog
    default:
596 7e7c5e4c balrog
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
597 7e7c5e4c balrog
                        __FUNCTION__, reg);
598 7e7c5e4c balrog
    }
599 7e7c5e4c balrog
}
600 7e7c5e4c balrog
601 7e7c5e4c balrog
static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
602 7e7c5e4c balrog
{
603 7e7c5e4c balrog
    struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque;
604 7e7c5e4c balrog
605 7e7c5e4c balrog
    if (rw)
606 7e7c5e4c balrog
        *val = tahvo_read(s, reg);
607 7e7c5e4c balrog
    else
608 7e7c5e4c balrog
        tahvo_write(s, reg, *val);
609 7e7c5e4c balrog
}
610 7e7c5e4c balrog
611 7e7c5e4c balrog
void *tahvo_init(qemu_irq irq, int betty)
612 7e7c5e4c balrog
{
613 7e7c5e4c balrog
    struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s));
614 7e7c5e4c balrog
615 7e7c5e4c balrog
    s->irq = irq;
616 7e7c5e4c balrog
    s->irqen = 0xffff;
617 7e7c5e4c balrog
    s->irqst = 0x0000;
618 7e7c5e4c balrog
    s->is_betty = !!betty;
619 7e7c5e4c balrog
620 7e7c5e4c balrog
    s->cbus.opaque = s;
621 7e7c5e4c balrog
    s->cbus.io = tahvo_io;
622 7e7c5e4c balrog
    s->cbus.addr = 2;
623 7e7c5e4c balrog
624 7e7c5e4c balrog
    return &s->cbus;
625 7e7c5e4c balrog
}