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.
6 * Copyright (C) 2008 Nokia Corporation
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.
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.
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.
24 #include "qemu-common.h"
33 void (*io)(void *opaque, int rw, int reg, uint16_t *val);
59 static void cbus_io(CBusPriv *s)
61 if (s->slave[s->addr])
62 s->slave[s->addr]->io(s->slave[s->addr]->opaque,
63 s->rw, s->reg, &s->val);
65 hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
68 static void cbus_cycle(CBusPriv *s)
72 s->addr = (s->val >> 6) & 7;
73 s->rw = (s->val >> 5) & 1;
74 s->reg = (s->val >> 0) & 0x1f;
76 s->cycle = cbus_value;
89 s->cycle = cbus_address;
97 static void cbus_clk(void *opaque, int line, int level)
99 CBusPriv *s = (CBusPriv *) opaque;
101 if (!s->sel && level && !s->clk) {
103 s->val |= s->dat << (s->bit --);
105 qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
114 static void cbus_dat(void *opaque, int line, int level)
116 CBusPriv *s = (CBusPriv *) opaque;
121 static void cbus_sel(void *opaque, int line, int level)
123 CBusPriv *s = (CBusPriv *) opaque;
134 CBus *cbus_init(qemu_irq dat)
136 CBusPriv *s = (CBusPriv *) qemu_mallocz(sizeof(*s));
139 s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
140 s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
141 s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
150 void cbus_attach(CBus *bus, void *slave_opaque)
152 CBusSlave *slave = (CBusSlave *) slave_opaque;
153 CBusPriv *s = (CBusPriv *) bus;
155 s->slave[slave->addr] = slave;
177 static void retu_interrupt_update(CBusRetu *s)
179 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
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) */
210 /* Retu Interrupt sources */
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 */
223 /* Retu ADC channel wiring */
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 */
239 static inline uint16_t retu_read(CBusRetu *s, int reg)
242 printf("RETU read at %02x\n", reg);
247 return 0x0215 | (s->is_vilma << 7);
249 case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
255 case RETU_REG_RTCDSR:
256 case RETU_REG_RTCHMR:
257 case RETU_REG_RTCHMAR:
261 case RETU_REG_RTCCALR:
265 return (s->channel << 10) | s->result[s->channel];
266 case RETU_REG_ADCSCR:
270 case RETU_REG_ANTIFR:
271 case RETU_REG_CALIBR:
280 case RETU_REG_RCTRL_CLR:
281 case RETU_REG_RCTRL_SET:
286 case RETU_REG_STATUS:
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:
302 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
306 static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
309 printf("RETU write of %04x at %02x\n", val, reg);
315 retu_interrupt_update(s);
320 retu_interrupt_update(s);
323 case RETU_REG_RTCDSR:
324 case RETU_REG_RTCHMAR:
328 case RETU_REG_RTCCALR:
333 s->channel = (val >> 10) & 0xf;
334 s->irqst |= 1 << retu_int_adcs;
335 retu_interrupt_update(s);
337 case RETU_REG_ADCSCR:
342 case RETU_REG_ANTIFR:
343 case RETU_REG_CALIBR:
352 case RETU_REG_RCTRL_CLR:
353 case RETU_REG_RCTRL_SET:
357 case RETU_REG_WATCHDOG:
358 if (val == 0 && (s->cc[0] & 2))
359 qemu_system_shutdown_request();
363 case RETU_REG_AUDTXR:
364 case RETU_REG_AUDPAR:
365 case RETU_REG_AUDRXR1:
366 case RETU_REG_AUDRXR2:
375 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
379 static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
381 CBusRetu *s = (CBusRetu *) opaque;
384 *val = retu_read(s, reg);
386 retu_write(s, reg, *val);
389 void *retu_init(qemu_irq irq, int vilma)
391 CBusRetu *s = (CBusRetu *) qemu_mallocz(sizeof(*s));
397 s->is_vilma = !!vilma;
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;
413 s->cbus.io = retu_io;
419 void retu_key_event(void *retu, int state)
421 CBusSlave *slave = (CBusSlave *) retu;
422 CBusRetu *s = (CBusRetu *) slave->opaque;
424 s->irqst |= 1 << retu_int_pwr;
425 retu_interrupt_update(s);
428 s->status &= ~(1 << 5);
434 static void retu_head_event(void *retu, int state)
436 CBusSlave *slave = (CBusSlave *) retu;
437 CBusRetu *s = (CBusRetu *) slave->opaque;
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);
446 s->result[retu_adc_head_det] = 50;
448 s->result[retu_adc_head_det] = 123;
451 static void retu_hook_event(void *retu, int state)
453 CBusSlave *slave = (CBusSlave *) retu;
454 CBusRetu *s = (CBusRetu *) slave->opaque;
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);
463 s->result[retu_adc_hook_det] = 50;
465 s->result[retu_adc_hook_det] = 123;
483 static void tahvo_interrupt_update(CBusTahvo *s)
485 qemu_set_irq(s->irq, s->irqst & ~s->irqen);
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 */
503 static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
506 printf("TAHVO read at %02x\n", reg);
510 case TAHVO_REG_ASICR:
511 return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
514 case TAHVO_REG_IDSR: /* XXX: what does this do? */
520 case TAHVO_REG_CHAPWMR:
523 case TAHVO_REG_LEDPWMR:
534 case TAHVO_REG_TESTR1:
535 case TAHVO_REG_TESTR2:
541 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
545 static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
548 printf("TAHVO write of %04x at %02x\n", val, reg);
554 tahvo_interrupt_update(s);
559 tahvo_interrupt_update(s);
562 case TAHVO_REG_CHAPWMR:
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);
584 case TAHVO_REG_TESTR1:
585 case TAHVO_REG_TESTR2:
591 hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
595 static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
597 CBusTahvo *s = (CBusTahvo *) opaque;
600 *val = tahvo_read(s, reg);
602 tahvo_write(s, reg, *val);
605 void *tahvo_init(qemu_irq irq, int betty)
607 CBusTahvo *s = (CBusTahvo *) qemu_mallocz(sizeof(*s));
612 s->is_betty = !!betty;
615 s->cbus.io = tahvo_io;