xref: /illumos-kvm-cmd/hw/lm832x.c (revision 68396ea9)
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 "console.h"
25 
26 typedef struct {
27     i2c_slave 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 
lm_kbd_irq_update(LM823KbdState * s)80 static void lm_kbd_irq_update(LM823KbdState *s)
81 {
82     qemu_set_irq(s->nirq, !s->status);
83 }
84 
lm_kbd_gpio_update(LM823KbdState * s)85 static void lm_kbd_gpio_update(LM823KbdState *s)
86 {
87 }
88 
lm_kbd_reset(LM823KbdState * s)89 static 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 
lm_kbd_error(LM823KbdState * s,int err)102 static 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 
lm_kbd_pwm_tick(LM823KbdState * s,int line)109 static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
110 {
111 }
112 
lm_kbd_pwm_start(LM823KbdState * s,int line)113 static void lm_kbd_pwm_start(LM823KbdState *s, int line)
114 {
115     lm_kbd_pwm_tick(s, line);
116 }
117 
lm_kbd_pwm0_tick(void * opaque)118 static void lm_kbd_pwm0_tick(void *opaque)
119 {
120     lm_kbd_pwm_tick(opaque, 0);
121 }
lm_kbd_pwm1_tick(void * opaque)122 static void lm_kbd_pwm1_tick(void *opaque)
123 {
124     lm_kbd_pwm_tick(opaque, 1);
125 }
lm_kbd_pwm2_tick(void * opaque)126 static void lm_kbd_pwm2_tick(void *opaque)
127 {
128     lm_kbd_pwm_tick(opaque, 2);
129 }
130 
131 enum {
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 
lm_kbd_read(LM823KbdState * s,int reg,int byte)163 static 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 
lm_kbd_write(LM823KbdState * s,int reg,int byte,uint8_t value)244 static 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 
lm_i2c_event(i2c_slave * i2c,enum i2c_event event)381 static void lm_i2c_event(i2c_slave *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 
lm_i2c_rx(i2c_slave * i2c)397 static int lm_i2c_rx(i2c_slave *i2c)
398 {
399     LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
400 
401     return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
402 }
403 
lm_i2c_tx(i2c_slave * i2c,uint8_t data)404 static int lm_i2c_tx(i2c_slave *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 
lm_kbd_post_load(void * opaque,int version_id)417 static 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 
427 static 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 
lm8323_init(i2c_slave * i2c)461 static int lm8323_init(i2c_slave *i2c)
462 {
463     LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
464 
465     s->model = 0x8323;
466     s->pwm.tm[0] = qemu_new_timer(vm_clock, lm_kbd_pwm0_tick, s);
467     s->pwm.tm[1] = qemu_new_timer(vm_clock, lm_kbd_pwm1_tick, s);
468     s->pwm.tm[2] = qemu_new_timer(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 
lm832x_key_event(struct i2c_slave * i2c,int key,int state)477 void lm832x_key_event(struct i2c_slave *i2c, int key, int state)
478 {
479     LM823KbdState *s = (LM823KbdState *) i2c;
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 
497 static I2CSlaveInfo lm8323_info = {
498     .qdev.name = "lm8323",
499     .qdev.size = sizeof(LM823KbdState),
500     .qdev.vmsd = &vmstate_lm_kbd,
501     .init = lm8323_init,
502     .event = lm_i2c_event,
503     .recv = lm_i2c_rx,
504     .send = lm_i2c_tx
505 };
506 
lm832x_register_devices(void)507 static void lm832x_register_devices(void)
508 {
509     i2c_register_slave(&lm8323_info);
510 }
511 
512 device_init(lm832x_register_devices)
513