Statistics
| Branch: | Revision:

root / hw / cbus.c @ f40070c3

History | View | Annotate | Download (14.9 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 along
20
 * with this program; if not, write to the Free Software Foundation, Inc.,
21
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
 */
23

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

    
29
//#define DEBUG
30

    
31
typedef struct {
32
    void *opaque;
33
    void (*io)(void *opaque, int rw, int reg, uint16_t *val);
34
    int addr;
35
} CBusSlave;
36

    
37
typedef struct {
38
    CBus cbus;
39

    
40
    int sel;
41
    int dat;
42
    int clk;
43
    int bit;
44
    int dir;
45
    uint16_t val;
46
    qemu_irq dat_out;
47

    
48
    int addr;
49
    int reg;
50
    int rw;
51
    enum {
52
        cbus_address,
53
        cbus_value,
54
    } cycle;
55

    
56
    CBusSlave *slave[8];
57
} CBusPriv;
58

    
59
static void cbus_io(CBusPriv *s)
60
{
61
    if (s->slave[s->addr])
62
        s->slave[s->addr]->io(s->slave[s->addr]->opaque,
63
                        s->rw, s->reg, &s->val);
64
    else
65
        hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
66
}
67

    
68
static void cbus_cycle(CBusPriv *s)
69
{
70
    switch (s->cycle) {
71
    case cbus_address:
72
        s->addr = (s->val >> 6) & 7;
73
        s->rw =   (s->val >> 5) & 1;
74
        s->reg =  (s->val >> 0) & 0x1f;
75

    
76
        s->cycle = cbus_value;
77
        s->bit = 15;
78
        s->dir = !s->rw;
79
        s->val = 0;
80

    
81
        if (s->rw)
82
            cbus_io(s);
83
        break;
84

    
85
    case cbus_value:
86
        if (!s->rw)
87
            cbus_io(s);
88

    
89
        s->cycle = cbus_address;
90
        s->bit = 8;
91
        s->dir = 1;
92
        s->val = 0;
93
        break;
94
    }
95
}
96

    
97
static void cbus_clk(void *opaque, int line, int level)
98
{
99
    CBusPriv *s = (CBusPriv *) opaque;
100

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

    
107
        if (s->bit < 0)
108
            cbus_cycle(s);
109
    }
110

    
111
    s->clk = level;
112
}
113

    
114
static void cbus_dat(void *opaque, int line, int level)
115
{
116
    CBusPriv *s = (CBusPriv *) opaque;
117

    
118
    s->dat = level;
119
}
120

    
121
static void cbus_sel(void *opaque, int line, int level)
122
{
123
    CBusPriv *s = (CBusPriv *) opaque;
124

    
125
    if (!level) {
126
        s->dir = 1;
127
        s->bit = 8;
128
        s->val = 0;
129
    }
130

    
131
    s->sel = level;
132
}
133

    
134
CBus *cbus_init(qemu_irq dat)
135
{
136
    CBusPriv *s = (CBusPriv *) qemu_mallocz(sizeof(*s));
137

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

    
143
    s->sel = 1;
144
    s->clk = 0;
145
    s->dat = 0;
146

    
147
    return &s->cbus;
148
}
149

    
150
void cbus_attach(CBus *bus, void *slave_opaque)
151
{
152
    CBusSlave *slave = (CBusSlave *) slave_opaque;
153
    CBusPriv *s = (CBusPriv *) bus;
154

    
155
    s->slave[slave->addr] = slave;
156
}
157

    
158
/* Retu/Vilma */
159
typedef struct {
160
    uint16_t irqst;
161
    uint16_t irqen;
162
    uint16_t cc[2];
163
    int channel;
164
    uint16_t result[16];
165
    uint16_t sample;
166
    uint16_t status;
167

    
168
    struct {
169
        uint16_t cal;
170
    } rtc;
171

    
172
    int is_vilma;
173
    qemu_irq irq;
174
    CBusSlave cbus;
175
} CBusRetu;
176

    
177
static void retu_interrupt_update(CBusRetu *s)
178
{
179
    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
180
}
181

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

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

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

    
239
static inline uint16_t retu_read(CBusRetu *s, int reg)
240
{
241
#ifdef DEBUG
242
    printf("RETU read at %02x\n", reg);
243
#endif
244

    
245
    switch (reg) {
246
    case RETU_REG_ASICR:
247
        return 0x0215 | (s->is_vilma << 7);
248

    
249
    case RETU_REG_IDR:        /* TODO: Or is this ffs(s->irqst)?  */
250
        return s->irqst;
251

    
252
    case RETU_REG_IMR:
253
        return s->irqen;
254

    
255
    case RETU_REG_RTCDSR:
256
    case RETU_REG_RTCHMR:
257
    case RETU_REG_RTCHMAR:
258
        /* TODO */
259
        return 0x0000;
260

    
261
    case RETU_REG_RTCCALR:
262
        return s->rtc.cal;
263

    
264
    case RETU_REG_ADCR:
265
        return (s->channel << 10) | s->result[s->channel];
266
    case RETU_REG_ADCSCR:
267
        return s->sample;
268

    
269
    case RETU_REG_AFCR:
270
    case RETU_REG_ANTIFR:
271
    case RETU_REG_CALIBR:
272
        /* TODO */
273
        return 0x0000;
274

    
275
    case RETU_REG_CCR1:
276
        return s->cc[0];
277
    case RETU_REG_CCR2:
278
        return s->cc[1];
279

    
280
    case RETU_REG_RCTRL_CLR:
281
    case RETU_REG_RCTRL_SET:
282
    case RETU_REG_TXCR:
283
        /* TODO */
284
        return 0x0000;
285

    
286
    case RETU_REG_STATUS:
287
        return s->status;
288

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

    
301
    default:
302
        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
303
    }
304
}
305

    
306
static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
307
{
308
#ifdef DEBUG
309
    printf("RETU write of %04x at %02x\n", val, reg);
310
#endif
311

    
312
    switch (reg) {
313
    case RETU_REG_IDR:
314
        s->irqst ^= val;
315
        retu_interrupt_update(s);
316
        break;
317

    
318
    case RETU_REG_IMR:
319
        s->irqen = val;
320
        retu_interrupt_update(s);
321
        break;
322

    
323
    case RETU_REG_RTCDSR:
324
    case RETU_REG_RTCHMAR:
325
        /* TODO */
326
        break;
327

    
328
    case RETU_REG_RTCCALR:
329
        s->rtc.cal = val;
330
        break;
331

    
332
    case RETU_REG_ADCR:
333
        s->channel = (val >> 10) & 0xf;
334
        s->irqst |= 1 << retu_int_adcs;
335
        retu_interrupt_update(s);
336
        break;
337
    case RETU_REG_ADCSCR:
338
        s->sample &= ~val;
339
        break;
340

    
341
    case RETU_REG_AFCR:
342
    case RETU_REG_ANTIFR:
343
    case RETU_REG_CALIBR:
344

    
345
    case RETU_REG_CCR1:
346
        s->cc[0] = val;
347
        break;
348
    case RETU_REG_CCR2:
349
        s->cc[1] = val;
350
        break;
351

    
352
    case RETU_REG_RCTRL_CLR:
353
    case RETU_REG_RCTRL_SET:
354
        /* TODO */
355
        break;
356

    
357
    case RETU_REG_WATCHDOG:
358
        if (val == 0 && (s->cc[0] & 2))
359
            qemu_system_shutdown_request();
360
        break;
361

    
362
    case RETU_REG_TXCR:
363
    case RETU_REG_AUDTXR:
364
    case RETU_REG_AUDPAR:
365
    case RETU_REG_AUDRXR1:
366
    case RETU_REG_AUDRXR2:
367
    case RETU_REG_SGR1:
368
    case RETU_REG_SCR1:
369
    case RETU_REG_SGR2:
370
    case RETU_REG_SCR2:
371
        /* TODO */
372
        break;
373

    
374
    default:
375
        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
376
    }
377
}
378

    
379
static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
380
{
381
    CBusRetu *s = (CBusRetu *) opaque;
382

    
383
    if (rw)
384
        *val = retu_read(s, reg);
385
    else
386
        retu_write(s, reg, *val);
387
}
388

    
389
void *retu_init(qemu_irq irq, int vilma)
390
{
391
    CBusRetu *s = (CBusRetu *) qemu_mallocz(sizeof(*s));
392

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

    
412
    s->cbus.opaque = s;
413
    s->cbus.io = retu_io;
414
    s->cbus.addr = 1;
415

    
416
    return &s->cbus;
417
}
418

    
419
void retu_key_event(void *retu, int state)
420
{
421
    CBusSlave *slave = (CBusSlave *) retu;
422
    CBusRetu *s = (CBusRetu *) slave->opaque;
423

    
424
    s->irqst |= 1 << retu_int_pwr;
425
    retu_interrupt_update(s);
426

    
427
    if (state)
428
        s->status &= ~(1 << 5);
429
    else
430
        s->status |= 1 << 5;
431
}
432

    
433
#if 0
434
static void retu_head_event(void *retu, int state)
435
{
436
    CBusSlave *slave = (CBusSlave *) retu;
437
    CBusRetu *s = (CBusRetu *) slave->opaque;
438

439
    if ((s->cc[0] & 0x500) == 0x500) {        /* TODO: Which bits? */
440
        /* TODO: reissue the interrupt every 100ms or so.  */
441
        s->irqst |= 1 << retu_int_head;
442
        retu_interrupt_update(s);
443
    }
444

445
    if (state)
446
        s->result[retu_adc_head_det] = 50;
447
    else
448
        s->result[retu_adc_head_det] = 123;
449
}
450

451
static void retu_hook_event(void *retu, int state)
452
{
453
    CBusSlave *slave = (CBusSlave *) retu;
454
    CBusRetu *s = (CBusRetu *) slave->opaque;
455

456
    if ((s->cc[0] & 0x500) == 0x500) {
457
        /* TODO: reissue the interrupt every 100ms or so.  */
458
        s->irqst |= 1 << retu_int_hook;
459
        retu_interrupt_update(s);
460
    }
461

462
    if (state)
463
        s->result[retu_adc_hook_det] = 50;
464
    else
465
        s->result[retu_adc_hook_det] = 123;
466
}
467
#endif
468

    
469
/* Tahvo/Betty */
470
typedef struct {
471
    uint16_t irqst;
472
    uint16_t irqen;
473
    uint8_t charger;
474
    uint8_t backlight;
475
    uint16_t usbr;
476
    uint16_t power;
477

    
478
    int is_betty;
479
    qemu_irq irq;
480
    CBusSlave cbus;
481
} CBusTahvo;
482

    
483
static void tahvo_interrupt_update(CBusTahvo *s)
484
{
485
    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
486
}
487

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

    
503
static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
504
{
505
#ifdef DEBUG
506
    printf("TAHVO read at %02x\n", reg);
507
#endif
508

    
509
    switch (reg) {
510
    case TAHVO_REG_ASICR:
511
        return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);        /* 22 in N810 */
512

    
513
    case TAHVO_REG_IDR:
514
    case TAHVO_REG_IDSR:        /* XXX: what does this do?  */
515
        return s->irqst;
516

    
517
    case TAHVO_REG_IMR:
518
        return s->irqen;
519

    
520
    case TAHVO_REG_CHAPWMR:
521
        return s->charger;
522

    
523
    case TAHVO_REG_LEDPWMR:
524
        return s->backlight;
525

    
526
    case TAHVO_REG_USBR:
527
        return s->usbr;
528

    
529
    case TAHVO_REG_RCR:
530
        return s->power;
531

    
532
    case TAHVO_REG_CCR1:
533
    case TAHVO_REG_CCR2:
534
    case TAHVO_REG_TESTR1:
535
    case TAHVO_REG_TESTR2:
536
    case TAHVO_REG_NOPR:
537
    case TAHVO_REG_FRR:
538
        return 0x0000;
539

    
540
    default:
541
        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
542
    }
543
}
544

    
545
static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
546
{
547
#ifdef DEBUG
548
    printf("TAHVO write of %04x at %02x\n", val, reg);
549
#endif
550

    
551
    switch (reg) {
552
    case TAHVO_REG_IDR:
553
        s->irqst ^= val;
554
        tahvo_interrupt_update(s);
555
        break;
556

    
557
    case TAHVO_REG_IMR:
558
        s->irqen = val;
559
        tahvo_interrupt_update(s);
560
        break;
561

    
562
    case TAHVO_REG_CHAPWMR:
563
        s->charger = val;
564
        break;
565

    
566
    case TAHVO_REG_LEDPWMR:
567
        if (s->backlight != (val & 0x7f)) {
568
            s->backlight = val & 0x7f;
569
            printf("%s: LCD backlight now at %i / 127\n",
570
                            __FUNCTION__, s->backlight);
571
        }
572
        break;
573

    
574
    case TAHVO_REG_USBR:
575
        s->usbr = val;
576
        break;
577

    
578
    case TAHVO_REG_RCR:
579
        s->power = val;
580
        break;
581

    
582
    case TAHVO_REG_CCR1:
583
    case TAHVO_REG_CCR2:
584
    case TAHVO_REG_TESTR1:
585
    case TAHVO_REG_TESTR2:
586
    case TAHVO_REG_NOPR:
587
    case TAHVO_REG_FRR:
588
        break;
589

    
590
    default:
591
        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
592
    }
593
}
594

    
595
static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
596
{
597
    CBusTahvo *s = (CBusTahvo *) opaque;
598

    
599
    if (rw)
600
        *val = tahvo_read(s, reg);
601
    else
602
        tahvo_write(s, reg, *val);
603
}
604

    
605
void *tahvo_init(qemu_irq irq, int betty)
606
{
607
    CBusTahvo *s = (CBusTahvo *) qemu_mallocz(sizeof(*s));
608

    
609
    s->irq = irq;
610
    s->irqen = 0xffff;
611
    s->irqst = 0x0000;
612
    s->is_betty = !!betty;
613

    
614
    s->cbus.opaque = s;
615
    s->cbus.io = tahvo_io;
616
    s->cbus.addr = 2;
617

    
618
    return &s->cbus;
619
}