packing update
[qemu] / hw / cbus.c
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 }