qemu/hw/lm832x.c
<<
>>
Prefs
   1/*
   2 * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
   3 *
   4 * Copyright (C) 2008 Nokia Corporation
   5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 or
  10 * (at your option) version 3 of the License.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along
  18 * with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "hw.h"
  22#include "i2c.h"
  23#include "qemu/timer.h"
  24#include "ui/console.h"
  25
  26typedef struct {
  27    I2CSlave i2c;
  28    uint8_t i2c_dir;
  29    uint8_t i2c_cycle;
  30    uint8_t reg;
  31
  32    qemu_irq nirq;
  33    uint16_t model;
  34
  35    struct {
  36        qemu_irq out[2];
  37        int in[2][2];
  38    } mux;
  39
  40    uint8_t config;
  41    uint8_t status;
  42    uint8_t acttime;
  43    uint8_t error;
  44    uint8_t clock;
  45
  46    struct {
  47        uint16_t pull;
  48        uint16_t mask;
  49        uint16_t dir;
  50        uint16_t level;
  51        qemu_irq out[16];
  52    } gpio;
  53
  54    struct {
  55        uint8_t dbnctime;
  56        uint8_t size;
  57        uint8_t start;
  58        uint8_t len;
  59        uint8_t fifo[16];
  60    } kbd;
  61
  62    struct {
  63        uint16_t file[256];
  64        uint8_t faddr;
  65        uint8_t addr[3];
  66        QEMUTimer *tm[3];
  67    } pwm;
  68} LM823KbdState;
  69
  70#define INT_KEYPAD              (1 << 0)
  71#define INT_ERROR               (1 << 3)
  72#define INT_NOINIT              (1 << 4)
  73#define INT_PWMEND(n)           (1 << (5 + n))
  74
  75#define ERR_BADPAR              (1 << 0)
  76#define ERR_CMDUNK              (1 << 1)
  77#define ERR_KEYOVR              (1 << 2)
  78#define ERR_FIFOOVR             (1 << 6)
  79
  80static void lm_kbd_irq_update(LM823KbdState *s)
  81{
  82    qemu_set_irq(s->nirq, !s->status);
  83}
  84
  85static void lm_kbd_gpio_update(LM823KbdState *s)
  86{
  87}
  88
  89static void lm_kbd_reset(LM823KbdState *s)
  90{
  91    s->config = 0x80;
  92    s->status = INT_NOINIT;
  93    s->acttime = 125;
  94    s->kbd.dbnctime = 3;
  95    s->kbd.size = 0x33;
  96    s->clock = 0x08;
  97
  98    lm_kbd_irq_update(s);
  99    lm_kbd_gpio_update(s);
 100}
 101
 102static void lm_kbd_error(LM823KbdState *s, int err)
 103{
 104    s->error |= err;
 105    s->status |= INT_ERROR;
 106    lm_kbd_irq_update(s);
 107}
 108
 109static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
 110{
 111}
 112
 113static void lm_kbd_pwm_start(LM823KbdState *s, int line)
 114{
 115    lm_kbd_pwm_tick(s, line);
 116}
 117
 118static void lm_kbd_pwm0_tick(void *opaque)
 119{
 120    lm_kbd_pwm_tick(opaque, 0);
 121}
 122static void lm_kbd_pwm1_tick(void *opaque)
 123{
 124    lm_kbd_pwm_tick(opaque, 1);
 125}
 126static void lm_kbd_pwm2_tick(void *opaque)
 127{
 128    lm_kbd_pwm_tick(opaque, 2);
 129}
 130
 131enum {
 132    LM832x_CMD_READ_ID          = 0x80, /* Read chip ID. */
 133    LM832x_CMD_WRITE_CFG        = 0x81, /* Set configuration item. */
 134    LM832x_CMD_READ_INT         = 0x82, /* Get interrupt status. */
 135    LM832x_CMD_RESET            = 0x83, /* Reset, same as external one */
 136    LM823x_CMD_WRITE_PULL_DOWN  = 0x84, /* Select GPIO pull-up/down. */
 137    LM832x_CMD_WRITE_PORT_SEL   = 0x85, /* Select GPIO in/out. */
 138    LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */
 139    LM832x_CMD_READ_PORT_SEL    = 0x87, /* Get GPIO in/out. */
 140    LM832x_CMD_READ_PORT_STATE  = 0x88, /* Get GPIO pull-up/down. */
 141    LM832x_CMD_READ_FIFO        = 0x89, /* Read byte from FIFO. */
 142    LM832x_CMD_RPT_READ_FIFO    = 0x8a, /* Read FIFO (no increment). */
 143    LM832x_CMD_SET_ACTIVE       = 0x8b, /* Set active time. */
 144    LM832x_CMD_READ_ERROR       = 0x8c, /* Get error status. */
 145    LM832x_CMD_READ_ROTATOR     = 0x8e, /* Read rotator status. */
 146    LM832x_CMD_SET_DEBOUNCE     = 0x8f, /* Set debouncing time. */
 147    LM832x_CMD_SET_KEY_SIZE     = 0x90, /* Set keypad size. */
 148    LM832x_CMD_READ_KEY_SIZE    = 0x91, /* Get keypad size. */
 149    LM832x_CMD_READ_CFG         = 0x92, /* Get configuration item. */
 150    LM832x_CMD_WRITE_CLOCK      = 0x93, /* Set clock config. */
 151    LM832x_CMD_READ_CLOCK       = 0x94, /* Get clock config. */
 152    LM832x_CMD_PWM_WRITE        = 0x95, /* Write PWM script. */
 153    LM832x_CMD_PWM_START        = 0x96, /* Start PWM engine. */
 154    LM832x_CMD_PWM_STOP         = 0x97, /* Stop PWM engine. */
 155    LM832x_GENERAL_ERROR        = 0xff, /* There was one error.
 156                                           Previously was represented by -1
 157                                           This is not a command */
 158};
 159
 160#define LM832x_MAX_KPX          8
 161#define LM832x_MAX_KPY          12
 162
 163static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
 164{
 165    int ret;
 166
 167    switch (reg) {
 168    case LM832x_CMD_READ_ID:
 169        ret = 0x0400;
 170        break;
 171
 172    case LM832x_CMD_READ_INT:
 173        ret = s->status;
 174        if (!(s->status & INT_NOINIT)) {
 175            s->status = 0;
 176            lm_kbd_irq_update(s);
 177        }
 178        break;
 179
 180    case LM832x_CMD_READ_PORT_SEL:
 181        ret = s->gpio.dir;
 182        break;
 183    case LM832x_CMD_READ_PORT_STATE:
 184        ret = s->gpio.mask;
 185        break;
 186
 187    case LM832x_CMD_READ_FIFO:
 188        if (s->kbd.len <= 1)
 189            return 0x00;
 190
 191        /* Example response from the two commands after a INT_KEYPAD
 192         * interrupt caused by the key 0x3c being pressed:
 193         * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
 194         *     READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
 195         * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
 196         *
 197         * 55 is the code of the key release event serviced in the previous
 198         * interrupt handling.
 199         *
 200         * TODO: find out whether the FIFO is advanced a single character
 201         * before reading every byte or the whole size of the FIFO at the
 202         * last LM832x_CMD_READ_FIFO.  This affects LM832x_CMD_RPT_READ_FIFO
 203         * output in cases where there are more than one event in the FIFO.
 204         * Assume 0xbc and 0x3c events are in the FIFO:
 205         * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
 206         *     READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
 207         * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
 208         */
 209        s->kbd.start ++;
 210        s->kbd.start &= sizeof(s->kbd.fifo) - 1;
 211        s->kbd.len --;
 212
 213        return s->kbd.fifo[s->kbd.start];
 214    case LM832x_CMD_RPT_READ_FIFO:
 215        if (byte >= s->kbd.len)
 216            return 0x00;
 217
 218        return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
 219
 220    case LM832x_CMD_READ_ERROR:
 221        return s->error;
 222
 223    case LM832x_CMD_READ_ROTATOR:
 224        return 0;
 225
 226    case LM832x_CMD_READ_KEY_SIZE:
 227        return s->kbd.size;
 228
 229    case LM832x_CMD_READ_CFG:
 230        return s->config & 0xf;
 231
 232    case LM832x_CMD_READ_CLOCK:
 233        return (s->clock & 0xfc) | 2;
 234
 235    default:
 236        lm_kbd_error(s, ERR_CMDUNK);
 237        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
 238        return 0x00;
 239    }
 240
 241    return ret >> (byte << 3);
 242}
 243
 244static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
 245{
 246    switch (reg) {
 247    case LM832x_CMD_WRITE_CFG:
 248        s->config = value;
 249        /* This must be done whenever s->mux.in is updated (never).  */
 250        if ((s->config >> 1) & 1)                       /* MUX1EN */
 251            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
 252        if ((s->config >> 3) & 1)                       /* MUX2EN */
 253            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
 254        /* TODO: check that this is issued only following the chip reset
 255         * and not in the middle of operation and that it is followed by
 256         * the GPIO ports re-resablishing through WRITE_PORT_SEL and
 257         * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
 258         * warnings.  */
 259        s->status = 0;
 260        lm_kbd_irq_update(s);
 261        s->kbd.len = 0;
 262        s->kbd.start = 0;
 263        s->reg = LM832x_GENERAL_ERROR;
 264        break;
 265
 266    case LM832x_CMD_RESET:
 267        if (value == 0xaa)
 268            lm_kbd_reset(s);
 269        else
 270            lm_kbd_error(s, ERR_BADPAR);
 271        s->reg = LM832x_GENERAL_ERROR;
 272        break;
 273
 274    case LM823x_CMD_WRITE_PULL_DOWN:
 275        if (!byte)
 276            s->gpio.pull = value;
 277        else {
 278            s->gpio.pull |= value << 8;
 279            lm_kbd_gpio_update(s);
 280            s->reg = LM832x_GENERAL_ERROR;
 281        }
 282        break;
 283    case LM832x_CMD_WRITE_PORT_SEL:
 284        if (!byte)
 285            s->gpio.dir = value;
 286        else {
 287            s->gpio.dir |= value << 8;
 288            lm_kbd_gpio_update(s);
 289            s->reg = LM832x_GENERAL_ERROR;
 290        }
 291        break;
 292    case LM832x_CMD_WRITE_PORT_STATE:
 293        if (!byte)
 294            s->gpio.mask = value;
 295        else {
 296            s->gpio.mask |= value << 8;
 297            lm_kbd_gpio_update(s);
 298            s->reg = LM832x_GENERAL_ERROR;
 299        }
 300        break;
 301
 302    case LM832x_CMD_SET_ACTIVE:
 303        s->acttime = value;
 304        s->reg = LM832x_GENERAL_ERROR;
 305        break;
 306
 307    case LM832x_CMD_SET_DEBOUNCE:
 308        s->kbd.dbnctime = value;
 309        s->reg = LM832x_GENERAL_ERROR;
 310        if (!value)
 311            lm_kbd_error(s, ERR_BADPAR);
 312        break;
 313
 314    case LM832x_CMD_SET_KEY_SIZE:
 315        s->kbd.size = value;
 316        s->reg = LM832x_GENERAL_ERROR;
 317        if (
 318                        (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
 319                        (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
 320            lm_kbd_error(s, ERR_BADPAR);
 321        break;
 322
 323    case LM832x_CMD_WRITE_CLOCK:
 324        s->clock = value;
 325        s->reg = LM832x_GENERAL_ERROR;
 326        if ((value & 3) && (value & 3) != 3) {
 327            lm_kbd_error(s, ERR_BADPAR);
 328            fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
 329                            __FUNCTION__);
 330        }
 331        /* TODO: Validate that the command is only issued once */
 332        break;
 333
 334    case LM832x_CMD_PWM_WRITE:
 335        if (byte == 0) {
 336            if (!(value & 3) || (value >> 2) > 59) {
 337                lm_kbd_error(s, ERR_BADPAR);
 338                s->reg = LM832x_GENERAL_ERROR;
 339                break;
 340            }
 341
 342            s->pwm.faddr = value;
 343            s->pwm.file[s->pwm.faddr] = 0;
 344        } else if (byte == 1) {
 345            s->pwm.file[s->pwm.faddr] |= value << 8;
 346        } else if (byte == 2) {
 347            s->pwm.file[s->pwm.faddr] |= value << 0;
 348            s->reg = LM832x_GENERAL_ERROR;
 349        }
 350        break;
 351    case LM832x_CMD_PWM_START:
 352        s->reg = LM832x_GENERAL_ERROR;
 353        if (!(value & 3) || (value >> 2) > 59) {
 354            lm_kbd_error(s, ERR_BADPAR);
 355            break;
 356        }
 357
 358        s->pwm.addr[(value & 3) - 1] = value >> 2;
 359        lm_kbd_pwm_start(s, (value & 3) - 1);
 360        break;
 361    case LM832x_CMD_PWM_STOP:
 362        s->reg = LM832x_GENERAL_ERROR;
 363        if (!(value & 3)) {
 364            lm_kbd_error(s, ERR_BADPAR);
 365            break;
 366        }
 367
 368        qemu_del_timer(s->pwm.tm[(value & 3) - 1]);
 369        break;
 370
 371    case LM832x_GENERAL_ERROR:
 372        lm_kbd_error(s, ERR_BADPAR);
 373        break;
 374    default:
 375        lm_kbd_error(s, ERR_CMDUNK);
 376        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
 377        break;
 378    }
 379}
 380
 381static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
 382{
 383    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
 384
 385    switch (event) {
 386    case I2C_START_RECV:
 387    case I2C_START_SEND:
 388        s->i2c_cycle = 0;
 389        s->i2c_dir = (event == I2C_START_SEND);
 390        break;
 391
 392    default:
 393        break;
 394    }
 395}
 396
 397static int lm_i2c_rx(I2CSlave *i2c)
 398{
 399    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
 400
 401    return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
 402}
 403
 404static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
 405{
 406    LM823KbdState *s = (LM823KbdState *) i2c;
 407
 408    if (!s->i2c_cycle)
 409        s->reg = data;
 410    else
 411        lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
 412    s->i2c_cycle ++;
 413
 414    return 0;
 415}
 416
 417static int lm_kbd_post_load(void *opaque, int version_id)
 418{
 419    LM823KbdState *s = opaque;
 420
 421    lm_kbd_irq_update(s);
 422    lm_kbd_gpio_update(s);
 423
 424    return 0;
 425}
 426
 427static const VMStateDescription vmstate_lm_kbd = {
 428    .name = "LM8323",
 429    .version_id = 0,
 430    .minimum_version_id = 0,
 431    .minimum_version_id_old = 0,
 432    .post_load = lm_kbd_post_load,
 433    .fields      = (VMStateField []) {
 434        VMSTATE_I2C_SLAVE(i2c, LM823KbdState),
 435        VMSTATE_UINT8(i2c_dir, LM823KbdState),
 436        VMSTATE_UINT8(i2c_cycle, LM823KbdState),
 437        VMSTATE_UINT8(reg, LM823KbdState),
 438        VMSTATE_UINT8(config, LM823KbdState),
 439        VMSTATE_UINT8(status, LM823KbdState),
 440        VMSTATE_UINT8(acttime, LM823KbdState),
 441        VMSTATE_UINT8(error, LM823KbdState),
 442        VMSTATE_UINT8(clock, LM823KbdState),
 443        VMSTATE_UINT16(gpio.pull, LM823KbdState),
 444        VMSTATE_UINT16(gpio.mask, LM823KbdState),
 445        VMSTATE_UINT16(gpio.dir, LM823KbdState),
 446        VMSTATE_UINT16(gpio.level, LM823KbdState),
 447        VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
 448        VMSTATE_UINT8(kbd.size, LM823KbdState),
 449        VMSTATE_UINT8(kbd.start, LM823KbdState),
 450        VMSTATE_UINT8(kbd.len, LM823KbdState),
 451        VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
 452        VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
 453        VMSTATE_UINT8(pwm.faddr, LM823KbdState),
 454        VMSTATE_BUFFER(pwm.addr, LM823KbdState),
 455        VMSTATE_TIMER_ARRAY(pwm.tm, LM823KbdState, 3),
 456        VMSTATE_END_OF_LIST()
 457    }
 458};
 459
 460
 461static int lm8323_init(I2CSlave *i2c)
 462{
 463    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
 464
 465    s->model = 0x8323;
 466    s->pwm.tm[0] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm0_tick, s);
 467    s->pwm.tm[1] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm1_tick, s);
 468    s->pwm.tm[2] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm2_tick, s);
 469    qdev_init_gpio_out(&i2c->qdev, &s->nirq, 1);
 470
 471    lm_kbd_reset(s);
 472
 473    qemu_register_reset((void *) lm_kbd_reset, s);
 474    return 0;
 475}
 476
 477void lm832x_key_event(DeviceState *dev, int key, int state)
 478{
 479    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE(dev));
 480
 481    if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
 482        return;
 483
 484    if (s->kbd.len >= sizeof(s->kbd.fifo)) {
 485        lm_kbd_error(s, ERR_FIFOOVR);
 486        return;
 487    }
 488
 489    s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
 490            key | (state << 7);
 491
 492    /* We never set ERR_KEYOVR because we support multiple keys fine.  */
 493    s->status |= INT_KEYPAD;
 494    lm_kbd_irq_update(s);
 495}
 496
 497static void lm8323_class_init(ObjectClass *klass, void *data)
 498{
 499    DeviceClass *dc = DEVICE_CLASS(klass);
 500    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 501
 502    k->init = lm8323_init;
 503    k->event = lm_i2c_event;
 504    k->recv = lm_i2c_rx;
 505    k->send = lm_i2c_tx;
 506    dc->vmsd = &vmstate_lm_kbd;
 507}
 508
 509static const TypeInfo lm8323_info = {
 510    .name          = "lm8323",
 511    .parent        = TYPE_I2C_SLAVE,
 512    .instance_size = sizeof(LM823KbdState),
 513    .class_init    = lm8323_class_init,
 514};
 515
 516static void lm832x_register_types(void)
 517{
 518    type_register_static(&lm8323_info);
 519}
 520
 521type_init(lm832x_register_types)
 522