]> git.proxmox.com Git - qemu.git/blame - hw/cbus.c
user: Restore debug usage message for '-d ?' in user mode emulation
[qemu.git] / hw / cbus.c
CommitLineData
7e7c5e4c
AZ
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 *
fad6cb1a 19 * You should have received a copy of the GNU General Public License along
8167ee88 20 * with this program; if not, see <http://www.gnu.org/licenses/>.
7e7c5e4c
AZ
21 */
22
23#include "qemu-common.h"
24#include "irq.h"
25#include "devices.h"
26#include "sysemu.h"
27
28//#define DEBUG
29
bc24a225
PB
30typedef struct {
31 void *opaque;
32 void (*io)(void *opaque, int rw, int reg, uint16_t *val);
33 int addr;
34} CBusSlave;
35
36typedef struct {
37 CBus cbus;
7e7c5e4c
AZ
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
bc24a225
PB
55 CBusSlave *slave[8];
56} CBusPriv;
7e7c5e4c 57
bc24a225 58static void cbus_io(CBusPriv *s)
7e7c5e4c
AZ
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
2ac71179 64 hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
7e7c5e4c
AZ
65}
66
bc24a225 67static void cbus_cycle(CBusPriv *s)
7e7c5e4c
AZ
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
96static void cbus_clk(void *opaque, int line, int level)
97{
bc24a225 98 CBusPriv *s = (CBusPriv *) opaque;
7e7c5e4c
AZ
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
113static void cbus_dat(void *opaque, int line, int level)
114{
bc24a225 115 CBusPriv *s = (CBusPriv *) opaque;
7e7c5e4c
AZ
116
117 s->dat = level;
118}
119
120static void cbus_sel(void *opaque, int line, int level)
121{
bc24a225 122 CBusPriv *s = (CBusPriv *) opaque;
7e7c5e4c
AZ
123
124 if (!level) {
125 s->dir = 1;
126 s->bit = 8;
127 s->val = 0;
128 }
129
130 s->sel = level;
131}
132
bc24a225 133CBus *cbus_init(qemu_irq dat)
7e7c5e4c 134{
bc24a225 135 CBusPriv *s = (CBusPriv *) qemu_mallocz(sizeof(*s));
7e7c5e4c
AZ
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
bc24a225 149void cbus_attach(CBus *bus, void *slave_opaque)
7e7c5e4c 150{
bc24a225
PB
151 CBusSlave *slave = (CBusSlave *) slave_opaque;
152 CBusPriv *s = (CBusPriv *) bus;
7e7c5e4c
AZ
153
154 s->slave[slave->addr] = slave;
155}
156
157/* Retu/Vilma */
bc24a225 158typedef struct {
7e7c5e4c
AZ
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;
bc24a225
PB
173 CBusSlave cbus;
174} CBusRetu;
7e7c5e4c 175
bc24a225 176static void retu_interrupt_update(CBusRetu *s)
7e7c5e4c
AZ
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 */
210enum {
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 */
223enum {
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
bc24a225 238static inline uint16_t retu_read(CBusRetu *s, int reg)
7e7c5e4c
AZ
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:
2ac71179 301 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
302 }
303}
304
bc24a225 305static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
7e7c5e4c
AZ
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:
2ac71179 374 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
375 }
376}
377
378static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
379{
bc24a225 380 CBusRetu *s = (CBusRetu *) opaque;
7e7c5e4c
AZ
381
382 if (rw)
383 *val = retu_read(s, reg);
384 else
385 retu_write(s, reg, *val);
386}
387
388void *retu_init(qemu_irq irq, int vilma)
389{
bc24a225 390 CBusRetu *s = (CBusRetu *) qemu_mallocz(sizeof(*s));
7e7c5e4c
AZ
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
418void retu_key_event(void *retu, int state)
419{
bc24a225
PB
420 CBusSlave *slave = (CBusSlave *) retu;
421 CBusRetu *s = (CBusRetu *) slave->opaque;
7e7c5e4c
AZ
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
b1d8e52e
BS
432#if 0
433static void retu_head_event(void *retu, int state)
7e7c5e4c 434{
bc24a225
PB
435 CBusSlave *slave = (CBusSlave *) retu;
436 CBusRetu *s = (CBusRetu *) slave->opaque;
7e7c5e4c
AZ
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
b1d8e52e 450static void retu_hook_event(void *retu, int state)
7e7c5e4c 451{
bc24a225
PB
452 CBusSlave *slave = (CBusSlave *) retu;
453 CBusRetu *s = (CBusRetu *) slave->opaque;
7e7c5e4c
AZ
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}
b1d8e52e 466#endif
7e7c5e4c
AZ
467
468/* Tahvo/Betty */
bc24a225 469typedef struct {
7e7c5e4c
AZ
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;
bc24a225
PB
479 CBusSlave cbus;
480} CBusTahvo;
7e7c5e4c 481
bc24a225 482static void tahvo_interrupt_update(CBusTahvo *s)
7e7c5e4c
AZ
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
bc24a225 502static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
7e7c5e4c
AZ
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:
2ac71179 540 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
541 }
542}
543
bc24a225 544static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
7e7c5e4c
AZ
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:
2ac71179 590 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
591 }
592}
593
594static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
595{
bc24a225 596 CBusTahvo *s = (CBusTahvo *) opaque;
7e7c5e4c
AZ
597
598 if (rw)
599 *val = tahvo_read(s, reg);
600 else
601 tahvo_write(s, reg, *val);
602}
603
604void *tahvo_init(qemu_irq irq, int betty)
605{
bc24a225 606 CBusTahvo *s = (CBusTahvo *) qemu_mallocz(sizeof(*s));
7e7c5e4c
AZ
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}