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
7 * Written by Andrzej Zaborowski <andrew@openedhand.com>
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, see <http://www.gnu.org/licenses/>.
23 #include "qemu-common.h"
32 void (*io
)(void *opaque
, int rw
, int reg
, uint16_t *val
);
58 static void cbus_io(CBusPriv
*s
)
60 if (s
->slave
[s
->addr
])
61 s
->slave
[s
->addr
]->io(s
->slave
[s
->addr
]->opaque
,
62 s
->rw
, s
->reg
, &s
->val
);
64 hw_error("%s: bad slave address %i\n", __FUNCTION__
, s
->addr
);
67 static void cbus_cycle(CBusPriv
*s
)
71 s
->addr
= (s
->val
>> 6) & 7;
72 s
->rw
= (s
->val
>> 5) & 1;
73 s
->reg
= (s
->val
>> 0) & 0x1f;
75 s
->cycle
= cbus_value
;
88 s
->cycle
= cbus_address
;
96 static void cbus_clk(void *opaque
, int line
, int level
)
98 CBusPriv
*s
= (CBusPriv
*) opaque
;
100 if (!s
->sel
&& level
&& !s
->clk
) {
102 s
->val
|= s
->dat
<< (s
->bit
--);
104 qemu_set_irq(s
->dat_out
, (s
->val
>> (s
->bit
--)) & 1);
113 static void cbus_dat(void *opaque
, int line
, int level
)
115 CBusPriv
*s
= (CBusPriv
*) opaque
;
120 static void cbus_sel(void *opaque
, int line
, int level
)
122 CBusPriv
*s
= (CBusPriv
*) opaque
;
133 CBus
*cbus_init(qemu_irq dat
)
135 CBusPriv
*s
= (CBusPriv
*) qemu_mallocz(sizeof(*s
));
138 s
->cbus
.clk
= qemu_allocate_irqs(cbus_clk
, s
, 1)[0];
139 s
->cbus
.dat
= qemu_allocate_irqs(cbus_dat
, s
, 1)[0];
140 s
->cbus
.sel
= qemu_allocate_irqs(cbus_sel
, s
, 1)[0];
149 void cbus_attach(CBus
*bus
, void *slave_opaque
)
151 CBusSlave
*slave
= (CBusSlave
*) slave_opaque
;
152 CBusPriv
*s
= (CBusPriv
*) bus
;
154 s
->slave
[slave
->addr
] = slave
;
176 static void retu_interrupt_update(CBusRetu
*s
)
178 qemu_set_irq(s
->irq
, s
->irqst
& ~s
->irqen
);
181 #define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
182 #define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
183 #define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
184 #define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
185 #define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
186 #define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
187 #define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
188 #define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
189 #define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
190 #define RETU_REG_AFCR 0x0a /* (RW) AFC register */
191 #define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
192 #define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
193 #define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
194 #define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
195 #define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
196 #define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
197 #define RETU_REG_TXCR 0x11 /* (RW) TxC register */
198 #define RETU_REG_STATUS 0x16 /* (RO) Status register */
199 #define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
200 #define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
201 #define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
202 #define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
203 #define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
204 #define RETU_REG_SGR1 0x1c /* (RW) */
205 #define RETU_REG_SCR1 0x1d /* (RW) */
206 #define RETU_REG_SGR2 0x1e /* (RW) */
207 #define RETU_REG_SCR2 0x1f /* (RW) */
209 /* Retu Interrupt sources */
211 retu_int_pwr
= 0, /* Power button */
212 retu_int_char
= 1, /* Charger */
213 retu_int_rtcs
= 2, /* Seconds */
214 retu_int_rtcm
= 3, /* Minutes */
215 retu_int_rtcd
= 4, /* Days */
216 retu_int_rtca
= 5, /* Alarm */
217 retu_int_hook
= 6, /* Hook */
218 retu_int_head
= 7, /* Headset */
219 retu_int_adcs
= 8, /* ADC sample */
222 /* Retu ADC channel wiring */
224 retu_adc_bsi
= 1, /* BSI */
225 retu_adc_batt_temp
= 2, /* Battery temperature */
226 retu_adc_chg_volt
= 3, /* Charger voltage */
227 retu_adc_head_det
= 4, /* Headset detection */
228 retu_adc_hook_det
= 5, /* Hook detection */
229 retu_adc_rf_gp
= 6, /* RF GP */
230 retu_adc_tx_det
= 7, /* Wideband Tx detection */
231 retu_adc_batt_volt
= 8, /* Battery voltage */
232 retu_adc_sens
= 10, /* Light sensor */
233 retu_adc_sens_temp
= 11, /* Light sensor temperature */
234 retu_adc_bbatt_volt
= 12, /* Backup battery voltage */
235 retu_adc_self_temp
= 13, /* RETU temperature */
238 static inline uint16_t retu_read(CBusRetu
*s
, int reg
)
241 printf("RETU read at %02x\n", reg
);
246 return 0x0215 | (s
->is_vilma
<< 7);
248 case RETU_REG_IDR
: /* TODO: Or is this ffs(s->irqst)? */
254 case RETU_REG_RTCDSR
:
255 case RETU_REG_RTCHMR
:
256 case RETU_REG_RTCHMAR
:
260 case RETU_REG_RTCCALR
:
264 return (s
->channel
<< 10) | s
->result
[s
->channel
];
265 case RETU_REG_ADCSCR
:
269 case RETU_REG_ANTIFR
:
270 case RETU_REG_CALIBR
:
279 case RETU_REG_RCTRL_CLR
:
280 case RETU_REG_RCTRL_SET
:
285 case RETU_REG_STATUS
:
288 case RETU_REG_WATCHDOG
:
289 case RETU_REG_AUDTXR
:
290 case RETU_REG_AUDPAR
:
291 case RETU_REG_AUDRXR1
:
292 case RETU_REG_AUDRXR2
:
301 hw_error("%s: bad register %02x\n", __FUNCTION__
, reg
);
305 static inline void retu_write(CBusRetu
*s
, int reg
, uint16_t val
)
308 printf("RETU write of %04x at %02x\n", val
, reg
);
314 retu_interrupt_update(s
);
319 retu_interrupt_update(s
);
322 case RETU_REG_RTCDSR
:
323 case RETU_REG_RTCHMAR
:
327 case RETU_REG_RTCCALR
:
332 s
->channel
= (val
>> 10) & 0xf;
333 s
->irqst
|= 1 << retu_int_adcs
;
334 retu_interrupt_update(s
);
336 case RETU_REG_ADCSCR
:
341 case RETU_REG_ANTIFR
:
342 case RETU_REG_CALIBR
:
351 case RETU_REG_RCTRL_CLR
:
352 case RETU_REG_RCTRL_SET
:
356 case RETU_REG_WATCHDOG
:
357 if (val
== 0 && (s
->cc
[0] & 2))
358 qemu_system_shutdown_request();
362 case RETU_REG_AUDTXR
:
363 case RETU_REG_AUDPAR
:
364 case RETU_REG_AUDRXR1
:
365 case RETU_REG_AUDRXR2
:
374 hw_error("%s: bad register %02x\n", __FUNCTION__
, reg
);
378 static void retu_io(void *opaque
, int rw
, int reg
, uint16_t *val
)
380 CBusRetu
*s
= (CBusRetu
*) opaque
;
383 *val
= retu_read(s
, reg
);
385 retu_write(s
, reg
, *val
);
388 void *retu_init(qemu_irq irq
, int vilma
)
390 CBusRetu
*s
= (CBusRetu
*) qemu_mallocz(sizeof(*s
));
396 s
->is_vilma
= !!vilma
;
398 s
->result
[retu_adc_bsi
] = 0x3c2;
399 s
->result
[retu_adc_batt_temp
] = 0x0fc;
400 s
->result
[retu_adc_chg_volt
] = 0x165;
401 s
->result
[retu_adc_head_det
] = 123;
402 s
->result
[retu_adc_hook_det
] = 1023;
403 s
->result
[retu_adc_rf_gp
] = 0x11;
404 s
->result
[retu_adc_tx_det
] = 0x11;
405 s
->result
[retu_adc_batt_volt
] = 0x250;
406 s
->result
[retu_adc_sens
] = 2;
407 s
->result
[retu_adc_sens_temp
] = 0x11;
408 s
->result
[retu_adc_bbatt_volt
] = 0x3d0;
409 s
->result
[retu_adc_self_temp
] = 0x330;
412 s
->cbus
.io
= retu_io
;
418 void retu_key_event(void *retu
, int state
)
420 CBusSlave
*slave
= (CBusSlave
*) retu
;
421 CBusRetu
*s
= (CBusRetu
*) slave
->opaque
;
423 s
->irqst
|= 1 << retu_int_pwr
;
424 retu_interrupt_update(s
);
427 s
->status
&= ~(1 << 5);
433 static void retu_head_event(void *retu
, int state
)
435 CBusSlave
*slave
= (CBusSlave
*) retu
;
436 CBusRetu
*s
= (CBusRetu
*) slave
->opaque
;
438 if ((s
->cc
[0] & 0x500) == 0x500) { /* TODO: Which bits? */
439 /* TODO: reissue the interrupt every 100ms or so. */
440 s
->irqst
|= 1 << retu_int_head
;
441 retu_interrupt_update(s
);
445 s
->result
[retu_adc_head_det
] = 50;
447 s
->result
[retu_adc_head_det
] = 123;
450 static void retu_hook_event(void *retu
, int state
)
452 CBusSlave
*slave
= (CBusSlave
*) retu
;
453 CBusRetu
*s
= (CBusRetu
*) slave
->opaque
;
455 if ((s
->cc
[0] & 0x500) == 0x500) {
456 /* TODO: reissue the interrupt every 100ms or so. */
457 s
->irqst
|= 1 << retu_int_hook
;
458 retu_interrupt_update(s
);
462 s
->result
[retu_adc_hook_det
] = 50;
464 s
->result
[retu_adc_hook_det
] = 123;
482 static void tahvo_interrupt_update(CBusTahvo
*s
)
484 qemu_set_irq(s
->irq
, s
->irqst
& ~s
->irqen
);
487 #define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
488 #define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
489 #define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
490 #define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
491 #define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
492 #define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
493 #define TAHVO_REG_USBR 0x06 /* (RW) USB control */
494 #define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
495 #define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
496 #define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
497 #define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
498 #define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
499 #define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
500 #define TAHVO_REG_FRR 0x0d /* (RO) FR */
502 static inline uint16_t tahvo_read(CBusTahvo
*s
, int reg
)
505 printf("TAHVO read at %02x\n", reg
);
509 case TAHVO_REG_ASICR
:
510 return 0x0021 | (s
->is_betty
? 0x0b00 : 0x0300); /* 22 in N810 */
513 case TAHVO_REG_IDSR
: /* XXX: what does this do? */
519 case TAHVO_REG_CHAPWMR
:
522 case TAHVO_REG_LEDPWMR
:
533 case TAHVO_REG_TESTR1
:
534 case TAHVO_REG_TESTR2
:
540 hw_error("%s: bad register %02x\n", __FUNCTION__
, reg
);
544 static inline void tahvo_write(CBusTahvo
*s
, int reg
, uint16_t val
)
547 printf("TAHVO write of %04x at %02x\n", val
, reg
);
553 tahvo_interrupt_update(s
);
558 tahvo_interrupt_update(s
);
561 case TAHVO_REG_CHAPWMR
:
565 case TAHVO_REG_LEDPWMR
:
566 if (s
->backlight
!= (val
& 0x7f)) {
567 s
->backlight
= val
& 0x7f;
568 printf("%s: LCD backlight now at %i / 127\n",
569 __FUNCTION__
, s
->backlight
);
583 case TAHVO_REG_TESTR1
:
584 case TAHVO_REG_TESTR2
:
590 hw_error("%s: bad register %02x\n", __FUNCTION__
, reg
);
594 static void tahvo_io(void *opaque
, int rw
, int reg
, uint16_t *val
)
596 CBusTahvo
*s
= (CBusTahvo
*) opaque
;
599 *val
= tahvo_read(s
, reg
);
601 tahvo_write(s
, reg
, *val
);
604 void *tahvo_init(qemu_irq irq
, int betty
)
606 CBusTahvo
*s
= (CBusTahvo
*) qemu_mallocz(sizeof(*s
));
611 s
->is_betty
= !!betty
;
614 s
->cbus
.io
= tahvo_io
;