]> git.proxmox.com Git - qemu.git/blame - hw/cbus.c
Workaround compiler warnings at -O1
[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
AJ
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.
7e7c5e4c
AZ
22 */
23
24#include "qemu-common.h"
25#include "irq.h"
26#include "devices.h"
27#include "sysemu.h"
28
29//#define DEBUG
30
31struct cbus_slave_s;
32struct 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
54struct cbus_slave_s {
55 void *opaque;
56 void (*io)(void *opaque, int rw, int reg, uint16_t *val);
57 int addr;
58};
59
60static 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
2ac71179 66 hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
7e7c5e4c
AZ
67}
68
69static void cbus_cycle(struct cbus_priv_s *s)
70{
71 switch (s->cycle) {
72 case cbus_address:
73 s->addr = (s->val >> 6) & 7;
74 s->rw = (s->val >> 5) & 1;
75 s->reg = (s->val >> 0) & 0x1f;
76
77 s->cycle = cbus_value;
78 s->bit = 15;
79 s->dir = !s->rw;
80 s->val = 0;
81
82 if (s->rw)
83 cbus_io(s);
84 break;
85
86 case cbus_value:
87 if (!s->rw)
88 cbus_io(s);
89
90 s->cycle = cbus_address;
91 s->bit = 8;
92 s->dir = 1;
93 s->val = 0;
94 break;
95 }
96}
97
98static void cbus_clk(void *opaque, int line, int level)
99{
100 struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
101
102 if (!s->sel && level && !s->clk) {
103 if (s->dir)
104 s->val |= s->dat << (s->bit --);
105 else
106 qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
107
108 if (s->bit < 0)
109 cbus_cycle(s);
110 }
111
112 s->clk = level;
113}
114
115static void cbus_dat(void *opaque, int line, int level)
116{
117 struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
118
119 s->dat = level;
120}
121
122static void cbus_sel(void *opaque, int line, int level)
123{
124 struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
125
126 if (!level) {
127 s->dir = 1;
128 s->bit = 8;
129 s->val = 0;
130 }
131
132 s->sel = level;
133}
134
135struct cbus_s *cbus_init(qemu_irq dat)
136{
137 struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s));
138
139 s->dat_out = dat;
140 s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
141 s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
142 s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
143
144 s->sel = 1;
145 s->clk = 0;
146 s->dat = 0;
147
148 return &s->cbus;
149}
150
151void cbus_attach(struct cbus_s *bus, void *slave_opaque)
152{
153 struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque;
154 struct cbus_priv_s *s = (struct cbus_priv_s *) bus;
155
156 s->slave[slave->addr] = slave;
157}
158
159/* Retu/Vilma */
160struct cbus_retu_s {
161 uint16_t irqst;
162 uint16_t irqen;
163 uint16_t cc[2];
164 int channel;
165 uint16_t result[16];
166 uint16_t sample;
167 uint16_t status;
168
169 struct {
170 uint16_t cal;
171 } rtc;
172
173 int is_vilma;
174 qemu_irq irq;
175 struct cbus_slave_s cbus;
176};
177
178static void retu_interrupt_update(struct cbus_retu_s *s)
179{
180 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
181}
182
183#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
184#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
185#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
186#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
187#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
188#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
189#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
190#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
191#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
192#define RETU_REG_AFCR 0x0a /* (RW) AFC register */
193#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
194#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
195#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
196#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
197#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
198#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
199#define RETU_REG_TXCR 0x11 /* (RW) TxC register */
200#define RETU_REG_STATUS 0x16 /* (RO) Status register */
201#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
202#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
203#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
204#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
205#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
206#define RETU_REG_SGR1 0x1c /* (RW) */
207#define RETU_REG_SCR1 0x1d /* (RW) */
208#define RETU_REG_SGR2 0x1e /* (RW) */
209#define RETU_REG_SCR2 0x1f /* (RW) */
210
211/* Retu Interrupt sources */
212enum {
213 retu_int_pwr = 0, /* Power button */
214 retu_int_char = 1, /* Charger */
215 retu_int_rtcs = 2, /* Seconds */
216 retu_int_rtcm = 3, /* Minutes */
217 retu_int_rtcd = 4, /* Days */
218 retu_int_rtca = 5, /* Alarm */
219 retu_int_hook = 6, /* Hook */
220 retu_int_head = 7, /* Headset */
221 retu_int_adcs = 8, /* ADC sample */
222};
223
224/* Retu ADC channel wiring */
225enum {
226 retu_adc_bsi = 1, /* BSI */
227 retu_adc_batt_temp = 2, /* Battery temperature */
228 retu_adc_chg_volt = 3, /* Charger voltage */
229 retu_adc_head_det = 4, /* Headset detection */
230 retu_adc_hook_det = 5, /* Hook detection */
231 retu_adc_rf_gp = 6, /* RF GP */
232 retu_adc_tx_det = 7, /* Wideband Tx detection */
233 retu_adc_batt_volt = 8, /* Battery voltage */
234 retu_adc_sens = 10, /* Light sensor */
235 retu_adc_sens_temp = 11, /* Light sensor temperature */
236 retu_adc_bbatt_volt = 12, /* Backup battery voltage */
237 retu_adc_self_temp = 13, /* RETU temperature */
238};
239
240static inline uint16_t retu_read(struct cbus_retu_s *s, int reg)
241{
242#ifdef DEBUG
243 printf("RETU read at %02x\n", reg);
244#endif
245
246 switch (reg) {
247 case RETU_REG_ASICR:
248 return 0x0215 | (s->is_vilma << 7);
249
250 case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
251 return s->irqst;
252
253 case RETU_REG_IMR:
254 return s->irqen;
255
256 case RETU_REG_RTCDSR:
257 case RETU_REG_RTCHMR:
258 case RETU_REG_RTCHMAR:
259 /* TODO */
260 return 0x0000;
261
262 case RETU_REG_RTCCALR:
263 return s->rtc.cal;
264
265 case RETU_REG_ADCR:
266 return (s->channel << 10) | s->result[s->channel];
267 case RETU_REG_ADCSCR:
268 return s->sample;
269
270 case RETU_REG_AFCR:
271 case RETU_REG_ANTIFR:
272 case RETU_REG_CALIBR:
273 /* TODO */
274 return 0x0000;
275
276 case RETU_REG_CCR1:
277 return s->cc[0];
278 case RETU_REG_CCR2:
279 return s->cc[1];
280
281 case RETU_REG_RCTRL_CLR:
282 case RETU_REG_RCTRL_SET:
283 case RETU_REG_TXCR:
284 /* TODO */
285 return 0x0000;
286
287 case RETU_REG_STATUS:
288 return s->status;
289
290 case RETU_REG_WATCHDOG:
291 case RETU_REG_AUDTXR:
292 case RETU_REG_AUDPAR:
293 case RETU_REG_AUDRXR1:
294 case RETU_REG_AUDRXR2:
295 case RETU_REG_SGR1:
296 case RETU_REG_SCR1:
297 case RETU_REG_SGR2:
298 case RETU_REG_SCR2:
299 /* TODO */
300 return 0x0000;
301
302 default:
2ac71179 303 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
304 }
305}
306
307static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val)
308{
309#ifdef DEBUG
310 printf("RETU write of %04x at %02x\n", val, reg);
311#endif
312
313 switch (reg) {
314 case RETU_REG_IDR:
315 s->irqst ^= val;
316 retu_interrupt_update(s);
317 break;
318
319 case RETU_REG_IMR:
320 s->irqen = val;
321 retu_interrupt_update(s);
322 break;
323
324 case RETU_REG_RTCDSR:
325 case RETU_REG_RTCHMAR:
326 /* TODO */
327 break;
328
329 case RETU_REG_RTCCALR:
330 s->rtc.cal = val;
331 break;
332
333 case RETU_REG_ADCR:
334 s->channel = (val >> 10) & 0xf;
335 s->irqst |= 1 << retu_int_adcs;
336 retu_interrupt_update(s);
337 break;
338 case RETU_REG_ADCSCR:
339 s->sample &= ~val;
340 break;
341
342 case RETU_REG_AFCR:
343 case RETU_REG_ANTIFR:
344 case RETU_REG_CALIBR:
345
346 case RETU_REG_CCR1:
347 s->cc[0] = val;
348 break;
349 case RETU_REG_CCR2:
350 s->cc[1] = val;
351 break;
352
353 case RETU_REG_RCTRL_CLR:
354 case RETU_REG_RCTRL_SET:
355 /* TODO */
356 break;
357
358 case RETU_REG_WATCHDOG:
359 if (val == 0 && (s->cc[0] & 2))
360 qemu_system_shutdown_request();
361 break;
362
363 case RETU_REG_TXCR:
364 case RETU_REG_AUDTXR:
365 case RETU_REG_AUDPAR:
366 case RETU_REG_AUDRXR1:
367 case RETU_REG_AUDRXR2:
368 case RETU_REG_SGR1:
369 case RETU_REG_SCR1:
370 case RETU_REG_SGR2:
371 case RETU_REG_SCR2:
372 /* TODO */
373 break;
374
375 default:
2ac71179 376 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
377 }
378}
379
380static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
381{
382 struct cbus_retu_s *s = (struct cbus_retu_s *) opaque;
383
384 if (rw)
385 *val = retu_read(s, reg);
386 else
387 retu_write(s, reg, *val);
388}
389
390void *retu_init(qemu_irq irq, int vilma)
391{
392 struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s));
393
394 s->irq = irq;
395 s->irqen = 0xffff;
396 s->irqst = 0x0000;
397 s->status = 0x0020;
398 s->is_vilma = !!vilma;
399 s->rtc.cal = 0x01;
400 s->result[retu_adc_bsi] = 0x3c2;
401 s->result[retu_adc_batt_temp] = 0x0fc;
402 s->result[retu_adc_chg_volt] = 0x165;
403 s->result[retu_adc_head_det] = 123;
404 s->result[retu_adc_hook_det] = 1023;
405 s->result[retu_adc_rf_gp] = 0x11;
406 s->result[retu_adc_tx_det] = 0x11;
407 s->result[retu_adc_batt_volt] = 0x250;
408 s->result[retu_adc_sens] = 2;
409 s->result[retu_adc_sens_temp] = 0x11;
410 s->result[retu_adc_bbatt_volt] = 0x3d0;
411 s->result[retu_adc_self_temp] = 0x330;
412
413 s->cbus.opaque = s;
414 s->cbus.io = retu_io;
415 s->cbus.addr = 1;
416
417 return &s->cbus;
418}
419
420void retu_key_event(void *retu, int state)
421{
422 struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
423 struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
424
425 s->irqst |= 1 << retu_int_pwr;
426 retu_interrupt_update(s);
427
428 if (state)
429 s->status &= ~(1 << 5);
430 else
431 s->status |= 1 << 5;
432}
433
b1d8e52e
BS
434#if 0
435static void retu_head_event(void *retu, int state)
7e7c5e4c
AZ
436{
437 struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
438 struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
439
440 if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
441 /* TODO: reissue the interrupt every 100ms or so. */
442 s->irqst |= 1 << retu_int_head;
443 retu_interrupt_update(s);
444 }
445
446 if (state)
447 s->result[retu_adc_head_det] = 50;
448 else
449 s->result[retu_adc_head_det] = 123;
450}
451
b1d8e52e 452static void retu_hook_event(void *retu, int state)
7e7c5e4c
AZ
453{
454 struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
455 struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
456
457 if ((s->cc[0] & 0x500) == 0x500) {
458 /* TODO: reissue the interrupt every 100ms or so. */
459 s->irqst |= 1 << retu_int_hook;
460 retu_interrupt_update(s);
461 }
462
463 if (state)
464 s->result[retu_adc_hook_det] = 50;
465 else
466 s->result[retu_adc_hook_det] = 123;
467}
b1d8e52e 468#endif
7e7c5e4c
AZ
469
470/* Tahvo/Betty */
471struct cbus_tahvo_s {
472 uint16_t irqst;
473 uint16_t irqen;
474 uint8_t charger;
475 uint8_t backlight;
476 uint16_t usbr;
477 uint16_t power;
478
479 int is_betty;
480 qemu_irq irq;
481 struct cbus_slave_s cbus;
482};
483
484static void tahvo_interrupt_update(struct cbus_tahvo_s *s)
485{
486 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
487}
488
489#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
490#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
491#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
492#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
493#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
494#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
495#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
496#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
497#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
498#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
499#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
500#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
501#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
502#define TAHVO_REG_FRR 0x0d /* (RO) FR */
503
504static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg)
505{
506#ifdef DEBUG
507 printf("TAHVO read at %02x\n", reg);
508#endif
509
510 switch (reg) {
511 case TAHVO_REG_ASICR:
512 return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
513
514 case TAHVO_REG_IDR:
515 case TAHVO_REG_IDSR: /* XXX: what does this do? */
516 return s->irqst;
517
518 case TAHVO_REG_IMR:
519 return s->irqen;
520
521 case TAHVO_REG_CHAPWMR:
522 return s->charger;
523
524 case TAHVO_REG_LEDPWMR:
525 return s->backlight;
526
527 case TAHVO_REG_USBR:
528 return s->usbr;
529
530 case TAHVO_REG_RCR:
531 return s->power;
532
533 case TAHVO_REG_CCR1:
534 case TAHVO_REG_CCR2:
535 case TAHVO_REG_TESTR1:
536 case TAHVO_REG_TESTR2:
537 case TAHVO_REG_NOPR:
538 case TAHVO_REG_FRR:
539 return 0x0000;
540
541 default:
2ac71179 542 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
543 }
544}
545
546static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val)
547{
548#ifdef DEBUG
549 printf("TAHVO write of %04x at %02x\n", val, reg);
550#endif
551
552 switch (reg) {
553 case TAHVO_REG_IDR:
554 s->irqst ^= val;
555 tahvo_interrupt_update(s);
556 break;
557
558 case TAHVO_REG_IMR:
559 s->irqen = val;
560 tahvo_interrupt_update(s);
561 break;
562
563 case TAHVO_REG_CHAPWMR:
564 s->charger = val;
565 break;
566
567 case TAHVO_REG_LEDPWMR:
568 if (s->backlight != (val & 0x7f)) {
569 s->backlight = val & 0x7f;
570 printf("%s: LCD backlight now at %i / 127\n",
571 __FUNCTION__, s->backlight);
572 }
573 break;
574
575 case TAHVO_REG_USBR:
576 s->usbr = val;
577 break;
578
579 case TAHVO_REG_RCR:
580 s->power = val;
581 break;
582
583 case TAHVO_REG_CCR1:
584 case TAHVO_REG_CCR2:
585 case TAHVO_REG_TESTR1:
586 case TAHVO_REG_TESTR2:
587 case TAHVO_REG_NOPR:
588 case TAHVO_REG_FRR:
589 break;
590
591 default:
2ac71179 592 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
7e7c5e4c
AZ
593 }
594}
595
596static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
597{
598 struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque;
599
600 if (rw)
601 *val = tahvo_read(s, reg);
602 else
603 tahvo_write(s, reg, *val);
604}
605
606void *tahvo_init(qemu_irq irq, int betty)
607{
608 struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s));
609
610 s->irq = irq;
611 s->irqen = 0xffff;
612 s->irqst = 0x0000;
613 s->is_betty = !!betty;
614
615 s->cbus.opaque = s;
616 s->cbus.io = tahvo_io;
617 s->cbus.addr = 2;
618
619 return &s->cbus;
620}