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