cbus.c (15156B)
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 "hw/hw.h" 25#include "hw/irq.h" 26#include "hw/misc/cbus.h" 27#include "sysemu/runstate.h" 28 29//#define DEBUG 30 31typedef struct { 32 void *opaque; 33 void (*io)(void *opaque, int rw, int reg, uint16_t *val); 34 int addr; 35} CBusSlave; 36 37typedef 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 59static 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", __func__, s->addr); 66} 67 68static 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 97static 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 114static void cbus_dat(void *opaque, int line, int level) 115{ 116 CBusPriv *s = (CBusPriv *) opaque; 117 118 s->dat = level; 119} 120 121static 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 134CBus *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 150void 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 */ 159typedef 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 177static 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 */ 211enum { 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 */ 224enum { 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 239static 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", __func__, reg); 303 } 304} 305 306static 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(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 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", __func__, reg); 376 } 377} 378 379static 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 389void *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 419void 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 434static 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 451static 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 */ 470typedef 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 483static 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 503static 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", __func__, reg); 542 } 543} 544 545static 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 __func__, 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", __func__, reg); 592 } 593} 594 595static 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 605void *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}