Statistics
| Branch: | Revision:

root / hw / cbus.c @ aba35a6c

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 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
struct cbus_slave_s;
32
struct cbus_priv_s {
33
    struct cbus_s cbus;
34

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

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

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

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

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

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

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

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

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

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

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

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

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

    
113
    s->clk = level;
114
}
115

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

    
120
    s->dat = level;
121
}
122

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

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

    
133
    s->sel = level;
134
}
135

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

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

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

    
149
    return &s->cbus;
150
}
151

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
420
    return &s->cbus;
421
}
422

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
624
    return &s->cbus;
625
}