From 32890b983086136fef8721363a2d3860f337ad53 Mon Sep 17 00:00:00 2001 From: Marc Dietrich Date: Thu, 19 May 2011 16:34:42 +0200 Subject: Staging: initial version of the nvec driver This is an implementation of a NVidia compliant embedded controller protocol driver. It is used on some ARM-Tegra boards for device communication. Signed-off-by: Marc Dietrich Signed-off-by: Greg Kroah-Hartman --- drivers/staging/nvec/nvec_kbd.c | 122 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 drivers/staging/nvec/nvec_kbd.c (limited to 'drivers/staging/nvec/nvec_kbd.c') diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c new file mode 100644 index 0000000..9a98507 --- /dev/null +++ b/drivers/staging/nvec/nvec_kbd.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include "nvec-keytable.h" +#include "nvec.h" + +#define ACK_KBD_EVENT {'\x05','\xed','\x01'} + +static unsigned char keycodes[ARRAY_SIZE(code_tab_102us) + + ARRAY_SIZE(extcode_tab_us102)]; + +struct nvec_keys { + struct input_dev *input; + struct notifier_block notifier; + struct nvec_chip *nvec; +}; + +static struct nvec_keys keys_dev; + +static int nvec_keys_notifier(struct notifier_block *nb, + unsigned long event_type, void *data) +{ + int code, state; + unsigned char *msg = (unsigned char *)data; + + if (event_type == NVEC_KB_EVT) { + nvec_size _size = (msg[0] & (3 << 5)) >> 5; + +/* power on/off button */ + if(_size == NVEC_VAR_SIZE) + return NOTIFY_STOP; + + if(_size == NVEC_3BYTES) + msg++; + + code = msg[1] & 0x7f; + state = msg[1] & 0x80; + + input_report_key(keys_dev.input, code_tabs[_size][code], !state); + input_sync(keys_dev.input); + + return NOTIFY_STOP; + } + + return NOTIFY_DONE; +} + +static int nvec_kbd_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) +{ + unsigned char buf[] = ACK_KBD_EVENT; + struct nvec_chip *nvec = keys_dev.nvec; + + if(type==EV_REP) + return 0; + + if(type!=EV_LED) + return -1; + + if(code!=LED_CAPSL) + return -1; + + buf[2] = !!value; + nvec_write_async(nvec, buf, sizeof(buf)); + + return 0; +} + +int __init nvec_kbd_init(struct nvec_chip *nvec) +{ + int i, j, err; + struct input_dev *idev; + + j = 0; + + for(i = 0; i < ARRAY_SIZE(code_tab_102us); ++i) + keycodes[j++] = code_tab_102us[i]; + + for(i = 0; i < ARRAY_SIZE(extcode_tab_us102); ++i) + keycodes[j++]=extcode_tab_us102[i]; + + idev = input_allocate_device(); + idev->name = "Tegra nvec keyboard"; + idev->phys = "i2c3_slave/nvec"; + idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_LED); + idev->ledbit[0] = BIT_MASK(LED_CAPSL); + idev->event = nvec_kbd_event; + idev->keycode = keycodes; + idev->keycodesize = sizeof(unsigned char); + idev->keycodemax = ARRAY_SIZE(keycodes); + + for( i = 0; i < ARRAY_SIZE(keycodes); ++i) + set_bit(keycodes[i], idev->keybit); + + clear_bit(0, idev->keybit); + err = input_register_device(idev); + if(err) + goto fail; + + keys_dev.input = idev; + keys_dev.notifier.notifier_call = nvec_keys_notifier; + keys_dev.nvec = nvec; + nvec_register_notifier(nvec, &keys_dev.notifier, 0); + + /* Enable keyboard */ + nvec_write_async(nvec, "\x05\xf4", 2); + + /* keyboard reset? */ + nvec_write_async(nvec, "\x05\x03\x01\x01", 4); + nvec_write_async(nvec, "\x05\x04\x01", 3); + nvec_write_async(nvec, "\x06\x01\xff\x03", 4); +/* FIXME + wait until keyboard reset is finished + or until we have a sync write */ + mdelay(1000); + + return 0; + +fail: + input_free_device(idev); + return err; +} -- cgit v1.1