Commit 1d4e547b552213f91f81aadb3db5efc9ba800ef2

Authored by balrog
1 parent 64a88d5d

Add the LM8323-based keyboard of N810.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4400 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
... ... @@ -52,7 +52,7 @@ OBJS+=block.o
52 52 OBJS+=irq.o
53 53 OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
54 54 OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
55   -OBJS+=tmp105.o
  55 +OBJS+=tmp105.o lm832x.o
56 56 OBJS+=scsi-disk.o cdrom.o
57 57 OBJS+=scsi-generic.o
58 58 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o
... ...
hw/i2c.h
... ... @@ -84,4 +84,8 @@ struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm);
84 84 void tmp105_reset(i2c_slave *i2c);
85 85 void tmp105_set(i2c_slave *i2c, int temp);
86 86  
  87 +/* lm832x.c */
  88 +struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq);
  89 +void lm832x_key_event(struct i2c_slave *i2c, int key, int state);
  90 +
87 91 #endif
... ...
hw/lm832x.c 0 → 100644
  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
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include "hw.h"
  24 +#include "i2c.h"
  25 +#include "qemu-timer.h"
  26 +#include "console.h"
  27 +
  28 +struct lm_kbd_s {
  29 + i2c_slave i2c;
  30 + int i2c_dir;
  31 + int i2c_cycle;
  32 + int reg;
  33 +
  34 + qemu_irq nirq;
  35 + uint16_t model;
  36 +
  37 + struct {
  38 + qemu_irq out[2];
  39 + int in[2][2];
  40 + } mux;
  41 +
  42 + uint8_t config;
  43 + uint8_t status;
  44 + uint8_t acttime;
  45 + uint8_t error;
  46 + uint8_t clock;
  47 +
  48 + struct {
  49 + uint16_t pull;
  50 + uint16_t mask;
  51 + uint16_t dir;
  52 + uint16_t level;
  53 + qemu_irq out[16];
  54 + } gpio;
  55 +
  56 + struct {
  57 + uint8_t dbnctime;
  58 + uint8_t size;
  59 + int start;
  60 + int len;
  61 + uint8_t fifo[16];
  62 + } kbd;
  63 +
  64 + struct {
  65 + uint16_t file[256];
  66 + uint8_t faddr;
  67 + uint8_t addr[3];
  68 + QEMUTimer *tm[3];
  69 + } pwm;
  70 +};
  71 +
  72 +#define INT_KEYPAD (1 << 0)
  73 +#define INT_ERROR (1 << 3)
  74 +#define INT_NOINIT (1 << 4)
  75 +#define INT_PWMEND(n) (1 << (5 + n))
  76 +
  77 +#define ERR_BADPAR (1 << 0)
  78 +#define ERR_CMDUNK (1 << 1)
  79 +#define ERR_KEYOVR (1 << 2)
  80 +#define ERR_FIFOOVR (1 << 6)
  81 +
  82 +static void lm_kbd_irq_update(struct lm_kbd_s *s)
  83 +{
  84 + qemu_set_irq(s->nirq, !s->status);
  85 +}
  86 +
  87 +static void lm_kbd_gpio_update(struct lm_kbd_s *s)
  88 +{
  89 +}
  90 +
  91 +static void lm_kbd_reset(struct lm_kbd_s *s)
  92 +{
  93 + s->config = 0x80;
  94 + s->status = INT_NOINIT;
  95 + s->acttime = 125;
  96 + s->kbd.dbnctime = 3;
  97 + s->kbd.size = 0x33;
  98 + s->clock = 0x08;
  99 +
  100 + lm_kbd_irq_update(s);
  101 + lm_kbd_gpio_update(s);
  102 +}
  103 +
  104 +static void lm_kbd_error(struct lm_kbd_s *s, int err)
  105 +{
  106 + s->error |= err;
  107 + s->status |= INT_ERROR;
  108 + lm_kbd_irq_update(s);
  109 +}
  110 +
  111 +static void lm_kbd_pwm_tick(struct lm_kbd_s *s, int line)
  112 +{
  113 +}
  114 +
  115 +static void lm_kbd_pwm_start(struct lm_kbd_s *s, int line)
  116 +{
  117 + lm_kbd_pwm_tick(s, line);
  118 +}
  119 +
  120 +static void lm_kbd_pwm0_tick(void *opaque)
  121 +{
  122 + lm_kbd_pwm_tick(opaque, 0);
  123 +}
  124 +static void lm_kbd_pwm1_tick(void *opaque)
  125 +{
  126 + lm_kbd_pwm_tick(opaque, 1);
  127 +}
  128 +static void lm_kbd_pwm2_tick(void *opaque)
  129 +{
  130 + lm_kbd_pwm_tick(opaque, 2);
  131 +}
  132 +
  133 +enum {
  134 + LM832x_CMD_READ_ID = 0x80, /* Read chip ID. */
  135 + LM832x_CMD_WRITE_CFG = 0x81, /* Set configuration item. */
  136 + LM832x_CMD_READ_INT = 0x82, /* Get interrupt status. */
  137 + LM832x_CMD_RESET = 0x83, /* Reset, same as external one */
  138 + LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */
  139 + LM832x_CMD_WRITE_PORT_SEL = 0x85, /* Select GPIO in/out. */
  140 + LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */
  141 + LM832x_CMD_READ_PORT_SEL = 0x87, /* Get GPIO in/out. */
  142 + LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */
  143 + LM832x_CMD_READ_FIFO = 0x89, /* Read byte from FIFO. */
  144 + LM832x_CMD_RPT_READ_FIFO = 0x8a, /* Read FIFO (no increment). */
  145 + LM832x_CMD_SET_ACTIVE = 0x8b, /* Set active time. */
  146 + LM832x_CMD_READ_ERROR = 0x8c, /* Get error status. */
  147 + LM832x_CMD_READ_ROTATOR = 0x8e, /* Read rotator status. */
  148 + LM832x_CMD_SET_DEBOUNCE = 0x8f, /* Set debouncing time. */
  149 + LM832x_CMD_SET_KEY_SIZE = 0x90, /* Set keypad size. */
  150 + LM832x_CMD_READ_KEY_SIZE = 0x91, /* Get keypad size. */
  151 + LM832x_CMD_READ_CFG = 0x92, /* Get configuration item. */
  152 + LM832x_CMD_WRITE_CLOCK = 0x93, /* Set clock config. */
  153 + LM832x_CMD_READ_CLOCK = 0x94, /* Get clock config. */
  154 + LM832x_CMD_PWM_WRITE = 0x95, /* Write PWM script. */
  155 + LM832x_CMD_PWM_START = 0x96, /* Start PWM engine. */
  156 + LM832x_CMD_PWM_STOP = 0x97, /* Stop PWM engine. */
  157 +};
  158 +
  159 +#define LM832x_MAX_KPX 8
  160 +#define LM832x_MAX_KPY 12
  161 +
  162 +static uint8_t lm_kbd_read(struct lm_kbd_s *s, int reg, int byte)
  163 +{
  164 + int ret;
  165 +
  166 + switch (reg) {
  167 + case LM832x_CMD_READ_ID:
  168 + ret = 0x0400;
  169 + break;
  170 +
  171 + case LM832x_CMD_READ_INT:
  172 + ret = s->status;
  173 + if (!(s->status & INT_NOINIT)) {
  174 + s->status = 0;
  175 + lm_kbd_irq_update(s);
  176 + }
  177 + break;
  178 +
  179 + case LM832x_CMD_READ_PORT_SEL:
  180 + ret = s->gpio.dir;
  181 + break;
  182 + case LM832x_CMD_READ_PORT_STATE:
  183 + ret = s->gpio.mask;
  184 + break;
  185 +
  186 + case LM832x_CMD_READ_FIFO:
  187 + if (s->kbd.len <= 1)
  188 + return 0x00;
  189 +
  190 + /* Example response from the two commands after a INT_KEYPAD
  191 + * interrupt caused by the key 0x3c being pressed:
  192 + * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
  193 + * READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
  194 + * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
  195 + *
  196 + * 55 is the code of the key release event serviced in the previous
  197 + * interrupt handling.
  198 + *
  199 + * TODO: find out whether the FIFO is advanced a single character
  200 + * before reading every byte or the whole size of the FIFO at the
  201 + * last LM832x_CMD_READ_FIFO. This affects LM832x_CMD_RPT_READ_FIFO
  202 + * output in cases where there are more than one event in the FIFO.
  203 + * Assume 0xbc and 0x3c events are in the FIFO:
  204 + * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
  205 + * READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
  206 + * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
  207 + */
  208 + s->kbd.start ++;
  209 + s->kbd.start &= sizeof(s->kbd.fifo) - 1;
  210 + s->kbd.len --;
  211 +
  212 + return s->kbd.fifo[s->kbd.start];
  213 + case LM832x_CMD_RPT_READ_FIFO:
  214 + if (byte >= s->kbd.len)
  215 + return 0x00;
  216 +
  217 + return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
  218 +
  219 + case LM832x_CMD_READ_ERROR:
  220 + return s->error;
  221 +
  222 + case LM832x_CMD_READ_ROTATOR:
  223 + return 0;
  224 +
  225 + case LM832x_CMD_READ_KEY_SIZE:
  226 + return s->kbd.size;
  227 +
  228 + case LM832x_CMD_READ_CFG:
  229 + return s->config & 0xf;
  230 +
  231 + case LM832x_CMD_READ_CLOCK:
  232 + return (s->clock & 0xfc) | 2;
  233 +
  234 + default:
  235 + lm_kbd_error(s, ERR_CMDUNK);
  236 + fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
  237 + return 0x00;
  238 + }
  239 +
  240 + return ret >> (byte << 3);
  241 +}
  242 +
  243 +static void lm_kbd_write(struct lm_kbd_s *s, int reg, int byte, uint8_t value)
  244 +{
  245 + switch (reg) {
  246 + case LM832x_CMD_WRITE_CFG:
  247 + s->config = value;
  248 + /* This must be done whenever s->mux.in is updated (never). */
  249 + if ((s->config >> 1) & 1) /* MUX1EN */
  250 + qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
  251 + if ((s->config >> 3) & 1) /* MUX2EN */
  252 + qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
  253 + /* TODO: check that this is issued only following the chip reset
  254 + * and not in the middle of operation and that it is followed by
  255 + * the GPIO ports re-resablishing through WRITE_PORT_SEL and
  256 + * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
  257 + * warnings. */
  258 + s->status = 0;
  259 + lm_kbd_irq_update(s);
  260 + s->kbd.len = 0;
  261 + s->kbd.start = 0;
  262 + s->reg = -1;
  263 + break;
  264 +
  265 + case LM832x_CMD_RESET:
  266 + if (value == 0xaa)
  267 + lm_kbd_reset(s);
  268 + else
  269 + lm_kbd_error(s, ERR_BADPAR);
  270 + s->reg = -1;
  271 + break;
  272 +
  273 + case LM823x_CMD_WRITE_PULL_DOWN:
  274 + if (!byte)
  275 + s->gpio.pull = value;
  276 + else {
  277 + s->gpio.pull |= value << 8;
  278 + lm_kbd_gpio_update(s);
  279 + s->reg = -1;
  280 + }
  281 + break;
  282 + case LM832x_CMD_WRITE_PORT_SEL:
  283 + if (!byte)
  284 + s->gpio.dir = value;
  285 + else {
  286 + s->gpio.dir |= value << 8;
  287 + lm_kbd_gpio_update(s);
  288 + s->reg = -1;
  289 + }
  290 + break;
  291 + case LM832x_CMD_WRITE_PORT_STATE:
  292 + if (!byte)
  293 + s->gpio.mask = value;
  294 + else {
  295 + s->gpio.mask |= value << 8;
  296 + lm_kbd_gpio_update(s);
  297 + s->reg = -1;
  298 + }
  299 + break;
  300 +
  301 + case LM832x_CMD_SET_ACTIVE:
  302 + s->acttime = value;
  303 + s->reg = -1;
  304 + break;
  305 +
  306 + case LM832x_CMD_SET_DEBOUNCE:
  307 + s->kbd.dbnctime = value;
  308 + s->reg = -1;
  309 + if (!value)
  310 + lm_kbd_error(s, ERR_BADPAR);
  311 + break;
  312 +
  313 + case LM832x_CMD_SET_KEY_SIZE:
  314 + s->kbd.size = value;
  315 + s->reg = -1;
  316 + if (
  317 + (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
  318 + (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
  319 + lm_kbd_error(s, ERR_BADPAR);
  320 + break;
  321 +
  322 + case LM832x_CMD_WRITE_CLOCK:
  323 + s->clock = value;
  324 + s->reg = -1;
  325 + if ((value & 3) && (value & 3) != 3) {
  326 + lm_kbd_error(s, ERR_BADPAR);
  327 + fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
  328 + __FUNCTION__);
  329 + }
  330 + /* TODO: Validate that the command is only issued once */
  331 + break;
  332 +
  333 + case LM832x_CMD_PWM_WRITE:
  334 + if (byte == 0) {
  335 + if (!(value & 3) || (value >> 2) > 59) {
  336 + lm_kbd_error(s, ERR_BADPAR);
  337 + s->reg = -1;
  338 + break;
  339 + }
  340 +
  341 + s->pwm.faddr = value;
  342 + s->pwm.file[s->pwm.faddr] = 0;
  343 + } else if (byte == 1) {
  344 + s->pwm.file[s->pwm.faddr] |= value << 8;
  345 + } else if (byte == 2) {
  346 + s->pwm.file[s->pwm.faddr] |= value << 0;
  347 + s->reg = -1;
  348 + }
  349 + break;
  350 + case LM832x_CMD_PWM_START:
  351 + s->reg = -1;
  352 + if (!(value & 3) || (value >> 2) > 59) {
  353 + lm_kbd_error(s, ERR_BADPAR);
  354 + break;
  355 + }
  356 +
  357 + s->pwm.addr[(value & 3) - 1] = value >> 2;
  358 + lm_kbd_pwm_start(s, (value & 3) - 1);
  359 + break;
  360 + case LM832x_CMD_PWM_STOP:
  361 + s->reg = -1;
  362 + if (!(value & 3)) {
  363 + lm_kbd_error(s, ERR_BADPAR);
  364 + break;
  365 + }
  366 +
  367 + qemu_del_timer(s->pwm.tm[(value & 3) - 1]);
  368 + break;
  369 +
  370 + case -1:
  371 + lm_kbd_error(s, ERR_BADPAR);
  372 + break;
  373 + default:
  374 + lm_kbd_error(s, ERR_CMDUNK);
  375 + fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
  376 + break;
  377 + }
  378 +}
  379 +
  380 +static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event)
  381 +{
  382 + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c;
  383 +
  384 + switch (event) {
  385 + case I2C_START_RECV:
  386 + case I2C_START_SEND:
  387 + s->i2c_cycle = 0;
  388 + s->i2c_dir = (event == I2C_START_SEND);
  389 + break;
  390 +
  391 + default:
  392 + break;
  393 + }
  394 +}
  395 +
  396 +static int lm_i2c_rx(i2c_slave *i2c)
  397 +{
  398 + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c;
  399 +
  400 + return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
  401 +}
  402 +
  403 +static int lm_i2c_tx(i2c_slave *i2c, uint8_t data)
  404 +{
  405 + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c;
  406 +
  407 + if (!s->i2c_cycle)
  408 + s->reg = data;
  409 + else
  410 + lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
  411 + s->i2c_cycle ++;
  412 +
  413 + return 0;
  414 +}
  415 +
  416 +static void lm_kbd_save(QEMUFile *f, void *opaque)
  417 +{
  418 + struct lm_kbd_s *s = (struct lm_kbd_s *) opaque;
  419 + int i;
  420 +
  421 + i2c_slave_save(f, &s->i2c);
  422 + qemu_put_byte(f, s->i2c_dir);
  423 + qemu_put_byte(f, s->i2c_cycle);
  424 + qemu_put_byte(f, (uint8_t) s->reg);
  425 +
  426 + qemu_put_8s(f, &s->config);
  427 + qemu_put_8s(f, &s->status);
  428 + qemu_put_8s(f, &s->acttime);
  429 + qemu_put_8s(f, &s->error);
  430 + qemu_put_8s(f, &s->clock);
  431 +
  432 + qemu_put_be16s(f, &s->gpio.pull);
  433 + qemu_put_be16s(f, &s->gpio.mask);
  434 + qemu_put_be16s(f, &s->gpio.dir);
  435 + qemu_put_be16s(f, &s->gpio.level);
  436 +
  437 + qemu_put_byte(f, s->kbd.dbnctime);
  438 + qemu_put_byte(f, s->kbd.size);
  439 + qemu_put_byte(f, s->kbd.start);
  440 + qemu_put_byte(f, s->kbd.len);
  441 + qemu_put_buffer(f, s->kbd.fifo, sizeof(s->kbd.fifo));
  442 +
  443 + for (i = 0; i < sizeof(s->pwm.file); i ++)
  444 + qemu_put_be16s(f, &s->pwm.file[i]);
  445 + qemu_put_8s(f, &s->pwm.faddr);
  446 + qemu_put_buffer(f, s->pwm.addr, sizeof(s->pwm.addr));
  447 + qemu_put_timer(f, s->pwm.tm[0]);
  448 + qemu_put_timer(f, s->pwm.tm[1]);
  449 + qemu_put_timer(f, s->pwm.tm[2]);
  450 +}
  451 +
  452 +static int lm_kbd_load(QEMUFile *f, void *opaque, int version_id)
  453 +{
  454 + struct lm_kbd_s *s = (struct lm_kbd_s *) opaque;
  455 + int i;
  456 +
  457 + i2c_slave_load(f, &s->i2c);
  458 + s->i2c_dir = qemu_get_byte(f);
  459 + s->i2c_cycle = qemu_get_byte(f);
  460 + s->reg = (int8_t) qemu_get_byte(f);
  461 +
  462 + qemu_get_8s(f, &s->config);
  463 + qemu_get_8s(f, &s->status);
  464 + qemu_get_8s(f, &s->acttime);
  465 + qemu_get_8s(f, &s->error);
  466 + qemu_get_8s(f, &s->clock);
  467 +
  468 + qemu_get_be16s(f, &s->gpio.pull);
  469 + qemu_get_be16s(f, &s->gpio.mask);
  470 + qemu_get_be16s(f, &s->gpio.dir);
  471 + qemu_get_be16s(f, &s->gpio.level);
  472 +
  473 + s->kbd.dbnctime = qemu_get_byte(f);
  474 + s->kbd.size = qemu_get_byte(f);
  475 + s->kbd.start = qemu_get_byte(f);
  476 + s->kbd.len = qemu_get_byte(f);
  477 + qemu_get_buffer(f, s->kbd.fifo, sizeof(s->kbd.fifo));
  478 +
  479 + for (i = 0; i < sizeof(s->pwm.file); i ++)
  480 + qemu_get_be16s(f, &s->pwm.file[i]);
  481 + qemu_get_8s(f, &s->pwm.faddr);
  482 + qemu_get_buffer(f, s->pwm.addr, sizeof(s->pwm.addr));
  483 + qemu_get_timer(f, s->pwm.tm[0]);
  484 + qemu_get_timer(f, s->pwm.tm[1]);
  485 + qemu_get_timer(f, s->pwm.tm[2]);
  486 +
  487 + lm_kbd_irq_update(s);
  488 + lm_kbd_gpio_update(s);
  489 +
  490 + return 0;
  491 +}
  492 +
  493 +static int lm_kbd_iid = 0;
  494 +
  495 +struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq)
  496 +{
  497 + struct lm_kbd_s *s;
  498 +
  499 + s = (struct lm_kbd_s *) i2c_slave_init(bus, 0, sizeof(struct lm_kbd_s));
  500 + s->model = 0x8323;
  501 + s->pwm.tm[0] = qemu_new_timer(vm_clock, lm_kbd_pwm0_tick, s);
  502 + s->pwm.tm[1] = qemu_new_timer(vm_clock, lm_kbd_pwm1_tick, s);
  503 + s->pwm.tm[2] = qemu_new_timer(vm_clock, lm_kbd_pwm2_tick, s);
  504 + s->nirq = nirq;
  505 +
  506 + s->i2c.event = lm_i2c_event;
  507 + s->i2c.recv = lm_i2c_rx;
  508 + s->i2c.send = lm_i2c_tx;
  509 +
  510 + lm_kbd_reset(s);
  511 +
  512 + qemu_register_reset((void *) lm_kbd_reset, s);
  513 + register_savevm("LM8323", lm_kbd_iid ++, 0,
  514 + lm_kbd_save, lm_kbd_load, s);
  515 +
  516 + return &s->i2c;
  517 +}
  518 +
  519 +void lm832x_key_event(struct i2c_slave *i2c, int key, int state)
  520 +{
  521 + struct lm_kbd_s *s = (struct lm_kbd_s *) i2c;
  522 +
  523 + if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
  524 + return;
  525 +
  526 + if (s->kbd.len >= sizeof(s->kbd.fifo))
  527 + return lm_kbd_error(s, ERR_FIFOOVR);
  528 +
  529 + s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
  530 + key | (state << 7);
  531 +
  532 + /* We never set ERR_KEYOVR because we support multiple keys fine. */
  533 + s->status |= INT_KEYPAD;
  534 + lm_kbd_irq_update(s);
  535 +}
... ...
hw/nseries.c
... ... @@ -45,6 +45,7 @@ struct n800_s {
45 45 i2c_bus *i2c;
46 46  
47 47 int keymap[0x80];
  48 + i2c_slave *kbd;
48 49  
49 50 struct tusb_s *usb;
50 51 void *retu;
... ... @@ -92,16 +93,22 @@ struct n800_s {
92 93 #define N8X0_TAHVO_GPIO 111
93 94 #define N800_UNKNOWN_GPIO4 112 /* out */
94 95 #define N810_SLEEPX_LED_GPIO 112
95   -#define N810_TSC_UNKNOWN_GPIO 118 /* out */
96   -#define N800_TSC_RESET_GPIO 119 /* ? */
  96 +#define N800_TSC_RESET_GPIO 118 /* ? */
  97 +#define N800_TSC_UNKNOWN_GPIO 119 /* out */
97 98 #define N8X0_TMP105_GPIO 125
98 99  
99 100 /* Config */
100 101 #define XLDR_LL_UART 1
101 102  
102   -/* Addresses on the I2C bus */
103   -#define N8X0_TMP105_ADDR 0x48
104   -#define N8X0_MENELAUS_ADDR 0x72
  103 +/* Addresses on the I2C bus 0 */
  104 +#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */
  105 +#define N8X0_TCM825x_ADDR 0x29 /* Camera */
  106 +#define N810_LP5521_ADDR 0x32 /* LEDs */
  107 +#define N810_TSL2563_ADDR 0x3d /* Light sensor */
  108 +#define N810_LM8323_ADDR 0x45 /* Keyboard */
  109 +/* Addresses on the I2C bus 1 */
  110 +#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */
  111 +#define N8X0_MENELAUS_ADDR 0x72 /* Power management */
105 112  
106 113 /* Chipselects on GPMC NOR interface */
107 114 #define N8X0_ONENAND_CS 0
... ... @@ -190,12 +197,12 @@ static const int n800_keys[16] = {
190 197 28, /* Enter */
191 198 77, /* Right */
192 199 -1,
193   - 1, /* Cycle (ESC) */
  200 + 1, /* Cycle (ESC) */
194 201 80, /* Down */
195 202 62, /* Menu (F4) */
196 203 -1,
197 204 66, /* Zoom- (F8) */
198   - 64, /* FS (F6) */
  205 + 64, /* FullScreen (F6) */
199 206 65, /* Zoom+ (F7) */
200 207 -1,
201 208 };
... ... @@ -235,6 +242,107 @@ static void n810_tsc_setup(struct n800_s *s)
235 242 tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
236 243 }
237 244  
  245 +/* N810 Keyboard controller */
  246 +static void n810_key_event(void *opaque, int keycode)
  247 +{
  248 + struct n800_s *s = (struct n800_s *) opaque;
  249 + int code = s->keymap[keycode & 0x7f];
  250 +
  251 + if (code == -1) {
  252 + if ((keycode & 0x7f) == RETU_KEYCODE)
  253 + retu_key_event(s->retu, !(keycode & 0x80));
  254 + return;
  255 + }
  256 +
  257 + lm832x_key_event(s->kbd, code, !(keycode & 0x80));
  258 +}
  259 +
  260 +#define M 0
  261 +
  262 +static int n810_keys[0x80] = {
  263 + [0x01] = 16, /* Q */
  264 + [0x02] = 37, /* K */
  265 + [0x03] = 24, /* O */
  266 + [0x04] = 25, /* P */
  267 + [0x05] = 14, /* Backspace */
  268 + [0x06] = 30, /* A */
  269 + [0x07] = 31, /* S */
  270 + [0x08] = 32, /* D */
  271 + [0x09] = 33, /* F */
  272 + [0x0a] = 34, /* G */
  273 + [0x0b] = 35, /* H */
  274 + [0x0c] = 36, /* J */
  275 +
  276 + [0x11] = 17, /* W */
  277 + [0x12] = 62, /* Menu (F4) */
  278 + [0x13] = 38, /* L */
  279 + [0x14] = 40, /* ' (Apostrophe) */
  280 + [0x16] = 44, /* Z */
  281 + [0x17] = 45, /* X */
  282 + [0x18] = 46, /* C */
  283 + [0x19] = 47, /* V */
  284 + [0x1a] = 48, /* B */
  285 + [0x1b] = 49, /* N */
  286 + [0x1c] = 42, /* Shift (Left shift) */
  287 + [0x1f] = 65, /* Zoom+ (F7) */
  288 +
  289 + [0x21] = 18, /* E */
  290 + [0x22] = 39, /* ; (Semicolon) */
  291 + [0x23] = 12, /* - (Minus) */
  292 + [0x24] = 13, /* = (Equal) */
  293 + [0x2b] = 56, /* Fn (Left Alt) */
  294 + [0x2c] = 50, /* M */
  295 + [0x2f] = 66, /* Zoom- (F8) */
  296 +
  297 + [0x31] = 19, /* R */
  298 + [0x32] = 29 | M, /* Right Ctrl */
  299 + [0x34] = 57, /* Space */
  300 + [0x35] = 51, /* , (Comma) */
  301 + [0x37] = 72 | M, /* Up */
  302 + [0x3c] = 82 | M, /* Compose (Insert) */
  303 + [0x3f] = 64, /* FullScreen (F6) */
  304 +
  305 + [0x41] = 20, /* T */
  306 + [0x44] = 52, /* . (Dot) */
  307 + [0x46] = 77 | M, /* Right */
  308 + [0x4f] = 63, /* Home (F5) */
  309 + [0x51] = 21, /* Y */
  310 + [0x53] = 80 | M, /* Down */
  311 + [0x55] = 28, /* Enter */
  312 + [0x5f] = 1, /* Cycle (ESC) */
  313 +
  314 + [0x61] = 22, /* U */
  315 + [0x64] = 75 | M, /* Left */
  316 +
  317 + [0x71] = 23, /* I */
  318 +#if 0
  319 + [0x75] = 28 | M, /* KP Enter (KP Enter) */
  320 +#else
  321 + [0x75] = 15, /* KP Enter (Tab) */
  322 +#endif
  323 +};
  324 +
  325 +#undef M
  326 +
  327 +static void n810_kbd_setup(struct n800_s *s)
  328 +{
  329 + qemu_irq kbd_irq = omap2_gpio_in_get(s->cpu->gpif, N810_KEYBOARD_GPIO)[0];
  330 + int i;
  331 +
  332 + for (i = 0; i < 0x80; i ++)
  333 + s->keymap[i] = -1;
  334 + for (i = 0; i < 0x80; i ++)
  335 + if (n810_keys[i] > 0)
  336 + s->keymap[n810_keys[i]] = i;
  337 +
  338 + qemu_add_kbd_event_handler(n810_key_event, s);
  339 +
  340 + /* Attach the LM8322 keyboard to the I2C bus,
  341 + * should happen in n8x0_i2c_setup and s->kbd be initialised here. */
  342 + s->kbd = lm8323_init(s->i2c, kbd_irq);
  343 + i2c_set_slave_address(s->kbd, N810_LM8323_ADDR);
  344 +}
  345 +
238 346 /* LCD MIPI DBI-C controller (URAL) */
239 347 struct mipid_s {
240 348 int resp[4];
... ... @@ -954,8 +1062,10 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
954 1062 n8x0_i2c_setup(s);
955 1063 if (model == 800)
956 1064 n800_tsc_kbd_setup(s);
957   - else if (model == 810)
  1065 + else if (model == 810) {
958 1066 n810_tsc_setup(s);
  1067 + n810_kbd_setup(s);
  1068 + }
959 1069 n8x0_spi_setup(s);
960 1070 n8x0_dss_setup(s, ds);
961 1071 n8x0_cbus_setup(s);
... ...