Statistics
| Branch: | Revision:

root / hw / cbus.c @ 9c17d615

History | View | Annotate | Download (14.8 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, see <http://www.gnu.org/licenses/>.
21
 */
22

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

    
28
//#define DEBUG
29

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

    
36
typedef struct {
37
    CBus cbus;
38

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

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

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

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

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

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

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

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

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

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

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

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

    
110
    s->clk = level;
111
}
112

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

    
117
    s->dat = level;
118
}
119

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

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

    
130
    s->sel = level;
131
}
132

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

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

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

    
146
    return &s->cbus;
147
}
148

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
415
    return &s->cbus;
416
}
417

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
617
    return &s->cbus;
618
}