Statistics
| Branch: | Revision:

root / hw / cbus.c @ 5c16736a

History | View | Annotate | Download (15.5 kB)

1
/*
2
 * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
3
 * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
4
 * Based on reverse-engineering of a linux driver.
5
 *
6
 * Copyright (C) 2008 Nokia Corporation
7
 * Written by Andrzej Zaborowski <andrew@openedhand.com>
8
 *
9
 * This program is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU General Public License as
11
 * published by the Free Software Foundation; either version 2 or
12
 * (at your option) version 3 of the License.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22
 * MA 02111-1307 USA
23
 */
24

    
25
#include "qemu-common.h"
26
#include "irq.h"
27
#include "devices.h"
28
#include "sysemu.h"
29

    
30
//#define DEBUG
31

    
32
struct cbus_slave_s;
33
struct cbus_priv_s {
34
    struct cbus_s cbus;
35

    
36
    int sel;
37
    int dat;
38
    int clk;
39
    int bit;
40
    int dir;
41
    uint16_t val;
42
    qemu_irq dat_out;
43

    
44
    int addr;
45
    int reg;
46
    int rw;
47
    enum {
48
        cbus_address,
49
        cbus_value,
50
    } cycle;
51

    
52
    struct cbus_slave_s *slave[8];
53
};
54

    
55
struct cbus_slave_s {
56
    void *opaque;
57
    void (*io)(void *opaque, int rw, int reg, uint16_t *val);
58
    int addr;
59
};
60

    
61
static void cbus_io(struct cbus_priv_s *s)
62
{
63
    if (s->slave[s->addr])
64
        s->slave[s->addr]->io(s->slave[s->addr]->opaque,
65
                        s->rw, s->reg, &s->val);
66
    else
67
        cpu_abort(cpu_single_env, "%s: bad slave address %i\n",
68
                        __FUNCTION__, s->addr);
69
}
70

    
71
static void cbus_cycle(struct cbus_priv_s *s)
72
{
73
    switch (s->cycle) {
74
    case cbus_address:
75
        s->addr = (s->val >> 6) & 7;
76
        s->rw =   (s->val >> 5) & 1;
77
        s->reg =  (s->val >> 0) & 0x1f;
78

    
79
        s->cycle = cbus_value;
80
        s->bit = 15;
81
        s->dir = !s->rw;
82
        s->val = 0;
83

    
84
        if (s->rw)
85
            cbus_io(s);
86
        break;
87

    
88
    case cbus_value:
89
        if (!s->rw)
90
            cbus_io(s);
91

    
92
        s->cycle = cbus_address;
93
        s->bit = 8;
94
        s->dir = 1;
95
        s->val = 0;
96
        break;
97
    }
98
}
99

    
100
static void cbus_clk(void *opaque, int line, int level)
101
{
102
    struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
103

    
104
    if (!s->sel && level && !s->clk) {
105
        if (s->dir)
106
            s->val |= s->dat << (s->bit --);
107
        else
108
            qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
109

    
110
        if (s->bit < 0)
111
            cbus_cycle(s);
112
    }
113

    
114
    s->clk = level;
115
}
116

    
117
static void cbus_dat(void *opaque, int line, int level)
118
{
119
    struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
120

    
121
    s->dat = level;
122
}
123

    
124
static void cbus_sel(void *opaque, int line, int level)
125
{
126
    struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
127

    
128
    if (!level) {
129
        s->dir = 1;
130
        s->bit = 8;
131
        s->val = 0;
132
    }
133

    
134
    s->sel = level;
135
}
136

    
137
struct cbus_s *cbus_init(qemu_irq dat)
138
{
139
    struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s));
140

    
141
    s->dat_out = dat;
142
    s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
143
    s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
144
    s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
145

    
146
    s->sel = 1;
147
    s->clk = 0;
148
    s->dat = 0;
149

    
150
    return &s->cbus;
151
}
152

    
153
void cbus_attach(struct cbus_s *bus, void *slave_opaque)
154
{
155
    struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque;
156
    struct cbus_priv_s *s = (struct cbus_priv_s *) bus;
157

    
158
    s->slave[slave->addr] = slave;
159
}
160

    
161
/* Retu/Vilma */
162
struct cbus_retu_s {
163
    uint16_t irqst;
164
    uint16_t irqen;
165
    uint16_t cc[2];
166
    int channel;
167
    uint16_t result[16];
168
    uint16_t sample;
169
    uint16_t status;
170

    
171
    struct {
172
        uint16_t cal;
173
    } rtc;
174

    
175
    int is_vilma;
176
    qemu_irq irq;
177
    struct cbus_slave_s cbus;
178
};
179

    
180
static void retu_interrupt_update(struct cbus_retu_s *s)
181
{
182
    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
183
}
184

    
185
#define RETU_REG_ASICR                0x00        /* (RO) ASIC ID & revision */
186
#define RETU_REG_IDR                0x01        /* (T)  Interrupt ID */
187
#define RETU_REG_IMR                0x02        /* (RW) Interrupt mask */
188
#define RETU_REG_RTCDSR                0x03        /* (RW) RTC seconds register */
189
#define RETU_REG_RTCHMR                0x04        /* (RO) RTC hours and minutes reg */
190
#define RETU_REG_RTCHMAR        0x05        /* (RW) RTC hours and minutes set reg */
191
#define RETU_REG_RTCCALR        0x06        /* (RW) RTC calibration register */
192
#define RETU_REG_ADCR                0x08        /* (RW) ADC result register */
193
#define RETU_REG_ADCSCR                0x09        /* (RW) ADC sample control register */
194
#define RETU_REG_AFCR                0x0a        /* (RW) AFC register */
195
#define RETU_REG_ANTIFR                0x0b        /* (RW) AntiF register */
196
#define RETU_REG_CALIBR                0x0c        /* (RW) CalibR register*/
197
#define RETU_REG_CCR1                0x0d        /* (RW) Common control register 1 */
198
#define RETU_REG_CCR2                0x0e        /* (RW) Common control register 2 */
199
#define RETU_REG_RCTRL_CLR        0x0f        /* (T)  Regulator clear register */
200
#define RETU_REG_RCTRL_SET        0x10        /* (T)  Regulator set register */
201
#define RETU_REG_TXCR                0x11        /* (RW) TxC register */
202
#define RETU_REG_STATUS                0x16        /* (RO) Status register */
203
#define RETU_REG_WATCHDOG        0x17        /* (RW) Watchdog register */
204
#define RETU_REG_AUDTXR                0x18        /* (RW) Audio Codec Tx register */
205
#define RETU_REG_AUDPAR                0x19        /* (RW) AudioPA register */
206
#define RETU_REG_AUDRXR1        0x1a        /* (RW) Audio receive register 1 */
207
#define RETU_REG_AUDRXR2        0x1b        /* (RW) Audio receive register 2 */
208
#define RETU_REG_SGR1                0x1c        /* (RW) */
209
#define RETU_REG_SCR1                0x1d        /* (RW) */
210
#define RETU_REG_SGR2                0x1e        /* (RW) */
211
#define RETU_REG_SCR2                0x1f        /* (RW) */
212

    
213
/* Retu Interrupt sources */
214
enum {
215
    retu_int_pwr        = 0,        /* Power button */
216
    retu_int_char        = 1,        /* Charger */
217
    retu_int_rtcs        = 2,        /* Seconds */
218
    retu_int_rtcm        = 3,        /* Minutes */
219
    retu_int_rtcd        = 4,        /* Days */
220
    retu_int_rtca        = 5,        /* Alarm */
221
    retu_int_hook        = 6,        /* Hook */
222
    retu_int_head        = 7,        /* Headset */
223
    retu_int_adcs        = 8,        /* ADC sample */
224
};
225

    
226
/* Retu ADC channel wiring */
227
enum {
228
    retu_adc_bsi        = 1,        /* BSI */
229
    retu_adc_batt_temp        = 2,        /* Battery temperature */
230
    retu_adc_chg_volt        = 3,        /* Charger voltage */
231
    retu_adc_head_det        = 4,        /* Headset detection */
232
    retu_adc_hook_det        = 5,        /* Hook detection */
233
    retu_adc_rf_gp        = 6,        /* RF GP */
234
    retu_adc_tx_det        = 7,        /* Wideband Tx detection */
235
    retu_adc_batt_volt        = 8,        /* Battery voltage */
236
    retu_adc_sens        = 10,        /* Light sensor */
237
    retu_adc_sens_temp        = 11,        /* Light sensor temperature */
238
    retu_adc_bbatt_volt        = 12,        /* Backup battery voltage */
239
    retu_adc_self_temp        = 13,        /* RETU temperature */
240
};
241

    
242
static inline uint16_t retu_read(struct cbus_retu_s *s, int reg)
243
{
244
#ifdef DEBUG
245
    printf("RETU read at %02x\n", reg);
246
#endif
247

    
248
    switch (reg) {
249
    case RETU_REG_ASICR:
250
        return 0x0215 | (s->is_vilma << 7);
251

    
252
    case RETU_REG_IDR:        /* TODO: Or is this ffs(s->irqst)?  */
253
        return s->irqst;
254

    
255
    case RETU_REG_IMR:
256
        return s->irqen;
257

    
258
    case RETU_REG_RTCDSR:
259
    case RETU_REG_RTCHMR:
260
    case RETU_REG_RTCHMAR:
261
        /* TODO */
262
        return 0x0000;
263

    
264
    case RETU_REG_RTCCALR:
265
        return s->rtc.cal;
266

    
267
    case RETU_REG_ADCR:
268
        return (s->channel << 10) | s->result[s->channel];
269
    case RETU_REG_ADCSCR:
270
        return s->sample;
271

    
272
    case RETU_REG_AFCR:
273
    case RETU_REG_ANTIFR:
274
    case RETU_REG_CALIBR:
275
        /* TODO */
276
        return 0x0000;
277

    
278
    case RETU_REG_CCR1:
279
        return s->cc[0];
280
    case RETU_REG_CCR2:
281
        return s->cc[1];
282

    
283
    case RETU_REG_RCTRL_CLR:
284
    case RETU_REG_RCTRL_SET:
285
    case RETU_REG_TXCR:
286
        /* TODO */
287
        return 0x0000;
288

    
289
    case RETU_REG_STATUS:
290
        return s->status;
291

    
292
    case RETU_REG_WATCHDOG:
293
    case RETU_REG_AUDTXR:
294
    case RETU_REG_AUDPAR:
295
    case RETU_REG_AUDRXR1:
296
    case RETU_REG_AUDRXR2:
297
    case RETU_REG_SGR1:
298
    case RETU_REG_SCR1:
299
    case RETU_REG_SGR2:
300
    case RETU_REG_SCR2:
301
        /* TODO */
302
        return 0x0000;
303

    
304
    default:
305
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
306
                        __FUNCTION__, reg);
307
    }
308
}
309

    
310
static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val)
311
{
312
#ifdef DEBUG
313
    printf("RETU write of %04x at %02x\n", val, reg);
314
#endif
315

    
316
    switch (reg) {
317
    case RETU_REG_IDR:
318
        s->irqst ^= val;
319
        retu_interrupt_update(s);
320
        break;
321

    
322
    case RETU_REG_IMR:
323
        s->irqen = val;
324
        retu_interrupt_update(s);
325
        break;
326

    
327
    case RETU_REG_RTCDSR:
328
    case RETU_REG_RTCHMAR:
329
        /* TODO */
330
        break;
331

    
332
    case RETU_REG_RTCCALR:
333
        s->rtc.cal = val;
334
        break;
335

    
336
    case RETU_REG_ADCR:
337
        s->channel = (val >> 10) & 0xf;
338
        s->irqst |= 1 << retu_int_adcs;
339
        retu_interrupt_update(s);
340
        break;
341
    case RETU_REG_ADCSCR:
342
        s->sample &= ~val;
343
        break;
344

    
345
    case RETU_REG_AFCR:
346
    case RETU_REG_ANTIFR:
347
    case RETU_REG_CALIBR:
348

    
349
    case RETU_REG_CCR1:
350
        s->cc[0] = val;
351
        break;
352
    case RETU_REG_CCR2:
353
        s->cc[1] = val;
354
        break;
355

    
356
    case RETU_REG_RCTRL_CLR:
357
    case RETU_REG_RCTRL_SET:
358
        /* TODO */
359
        break;
360

    
361
    case RETU_REG_WATCHDOG:
362
        if (val == 0 && (s->cc[0] & 2))
363
            qemu_system_shutdown_request();
364
        break;
365

    
366
    case RETU_REG_TXCR:
367
    case RETU_REG_AUDTXR:
368
    case RETU_REG_AUDPAR:
369
    case RETU_REG_AUDRXR1:
370
    case RETU_REG_AUDRXR2:
371
    case RETU_REG_SGR1:
372
    case RETU_REG_SCR1:
373
    case RETU_REG_SGR2:
374
    case RETU_REG_SCR2:
375
        /* TODO */
376
        break;
377

    
378
    default:
379
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
380
                        __FUNCTION__, reg);
381
    }
382
}
383

    
384
static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
385
{
386
    struct cbus_retu_s *s = (struct cbus_retu_s *) opaque;
387

    
388
    if (rw)
389
        *val = retu_read(s, reg);
390
    else
391
        retu_write(s, reg, *val);
392
}
393

    
394
void *retu_init(qemu_irq irq, int vilma)
395
{
396
    struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s));
397

    
398
    s->irq = irq;
399
    s->irqen = 0xffff;
400
    s->irqst = 0x0000;
401
    s->status = 0x0020;
402
    s->is_vilma = !!vilma;
403
    s->rtc.cal = 0x01;
404
    s->result[retu_adc_bsi] = 0x3c2;
405
    s->result[retu_adc_batt_temp] = 0x0fc;
406
    s->result[retu_adc_chg_volt] = 0x165;
407
    s->result[retu_adc_head_det] = 123;
408
    s->result[retu_adc_hook_det] = 1023;
409
    s->result[retu_adc_rf_gp] = 0x11;
410
    s->result[retu_adc_tx_det] = 0x11;
411
    s->result[retu_adc_batt_volt] = 0x250;
412
    s->result[retu_adc_sens] = 2;
413
    s->result[retu_adc_sens_temp] = 0x11;
414
    s->result[retu_adc_bbatt_volt] = 0x3d0;
415
    s->result[retu_adc_self_temp] = 0x330;
416

    
417
    s->cbus.opaque = s;
418
    s->cbus.io = retu_io;
419
    s->cbus.addr = 1;
420

    
421
    return &s->cbus;
422
}
423

    
424
void retu_key_event(void *retu, int state)
425
{
426
    struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
427
    struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
428

    
429
    s->irqst |= 1 << retu_int_pwr;
430
    retu_interrupt_update(s);
431

    
432
    if (state)
433
        s->status &= ~(1 << 5);
434
    else
435
        s->status |= 1 << 5;
436
}
437

    
438
#if 0
439
static void retu_head_event(void *retu, int state)
440
{
441
    struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
442
    struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
443

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

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

456
static void retu_hook_event(void *retu, int state)
457
{
458
    struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
459
    struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
460

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

467
    if (state)
468
        s->result[retu_adc_hook_det] = 50;
469
    else
470
        s->result[retu_adc_hook_det] = 123;
471
}
472
#endif
473

    
474
/* Tahvo/Betty */
475
struct cbus_tahvo_s {
476
    uint16_t irqst;
477
    uint16_t irqen;
478
    uint8_t charger;
479
    uint8_t backlight;
480
    uint16_t usbr;
481
    uint16_t power;
482

    
483
    int is_betty;
484
    qemu_irq irq;
485
    struct cbus_slave_s cbus;
486
};
487

    
488
static void tahvo_interrupt_update(struct cbus_tahvo_s *s)
489
{
490
    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
491
}
492

    
493
#define TAHVO_REG_ASICR                0x00        /* (RO) ASIC ID & revision */
494
#define TAHVO_REG_IDR                0x01        /* (T)  Interrupt ID */
495
#define TAHVO_REG_IDSR                0x02        /* (RO) Interrupt status */
496
#define TAHVO_REG_IMR                0x03        /* (RW) Interrupt mask */
497
#define TAHVO_REG_CHAPWMR        0x04        /* (RW) Charger PWM */
498
#define TAHVO_REG_LEDPWMR        0x05        /* (RW) LED PWM */
499
#define TAHVO_REG_USBR                0x06        /* (RW) USB control */
500
#define TAHVO_REG_RCR                0x07        /* (RW) Some kind of power management */
501
#define TAHVO_REG_CCR1                0x08        /* (RW) Common control register 1 */
502
#define TAHVO_REG_CCR2                0x09        /* (RW) Common control register 2 */
503
#define TAHVO_REG_TESTR1        0x0a        /* (RW) Test register 1 */
504
#define TAHVO_REG_TESTR2        0x0b        /* (RW) Test register 2 */
505
#define TAHVO_REG_NOPR                0x0c        /* (RW) Number of periods */
506
#define TAHVO_REG_FRR                0x0d        /* (RO) FR */
507

    
508
static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg)
509
{
510
#ifdef DEBUG
511
    printf("TAHVO read at %02x\n", reg);
512
#endif
513

    
514
    switch (reg) {
515
    case TAHVO_REG_ASICR:
516
        return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);        /* 22 in N810 */
517

    
518
    case TAHVO_REG_IDR:
519
    case TAHVO_REG_IDSR:        /* XXX: what does this do?  */
520
        return s->irqst;
521

    
522
    case TAHVO_REG_IMR:
523
        return s->irqen;
524

    
525
    case TAHVO_REG_CHAPWMR:
526
        return s->charger;
527

    
528
    case TAHVO_REG_LEDPWMR:
529
        return s->backlight;
530

    
531
    case TAHVO_REG_USBR:
532
        return s->usbr;
533

    
534
    case TAHVO_REG_RCR:
535
        return s->power;
536

    
537
    case TAHVO_REG_CCR1:
538
    case TAHVO_REG_CCR2:
539
    case TAHVO_REG_TESTR1:
540
    case TAHVO_REG_TESTR2:
541
    case TAHVO_REG_NOPR:
542
    case TAHVO_REG_FRR:
543
        return 0x0000;
544

    
545
    default:
546
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
547
                        __FUNCTION__, reg);
548
    }
549
}
550

    
551
static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val)
552
{
553
#ifdef DEBUG
554
    printf("TAHVO write of %04x at %02x\n", val, reg);
555
#endif
556

    
557
    switch (reg) {
558
    case TAHVO_REG_IDR:
559
        s->irqst ^= val;
560
        tahvo_interrupt_update(s);
561
        break;
562

    
563
    case TAHVO_REG_IMR:
564
        s->irqen = val;
565
        tahvo_interrupt_update(s);
566
        break;
567

    
568
    case TAHVO_REG_CHAPWMR:
569
        s->charger = val;
570
        break;
571

    
572
    case TAHVO_REG_LEDPWMR:
573
        if (s->backlight != (val & 0x7f)) {
574
            s->backlight = val & 0x7f;
575
            printf("%s: LCD backlight now at %i / 127\n",
576
                            __FUNCTION__, s->backlight);
577
        }
578
        break;
579

    
580
    case TAHVO_REG_USBR:
581
        s->usbr = val;
582
        break;
583

    
584
    case TAHVO_REG_RCR:
585
        s->power = val;
586
        break;
587

    
588
    case TAHVO_REG_CCR1:
589
    case TAHVO_REG_CCR2:
590
    case TAHVO_REG_TESTR1:
591
    case TAHVO_REG_TESTR2:
592
    case TAHVO_REG_NOPR:
593
    case TAHVO_REG_FRR:
594
        break;
595

    
596
    default:
597
        cpu_abort(cpu_single_env, "%s: bad register %02x\n",
598
                        __FUNCTION__, reg);
599
    }
600
}
601

    
602
static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
603
{
604
    struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque;
605

    
606
    if (rw)
607
        *val = tahvo_read(s, reg);
608
    else
609
        tahvo_write(s, reg, *val);
610
}
611

    
612
void *tahvo_init(qemu_irq irq, int betty)
613
{
614
    struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s));
615

    
616
    s->irq = irq;
617
    s->irqen = 0xffff;
618
    s->irqst = 0x0000;
619
    s->is_betty = !!betty;
620

    
621
    s->cbus.opaque = s;
622
    s->cbus.io = tahvo_io;
623
    s->cbus.addr = 2;
624

    
625
    return &s->cbus;
626
}