qemu/hw/misc/cbus.c
<<
>>
Prefs
   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/devices.h"
  27#include "sysemu/sysemu.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}
 620