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