b60ec057983b3e5613a29a7e3538a89f565cee05
[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         hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
67 }
68
69 static 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
98 static 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
115 static 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
122 static 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
135 struct 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
151 void 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 */
160 struct 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
178 static 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 */
212 enum {
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 */
225 enum {
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
240 static 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:
303         hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
304     }
305 }
306
307 static 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:
376         hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
377     }
378 }
379
380 static 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
390 void *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
420 void 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
434 #if 0
435 static void retu_head_event(void *retu, int state)
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
452 static void retu_hook_event(void *retu, int state)
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 }
468 #endif
469
470 /* Tahvo/Betty */
471 struct 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
484 static 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
504 static 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:
542         hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
543     }
544 }
545
546 static 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:
592         hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
593     }
594 }
595
596 static 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
606 void *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 }