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
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25
#include "qemu-common.h"
52
struct cbus_slave_s *slave[8];
57
void (*io)(void *opaque, int rw, int reg, uint16_t *val);
61
static void cbus_io(struct cbus_priv_s *s)
63
if (s->slave[s->addr])
64
s->slave[s->addr]->io(s->slave[s->addr]->opaque,
65
s->rw, s->reg, &s->val);
67
cpu_abort(cpu_single_env, "%s: bad slave address %i\n",
68
__FUNCTION__, s->addr);
71
static void cbus_cycle(struct cbus_priv_s *s)
75
s->addr = (s->val >> 6) & 7;
76
s->rw = (s->val >> 5) & 1;
77
s->reg = (s->val >> 0) & 0x1f;
79
s->cycle = cbus_value;
92
s->cycle = cbus_address;
100
static void cbus_clk(void *opaque, int line, int level)
102
struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
104
if (!s->sel && level && !s->clk) {
106
s->val |= s->dat << (s->bit --);
108
qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
117
static void cbus_dat(void *opaque, int line, int level)
119
struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
124
static void cbus_sel(void *opaque, int line, int level)
126
struct cbus_priv_s *s = (struct cbus_priv_s *) opaque;
137
struct cbus_s *cbus_init(qemu_irq dat)
139
struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s));
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];
153
void cbus_attach(struct cbus_s *bus, void *slave_opaque)
155
struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque;
156
struct cbus_priv_s *s = (struct cbus_priv_s *) bus;
158
s->slave[slave->addr] = slave;
177
struct cbus_slave_s cbus;
180
static void retu_interrupt_update(struct cbus_retu_s *s)
182
qemu_set_irq(s->irq, s->irqst & ~s->irqen);
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) */
213
/* Retu Interrupt sources */
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 */
226
/* Retu ADC channel wiring */
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 */
242
static inline uint16_t retu_read(struct cbus_retu_s *s, int reg)
245
printf("RETU read at %02x\n", reg);
250
return 0x0215 | (s->is_vilma << 7);
252
case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
258
case RETU_REG_RTCDSR:
259
case RETU_REG_RTCHMR:
260
case RETU_REG_RTCHMAR:
264
case RETU_REG_RTCCALR:
268
return (s->channel << 10) | s->result[s->channel];
269
case RETU_REG_ADCSCR:
273
case RETU_REG_ANTIFR:
274
case RETU_REG_CALIBR:
283
case RETU_REG_RCTRL_CLR:
284
case RETU_REG_RCTRL_SET:
289
case RETU_REG_STATUS:
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:
305
cpu_abort(cpu_single_env, "%s: bad register %02x\n",
310
static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val)
313
printf("RETU write of %04x at %02x\n", val, reg);
319
retu_interrupt_update(s);
324
retu_interrupt_update(s);
327
case RETU_REG_RTCDSR:
328
case RETU_REG_RTCHMAR:
332
case RETU_REG_RTCCALR:
337
s->channel = (val >> 10) & 0xf;
338
s->irqst |= 1 << retu_int_adcs;
339
retu_interrupt_update(s);
341
case RETU_REG_ADCSCR:
346
case RETU_REG_ANTIFR:
347
case RETU_REG_CALIBR:
356
case RETU_REG_RCTRL_CLR:
357
case RETU_REG_RCTRL_SET:
361
case RETU_REG_WATCHDOG:
362
if (val == 0 && (s->cc[0] & 2))
363
qemu_system_shutdown_request();
367
case RETU_REG_AUDTXR:
368
case RETU_REG_AUDPAR:
369
case RETU_REG_AUDRXR1:
370
case RETU_REG_AUDRXR2:
379
cpu_abort(cpu_single_env, "%s: bad register %02x\n",
384
static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
386
struct cbus_retu_s *s = (struct cbus_retu_s *) opaque;
389
*val = retu_read(s, reg);
391
retu_write(s, reg, *val);
394
void *retu_init(qemu_irq irq, int vilma)
396
struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s));
402
s->is_vilma = !!vilma;
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;
418
s->cbus.io = retu_io;
424
void retu_key_event(void *retu, int state)
426
struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
427
struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
429
s->irqst |= 1 << retu_int_pwr;
430
retu_interrupt_update(s);
433
s->status &= ~(1 << 5);
438
void retu_head_event(void *retu, int state)
440
struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
441
struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
443
if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
444
/* TODO: reissue the interrupt every 100ms or so. */
445
s->irqst |= 1 << retu_int_head;
446
retu_interrupt_update(s);
450
s->result[retu_adc_head_det] = 50;
452
s->result[retu_adc_head_det] = 123;
455
void retu_hook_event(void *retu, int state)
457
struct cbus_slave_s *slave = (struct cbus_slave_s *) retu;
458
struct cbus_retu_s *s = (struct cbus_retu_s *) slave->opaque;
460
if ((s->cc[0] & 0x500) == 0x500) {
461
/* TODO: reissue the interrupt every 100ms or so. */
462
s->irqst |= 1 << retu_int_hook;
463
retu_interrupt_update(s);
467
s->result[retu_adc_hook_det] = 50;
469
s->result[retu_adc_hook_det] = 123;
473
struct cbus_tahvo_s {
483
struct cbus_slave_s cbus;
486
static void tahvo_interrupt_update(struct cbus_tahvo_s *s)
488
qemu_set_irq(s->irq, s->irqst & ~s->irqen);
491
#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
492
#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
493
#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
494
#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
495
#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
496
#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
497
#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
498
#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
499
#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
500
#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
501
#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
502
#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
503
#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
504
#define TAHVO_REG_FRR 0x0d /* (RO) FR */
506
static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg)
509
printf("TAHVO read at %02x\n", reg);
513
case TAHVO_REG_ASICR:
514
return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
517
case TAHVO_REG_IDSR: /* XXX: what does this do? */
523
case TAHVO_REG_CHAPWMR:
526
case TAHVO_REG_LEDPWMR:
537
case TAHVO_REG_TESTR1:
538
case TAHVO_REG_TESTR2:
544
cpu_abort(cpu_single_env, "%s: bad register %02x\n",
549
static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val)
552
printf("TAHVO write of %04x at %02x\n", val, reg);
558
tahvo_interrupt_update(s);
563
tahvo_interrupt_update(s);
566
case TAHVO_REG_CHAPWMR:
570
case TAHVO_REG_LEDPWMR:
571
if (s->backlight != (val & 0x7f)) {
572
s->backlight = val & 0x7f;
573
printf("%s: LCD backlight now at %i / 127\n",
574
__FUNCTION__, s->backlight);
588
case TAHVO_REG_TESTR1:
589
case TAHVO_REG_TESTR2:
595
cpu_abort(cpu_single_env, "%s: bad register %02x\n",
600
static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
602
struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque;
605
*val = tahvo_read(s, reg);
607
tahvo_write(s, reg, *val);
610
void *tahvo_init(qemu_irq irq, int betty)
612
struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s));
617
s->is_betty = !!betty;
620
s->cbus.io = tahvo_io;