aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/nvec/nvec_kbd.c
diff options
context:
space:
mode:
authorMarc Dietrich <marvin24@gmx.de>2011-05-19 16:34:42 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-19 15:36:10 -0700
commit32890b983086136fef8721363a2d3860f337ad53 (patch)
tree123350f6002cf23fb2367d96bfe9dcbd93ffeb57 /drivers/staging/nvec/nvec_kbd.c
parent23a4231150ad227c99b7358ae9a741def5898d90 (diff)
downloadkernel_samsung_smdk4412-32890b983086136fef8721363a2d3860f337ad53.zip
kernel_samsung_smdk4412-32890b983086136fef8721363a2d3860f337ad53.tar.gz
kernel_samsung_smdk4412-32890b983086136fef8721363a2d3860f337ad53.tar.bz2
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 <marvin24@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/nvec/nvec_kbd.c')
-rw-r--r--drivers/staging/nvec/nvec_kbd.c122
1 files changed, 122 insertions, 0 deletions
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 <linux/slab.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#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;
+}