aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/keyboard/Kconfig6
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/tc35894xbg.c722
-rw-r--r--drivers/input/keyboard/tc35894xbg_regs.h1528
-rw-r--r--include/linux/i2c/tc35894xbg.h72
5 files changed, 2329 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index b8c51b9781d..1b2418da256 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -318,6 +318,12 @@ config KEYBOARD_IMX
To compile this driver as a module, choose M here: the
module will be called imx_keypad.
+config KEYBOARD_TC35894XBG
+ tristate "TC35894XBG I2C keypad support"
+ depends on I2C
+ help
+ Say Y if you have Toshiba TX35894XBG keypad controller
+
config KEYBOARD_NEWTON
tristate "Newton keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index a34452e8ebe..1057855bee4 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
+obj-$(CONFIG_KEYBOARD_TC35894XBG) += tc35894xbg.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
diff --git a/drivers/input/keyboard/tc35894xbg.c b/drivers/input/keyboard/tc35894xbg.c
new file mode 100644
index 00000000000..68e197dbe20
--- /dev/null
+++ b/drivers/input/keyboard/tc35894xbg.c
@@ -0,0 +1,722 @@
+/*
+ * tc35894xbg.c: Keypad driver for Toshiba TC35894XBG
+ *
+ * (C) Copyright 2010 Intel Corporation
+ * Author: Charlie Paul (z8cpaul@windriver.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/i2c/tc35894xbg.h>
+#include "tc35894xbg_regs.h"
+
+struct tc35894xbg_keypad_chip {
+ /* device lock */
+ struct mutex lock;
+ struct i2c_client *client;
+ struct work_struct work;
+ struct input_dev *idev;
+ bool kp_enabled;
+ bool pm_suspend;
+ char phys[32];
+ struct tc35894xbg_platform_data pd;
+ unsigned char keymap_index;
+ unsigned int kp_reg_addr;
+};
+
+#define work_to_keypad(w) container_of(w, struct tc35894xbg_keypad_chip, \
+ work)
+#define client_to_keypad(c) container_of(c, struct tc35894xbg_keypad_chip, \
+ client)
+#define dev_to_keypad(d) container_of(c, struct tc35894xbg_keypad_chip, \
+ client->dev)
+
+#define KEYPAD_MAX_DATA 8
+
+/*
+ * To write, access the chip's address in write mode, and dump the
+ * command and data on the bus. The command and data are taken as
+ * sequential u8s out of varargs, to a maxinum of KEYPAD_MAX_DATA
+ */
+static int keypad_write(struct tc35894xbg_keypad_chip *tc, int len, ...)
+{
+ int ret, i;
+ va_list ap;
+ u8 data[KEYPAD_MAX_DATA];
+
+ va_start(ap, len);
+ if (len > KEYPAD_MAX_DATA) {
+ dev_err(&tc->client->dev, "tried to send %d bytes\n", len);
+ va_end(ap);
+ return 0;
+ }
+
+ for (i = 0; i < len; i++)
+ data[i] = va_arg(ap, int);
+ va_end(ap);
+
+#ifdef DEBUG
+ dev_dbg(&tc->client->dev, "Register write: register:0x%02x", data[0]);
+ for (i = 1; i < len; i++)
+ dev_dbg(&tc->client->dev, ", value:0x%02x", data[i]);
+ dev_dbg(&tc->client->dev, "\n");
+#endif
+ /*
+ * In case of host's asleep, send again when get NACK
+ */
+ ret = i2c_master_send(tc->client, data, len);
+ if (ret == -EREMOTEIO)
+ ret = i2c_master_send(tc->client, data, len);
+
+ if (ret != len)
+ dev_err(&tc->client->dev, "sent %d bytes of %d total\n",
+ len, ret);
+
+ return ret;
+}
+
+/*
+ * To read, first send the command byte and end the transaction.
+ * Then we can get the data in read mode.
+ */
+static int keypad_read(struct tc35894xbg_keypad_chip *tc, u8 cmd, u8 * buf,
+ int len)
+{
+#ifdef DEBUG
+ int i;
+#endif
+ int ret;
+
+ /*
+ * In case of host's asleep, send again when get NACK
+ */
+ ret = i2c_master_send(tc->client, &cmd, 1);
+ if (ret == -EREMOTEIO)
+ ret = i2c_master_send(tc->client, &cmd, 1);
+
+ if (ret != 1) {
+ dev_err(&tc->client->dev, "sending command 0x%2x failed.\n",
+ cmd);
+ return 0;
+ }
+
+ ret = i2c_master_recv(tc->client, buf, len);
+ if (ret != len)
+ dev_err(&tc->client->dev, "want %d bytes, got %d\n", len, ret);
+
+#ifdef DEBUG
+ dev_dbg(&tc->client->dev, "Register read: register:0x%02x", cmd);
+ for (i = 0; i < len; i++)
+ dev_dbg(&tc->client->dev, ", value:0x%02x", buf[i]);
+ dev_dbg(&tc->client->dev, "\n");
+#endif
+ return ret;
+}
+
+/*software reset */
+static void keypad_reset(struct tc35894xbg_keypad_chip *tc)
+{
+ /*
+ * Three reset mode, one is software reset by
+ * control the RSTCTRL register.
+ */
+ keypad_write(tc, 2, TC_REG_RSTCTRL, (TC_VAL_IRQRST | TC_VAL_TIMRST
+ | TC_VAL_KBDRST | TC_VAL_GPIRST));
+ /*
+ * Once reset bit is set, need write back to 0
+ */
+ keypad_write(tc, 2, TC_REG_RSTCTRL, 0x0);
+}
+
+/*
+ * Read the manufacturer ID and SW revision registers. Return them
+ * to the caller, if the caller has supplied pointers.
+ */
+static int keypad_checkid(struct tc35894xbg_keypad_chip *tc,
+ int *mfg_id_ret, int *sw_rev_ret)
+{
+ u8 mfg_id;
+ u8 sw_rev;
+
+ if (keypad_read(tc, TC_REG_MANUFACT_CODE, &mfg_id, 1) != 1)
+ return -EREMOTEIO;
+ if (keypad_read(tc, TC_REG_SW_VERSION, &sw_rev, 1) != 1)
+ return -EREMOTEIO;
+
+ if (mfg_id_ret != NULL)
+ *mfg_id_ret = (int)mfg_id;
+ if (sw_rev_ret != NULL)
+ *sw_rev_ret = (int)sw_rev;
+ return 0;
+}
+
+static int keypad_configure(struct tc35894xbg_keypad_chip *tc)
+{
+ /* enable the modified feature */
+ keypad_write(tc, 2, TC_REG_KBDMFS, TC_VAL_MFSEN);
+
+ /* enable the SYSCLK in KBD and timer */
+ keypad_write(tc, 2, TC_REG_CLKEN, 0x28 | TC_VAL_KBDEN);
+ /* when clock source is RC osci NOTE: Needs to be written twice */
+ keypad_write(tc, 2, TC_REG_CLKEN, 0x28 | TC_VAL_KBDEN);
+
+ dev_dbg(&tc->client->dev, "keypad internal clock setting\n");
+ /* CLKCFG : select the RC-osc:2MHZ, disable doubler, divider:2 */
+ /* CLK_IN = internal clock / 2 = 65KHZ / 2 = 32KHZ */
+ keypad_write(tc, 2, TC_REG_CLKCFG, TC_VAL_CLKSRCSEL | 0x01);
+
+ dev_dbg(&tc->client->dev, "keypad keyboard setting\n");
+ /* keyboard settings */
+ keypad_write(tc, 2, TC_REG_KBDSETTLE, tc->pd.settle_time);
+ keypad_write(tc, 2, TC_REG_KBD_BOUNCE, tc->pd.debounce_time);
+ keypad_write(tc, 2, TC_REG_KBDSIZE, ((tc->pd.size_x << 4)
+ | tc->pd.size_y));
+ keypad_write(tc, 3, TC_REG_DEDCFG_COL, tc->pd.col_setting,
+ tc->pd.rowcol_setting);
+
+ dev_dbg(&tc->client->dev, "keypad keyboard interrupt setting\n");
+ /*XXX: set again */
+ keypad_write(tc, 2, TC_REG_DKBDMSK, 0x03);
+
+ /* clear pending interrupts before irq enabled */
+ keypad_write(tc, 2, TC_REG_KBDIC, (TC_VAL_EVTIC | TC_VAL_KBDIC));
+
+ /* Enable keycode lost intr & keyboard status intr */
+ keypad_write(tc, 2, TC_REG_KBDMSK, 0x00);
+
+ return 0;
+}
+
+/*
+ * AT-style: low 7 bits are the keycode, and the top
+ * bit indicates the state( 1 for down, 0 for up)
+ */
+static inline u8 keypad_whichkey(u8 event)
+{
+ /* bit[7-4]:key row, bit[3-0]:key col */
+ u8 row, col;
+ u8 key;
+ row = (event & 0x70) >> 4;
+ col = (event & 0x0F);
+
+ key = row * 8 + col;
+
+ return key;
+}
+
+static inline int keypad_ispress(u8 event)
+{
+ /* 1: pressed, 0: released */
+ return (event & 0x80) ? 0 : 1;
+}
+
+/* reset the keybit of input */
+static void set_keymap_bit(struct tc35894xbg_keypad_chip *tc)
+{
+ int i;
+ unsigned temp;
+ for (i = 0; i < tc->pd.keymap_size; i++) {
+ temp = (tc->pd.keymap[tc->keymap_index][i] & ~(SHIFT_NEEDED));
+ __set_bit(temp, tc->idev->keybit);
+ }
+
+ __clear_bit(KEY_RESERVED, tc->idev->keybit);
+}
+
+
+/* report the 'right shift' key */
+static void report_shift_key(struct tc35894xbg_keypad_chip *tc, int isdown)
+{
+ if (tc->kp_enabled) {
+ input_report_key(tc->idev,
+ tc->pd.keymap[TC_DEFAULT_KEYMAP][tc->pd.right_shift_key],
+ isdown);
+ input_sync(tc->idev);
+ }
+}
+
+/* report the key code */
+static void submit_key(struct tc35894xbg_keypad_chip *tc, u8 key,
+ unsigned short keycode, int isdown)
+{
+ unsigned short saved_keycode = keycode;
+
+ dev_vdbg(&tc->client->dev, "key 0x%02x %s\n",
+ key, isdown ? "down" : "up");
+ /*
+ * Translate the non-exist keycode keys.
+ * when key press down, report the 'shift' key pressed ahead.
+ */
+ if ((keycode & SHIFT_NEEDED) && isdown) {
+ keycode = keycode & ~(SHIFT_NEEDED);
+ report_shift_key(tc, isdown);
+ }
+
+ /* report the key */
+ if (tc->kp_enabled) {
+ input_report_key(tc->idev, (keycode & ~(SHIFT_NEEDED)), isdown);
+ input_sync(tc->idev);
+ }
+
+ /*
+ * When key press up, report the 'shift' up followed.
+ */
+ if ((saved_keycode & SHIFT_NEEDED) && !isdown)
+ report_shift_key(tc, isdown);
+}
+
+/* key event interrupt handler */
+static inline void process_keys(struct tc35894xbg_keypad_chip *tc)
+{
+ u8 event;
+ int ret, i = 0;
+ static u8 queue[TC35894XBG_MAX_FIFO];
+ static int tail;
+
+ ret = keypad_read(tc, TC_REG_EVTCODE, &event, 1);
+ if (ret < 0) {
+ dev_err(&tc->client->dev, "Failed reading fifo\n");
+ /* clear event buffer */
+ keypad_write(tc, 2, TC_REG_KBDIC, 0x83);
+ return;
+ }
+
+ /* clear event buffer */
+ keypad_write(tc, 2, TC_REG_KBDIC, 0x83);
+
+ i = 0;
+ /* modified feature enable on KBDMFS */
+ if (event != 0x7F && event != 0xFF) {
+
+ u8 key = keypad_whichkey(event);
+ int isdown = keypad_ispress(event);
+ unsigned short keycode = tc->pd.keymap[tc->keymap_index][key];
+
+ /* The function key pressed */
+ if ((key == tc->pd.function_key) && isdown) {
+ tc->keymap_index = TC_ALT_KEYMAP;
+ set_keymap_bit(tc);
+ return;
+ }
+
+ /* Function key press up */
+ if ((key == tc->pd.function_key) && !isdown) {
+ /*
+ * dequeue the queue,
+ * where keys stored while FN is pressed
+ */
+ int j;
+ unsigned short temp_key;
+ for (j = 0; j < tail; j++) { /* keys up */
+ temp_key = tc->pd.keymap[TC_ALT_KEYMAP][queue[j]];
+ submit_key(tc, queue[j], temp_key, 0);
+ }
+ tail = 0;
+
+ tc->keymap_index = TC_DEFAULT_KEYMAP;
+ set_keymap_bit(tc);
+ return;
+ }
+
+ if (tc->keymap_index == TC_ALT_KEYMAP)
+ queue[tail++] = key;
+
+ submit_key(tc, key, keycode, isdown);
+ }
+
+}
+
+/*
+ * Bottom Half: handle the interrupt by posting key events, or dealing with
+ * errors appropriately
+ */
+static void keypad_work(struct work_struct *work)
+{
+ struct tc35894xbg_keypad_chip *tc = work_to_keypad(work);
+ u8 ints = 0;
+
+
+ mutex_lock(&tc->lock);
+ while ((keypad_read(tc, TC_REG_IRQST, &ints, 1) == 1) && ints) {
+ if (ints & TC_VAL_KBDIRQ) {
+ /* keycode revert from the FIFO buffer */
+ process_keys(tc);
+ }
+ }
+ mutex_unlock(&tc->lock);
+}
+
+/*
+ * We cannot use I2c in interrupt context, so we just schedule work.
+ */
+static irqreturn_t keypad_irq(int irq, void *data)
+{
+ struct tc35894xbg_keypad_chip *tc = data;
+ schedule_work(&tc->work);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Sysfs interface
+ */
+static ssize_t keypad_show_disable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tc35894xbg_keypad_chip *tc = dev_get_drvdata(dev);
+ return sprintf(buf, "%u\n", !tc->kp_enabled);
+}
+
+static ssize_t keypad_set_disable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tc35894xbg_keypad_chip *tc = dev_get_drvdata(dev);
+ int ret;
+ unsigned long i;
+
+ ret = strict_strtoul(buf, 10, &i);
+
+ mutex_lock(&tc->lock);
+ tc->kp_enabled = !i;
+ mutex_unlock(&tc->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(disable_kp, 0644,
+ keypad_show_disable, keypad_set_disable);
+
+static ssize_t keypad_show_addr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tc35894xbg_keypad_chip *tc = dev_get_drvdata(dev);
+ return sprintf(buf, "0x%02X\n", tc->kp_reg_addr);
+}
+
+static ssize_t keypad_set_addr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tc35894xbg_keypad_chip *tc = dev_get_drvdata(dev);
+ int ret;
+ unsigned long i;
+
+ ret = strict_strtoul(buf, 0, &i);
+
+ mutex_lock(&tc->lock);
+ tc->kp_reg_addr = i;
+ mutex_unlock(&tc->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(addr_kp, 0644,
+ keypad_show_addr, keypad_set_addr);
+
+static ssize_t keypad_show_data(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tc35894xbg_keypad_chip *tc = dev_get_drvdata(dev);
+ u8 val;
+
+ mutex_lock(&tc->lock);
+ if (keypad_read(tc, tc->kp_reg_addr, &val, 1) == 1) {
+ mutex_unlock(&tc->lock);
+ return sprintf(buf, "0x%02X\n", val);
+ }
+ mutex_unlock(&tc->lock);
+ return 0;
+}
+
+static ssize_t keypad_set_data(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return 0;
+}
+
+static DEVICE_ATTR(data_kp, 0644,
+ keypad_show_data, keypad_set_data);
+
+static struct attribute *tc35894_attributes[] = {
+ &dev_attr_disable_kp.attr,
+ &dev_attr_addr_kp.attr,
+ &dev_attr_data_kp.attr,
+ NULL
+};
+
+static const struct attribute_group tc35894_attr_group = {
+ .attrs = tc35894_attributes,
+};
+
+static int __devinit
+keypad_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+
+ struct tc35894xbg_platform_data *pdata = client->dev.platform_data;
+ struct input_dev *idev;
+ struct tc35894xbg_keypad_chip *tc;
+
+ int err;
+ int sw_rev;
+ int mfg_id;
+ unsigned long tmo;
+ u8 data[2];
+ unsigned int irq;
+
+
+ dev_dbg(&client->dev, "keypad probe\n");
+
+ if (!pdata || !pdata->size_x || !pdata->size_y) {
+ dev_err(&client->dev, "missing platform_data\n");
+ return -EINVAL;
+ }
+
+ if (pdata->size_x > 8) {
+ dev_err(&client->dev, "invalid x size %d specified\n",
+ pdata->size_x);
+ return -EINVAL;
+ }
+
+ if (pdata->size_y > 12) {
+ dev_err(&client->dev, "invalid y size %d specified\n",
+ pdata->size_y);
+ return -EINVAL;
+ }
+
+ tc = kzalloc(sizeof(*tc), GFP_KERNEL);
+ if (!tc) {
+ err = -ENOMEM;
+ goto fail0;
+ }
+ idev = input_allocate_device();
+ if (!idev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ memcpy(&tc->pd, pdata, sizeof(struct tc35894xbg_platform_data));
+
+ i2c_set_clientdata(client, tc);
+
+ tc->client = client;
+ tc->idev = idev;
+ mutex_init(&tc->lock);
+ INIT_WORK(&tc->work, keypad_work);
+
+ dev_dbg(&client->dev, "Reset GPIO ID: %d\n", tc->pd.gpio_reset);
+ dev_dbg(&client->dev, "Keypad size:%d x %d\n",
+ tc->pd.size_x, tc->pd.size_y);
+
+ /*
+ * Take controller out of reset
+ */
+ if (pdata->gpio_reset != -1) {
+ dev_dbg(&client->dev, "Release TC35894XBG reset\n");
+ if (pdata->reset_ctrl == NULL) {
+ dev_err(&client->dev, "No reset_ctrl function\n");
+ return -ENODEV;
+ }
+ pdata->reset_ctrl(client, 1);
+ }
+
+ /*
+ * Nothing's set up to service the IRQ yet, so just spin for max.
+ * 280us util we can configure.(Tp1 + Tp2)
+ */
+ tmo = jiffies + usecs_to_jiffies(280);
+ while (keypad_read(tc, TC_REG_IRQST, data, 1) == 1) {
+ if (data[0] & TC_VAL_PORIRQ) { /* power on reset complete */
+ /* clear the PORIRQ bit */
+ keypad_write(tc, 2, TC_REG_RSTINTCLR,
+ TC_VAL_IRQCLR);
+ break;
+ }
+ if (time_after(jiffies, tmo)) {
+ dev_err(&client->dev,
+ "timeout waiting for initialisation\n");
+ break;
+ }
+ udelay(1);
+ }
+
+ /* Confirm device ID register */
+ err = keypad_checkid(tc, &mfg_id, &sw_rev);
+ if (err != 0) {
+ dev_err(&client->dev, "Could not read ID and revision\n");
+ goto fail1;
+ } else {
+ dev_dbg(&client->dev, "Controller ID/Rev: 0x%02X/0x%02X\n",
+ mfg_id, sw_rev);
+ }
+
+ /* Software reset can be achieved only after power-on complete */
+ dev_dbg(&client->dev, "Controller reset by software\n");
+ keypad_reset(tc);
+
+ /* detach the RESETN from the global reset tree */
+ keypad_write(tc, 2, TC_REG_EXTRSTN, TC_VAL_EXTRSTN);
+
+ dev_dbg(&client->dev, "keypad configure start\n");
+ keypad_configure(tc);
+
+ tc->kp_enabled = true;
+
+ idev->name = "KEYPAD";
+ snprintf(tc->phys, sizeof(tc->phys), "%s/input-kp",
+ dev_name(&client->dev));
+ idev->phys = tc->phys;
+ /* the two bit set */
+ idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
+
+ tc->keymap_index = TC_DEFAULT_KEYMAP;
+ set_keymap_bit(tc);
+
+ err = input_register_device(idev);
+ if (err) {
+ dev_dbg(&client->dev, "error register input device\n");
+ goto fail2;
+ }
+
+ irq = gpio_to_irq(pdata->gpio_irq);
+ if (irq < 0) {
+ dev_err(&client->dev, "Failed to get IRQ to GPIO %d\n", irq);
+ goto fail2;
+ }
+ client->irq = irq;
+
+ dev_dbg(&client->dev, "keypad irq register\n");
+ err = request_irq(client->irq, keypad_irq, IRQ_TYPE_EDGE_FALLING
+ | IRQF_SHARED, "keypad", tc);
+ if (err) {
+ dev_err(&client->dev, "could not get IRQ %d\n", irq);
+ goto fail3;
+ }
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &tc35894_attr_group);
+ if (err)
+ goto fail3;
+
+ device_init_wakeup(&client->dev, 1);
+ enable_irq_wake(client->irq);
+
+ return 0;
+
+fail3: input_unregister_device(idev);
+ idev = NULL;
+
+fail2: device_remove_file(&client->dev, &dev_attr_disable_kp);
+
+fail1: input_free_device(idev);
+
+fail0: kfree(tc);
+
+ return err;
+}
+
+static int __devexit keypad_remove(struct i2c_client *client)
+{
+ struct tc35894xbg_keypad_chip *tc = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "keypad driver remove\n");
+
+ disable_irq_wake(client->irq);
+ free_irq(client->irq, tc);
+ cancel_work_sync(&tc->work);
+
+ dev_dbg(&client->dev, "keypad input device unregister\n");
+ sysfs_remove_group(&client->dev.kobj, &tc35894_attr_group);
+ input_unregister_device(tc->idev);
+ device_remove_file(&tc->client->dev, &dev_attr_disable_kp);
+
+ kfree(tc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * the chip can switch off when no activity, so
+ * explicitly suspend is no need
+ */
+
+static int keypad_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct tc35894xbg_keypad_chip *tc = i2c_get_clientdata(client);
+
+ set_irq_wake(client->irq, 0);
+ disable_irq(client->irq);
+
+ mutex_lock(&tc->lock);
+ tc->pm_suspend = true;
+ mutex_unlock(&tc->lock);
+ return 0;
+}
+
+static int keypad_resume(struct i2c_client *client)
+{
+ struct tc35894xbg_keypad_chip *tc = i2c_get_clientdata(client);
+
+ mutex_lock(&tc->lock);
+ tc->pm_suspend = false;
+ mutex_unlock(&tc->lock);
+
+ enable_irq(client->irq);
+ set_irq_wake(client->irq, 1);
+ return 0;
+}
+
+#else
+#define keypad_suspend NULL
+#define keypad_resume NULL
+
+#endif
+
+static const struct i2c_device_id keypad_id[] = {
+ { "i2c_TC35894-nEB1", 0 },
+ { "i2c_TC35894-i", 0 },
+ { }
+};
+
+static struct i2c_driver keypad_i2c_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {.name = "keypad",},
+ .probe = keypad_probe,
+ .remove = __devexit_p(keypad_remove),
+ .suspend = keypad_suspend,
+ .resume = keypad_resume,
+ .id_table = keypad_id,
+};
+
+MODULE_DEVICE_TABLE(i2c, keypad_id);
+
+static int __init keypad_init(void)
+{
+ return i2c_add_driver(&keypad_i2c_driver);
+}
+
+static void __exit keypad_exit(void)
+{
+ i2c_del_driver(&keypad_i2c_driver);
+}
+
+module_init(keypad_init);
+module_exit(keypad_exit);
+
+MODULE_AUTHOR("Charlie Paul");
+MODULE_DESCRIPTION("TC35894XBG expander driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/tc35894xbg_regs.h b/drivers/input/keyboard/tc35894xbg_regs.h
new file mode 100644
index 00000000000..87bf7a890be
--- /dev/null
+++ b/drivers/input/keyboard/tc35894xbg_regs.h
@@ -0,0 +1,1528 @@
+/*
+ * tc35894_regs.h: Register definitions for Toshiba TC35894XBG
+ *
+ * (C) Copyright 2010 Intel Corporation
+ * Author: Charlie Paul (z8cpaul@windriver.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#ifndef __TC3589XBG_REGS_H
+#define __TC3589XBG_REGS_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+/******************************************************************************
+ * REGISTER DEFINITIONS
+ ******************************************************************************/
+/******************************************************************************
+ * Setup of Wait Period register
+ ******************************************************************************/
+#define TC_REG_KBDSETTLE (0x01)
+
+/*
+ * Initial wait time for keys to settle, before key scan is started. Each unit
+ * of this timer equals for SYSCLK clock cycles or approx. 61us on a 65.536kHz
+ * SYSCLK. 4 times the value programmed to WAIT0 divided by the SYSCLK
+ * frequency in Hz.
+ * 0xFF: 15.6ms
+ * 0xA3: 9.68ms
+ * 0x7F: 7.8ms
+ * 0x52: 5.0ms
+ * 0x40: 3.9ms
+ * 0x00: 0ms
+ */
+#define TC_VAL_WAIT_15_6MS (0xFF)
+#define TC_VAL_WAIT_9_68MS (0xA3)
+#define TC_VAL_WAIT_7_8MS (0x7F)
+#define TC_VAL_WAIT_5_0MS (0x52)
+#define TC_VAL_WAIT_3_9MS (0x40)
+
+/******************************************************************************
+ * Setup of Debouncing Register
+ *****************************************************************************/
+#define TC_REG_KBD_BOUNCE (0x02)
+
+/*
+ * De-bounce time between detection of any key change and the keyboard
+ * scan. Each unit of this time equals for SYSCLK clock cycles or approx 61us
+ * on a 65.536KHz clock. Debounce time is calculated to:
+ * 4 times the value programmed to BOUNCETIM0 divided by the SYSCLK frequency
+ * in Hz
+ * 0xFF: 15.6ms
+ * 0xA3: 9.68ms
+ * 0x7F: 7.8ms
+ * 0x52: 5.0ms
+ * 0x40: 3.9ms
+ * 0x00: 0ms
+ */
+#define TC_VAL_BOUNCE_15_6MS (0xFF)
+#define TC_VAL_BOUNCE_9_68MS (0xA3)
+#define TC_VAL_BOUNCE_7_8MS (0x7F)
+#define TC_VAL_BOUNCE_5_0MS (0x52)
+#define TC_VAL_BOUNCE_3_9MS (0x40)
+
+/******************************************************************************
+ * Keyboard Matrix Setup
+ ******************************************************************************/
+#define TC_REG_KBDSIZE (0x03)
+
+/*
+ * Number of rows in the keyboard matrix, between 2 and 8
+ * 0: A value of 0 will free all rows to become GPIO lines.
+ * 1: Inhibition
+ * 2-8: Number of Rows
+ */
+#define TC_VAL_ROW_SIZE_MASK (0xF0)
+
+/*
+ * Number of columns in the keyboard matrix, betwee 2 and 12.
+ * 0: A value of 0 will free all rows to become GPIO lines
+ * 1: Inhibition
+ * 2-12: Number of columns
+ */
+#define TC_VAL_COL_SIZE_MASK (0x0F)
+
+/******************************************************************************
+ * Dedicated Key Setup register (0x04 and 0x05)
+ *****************************************************************************/
+#define TC_REG_DEDCFG_COL (0x04)
+
+/*
+ * Each bit in COL[8:2] corresponds to ball KPY8..KPY2 and can be
+ * configured individually.
+ * 0: Dedicated key
+ * 1: No dedicated key (standard GPIO, alternative functionality according
+ * to register BALLCFG or keyboard)
+ */
+#define TC_VAL_COL9 (0x01 << 7)
+#define TC_VAL_COL8 (0x01 << 6)
+#define TC_VAL_COL7 (0x01 << 5)
+#define TC_VAL_COL6 (0x01 << 4)
+#define TC_VAL_COL5 (0x01 << 3)
+#define TC_VAL_COL4 (0x01 << 2)
+#define TC_VAL_COL3 (0x01 << 1)
+#define TC_VAL_COL2 (0x01)
+
+#define TC_REG_DEDCFG_ROW_COL (0x05)
+
+/*
+ * Each bit in ROW[7:2] corresponds to ball KPX7..KPX2 and can be
+ * configured individually.
+ * 0: Dedicated key
+ * 1: No dedicated key (standard GPIO or keyboard matrix)
+ */
+#define TC_VAL_ROW7 (0x01 << 7)
+#define TC_VAL_ROW6 (0x01 << 6)
+#define TC_VAL_ROW5 (0x01 << 5)
+#define TC_VAL_ROW4 (0x01 << 4)
+#define TC_VAL_ROW3 (0x01 << 3)
+#define TC_VAL_ROW2 (0x01 << 2)
+
+/*
+ * Each bit in COL[11:10] corresponds to ball KPY11..KPY10 and can be
+ * configured individually.
+ * 0: Dedicated key
+ * 1: No dedicated key (standard GPIO, alternative functionality according
+ * to register BALLCFG or keyboard)
+ */
+#define TC_VAL_COL11 (0x01 << 1)
+#define TC_VAL_COL10 (0x01)
+
+/******************************************************************************
+ * Keyboard Raw Interrupt Register
+ *****************************************************************************/
+#define TC_REG_KBDRIS (0x06) /* Read Only */
+
+/*
+ * Raw Event Lost Interrupt.
+ * This bit is cleared by writing into EVTIC
+ * 0: No interrupt
+ * 1: More than 8 keyboard event shave been detected and caused
+ * the event buffer to overflow.
+ */
+#define TC_VAL_RELINT (0x01 << 3)
+
+/*
+ * Raw keyboard event interrupt
+ * Reading from EVTCODE until the buffer is empty will automatically
+ * clear this interrupt.
+ * 0: No interrupt
+ * 1: At least one key press or key release is in the keyboard
+ * event buffer.
+ */
+#define TC_VAL_REVT_INT (0x01 << 2)
+
+/*
+ * Raw Key Lost interrupt (indicates a lost keycode)
+ * The meaning of this interrupt bit changes depending on the
+ * configuration of KBDMFS register.
+ * 0: No interrupt
+ * 1: If KBDMFS is set to 0: When RSINT has not been clear upon
+ * detection of a new key press or key
+ * release, or when more than 4 keys are pressed
+ * simultaneously.
+ * If KBDMFS is set to 1: Indicates that more than 4 keys are pressed
+ * simultaneously, i.e. key presses are lost
+ */
+#define TC_VAL_RKLINT (0x01 << 1)
+
+/*
+ * Raw scan interrupt
+ * 0: No interrupt
+ * 1: Interrupt generated after keyboard scan, if the keyboard status has
+ * changed
+ */
+#define TC_VAL_RSINT (0x01)
+
+/******************************************************************************
+ * Keyboard Mask Interrupt Register
+ *****************************************************************************/
+#define TC_REG_KBDMIS (0x07) /* Read Only */
+
+/*
+ * Masked Event Lost Interrupt
+ * 0: No interrupt
+ * 1: More than 8 keyboard events have been detected
+ * and caused the event buffer to overflow.
+ */
+#define TC_VAL_MELINT (0x01 << 3)
+
+/*
+ * Masked keyboard event interrupt
+ * 0: No interrupt
+ * 1: At least one key press or key release is in the keyboard
+ * event buffer.
+ */
+#define TC_VAL_MEVT_INT (0x01 << 2)
+
+/*
+ * Masked key lose interrupt
+ * 0: No interrupt
+ * 1: Masked key lost interrupt.
+ */
+#define TC_VAL_MKLINT (0x01 << 1)
+
+/*
+ * Masked scan interrupt
+ * 0: No interrupt
+ * 1: Interrupt generated after keyboard scan,
+ * if the keyboard status has changed, after masking process.
+ */
+#define TC_VAL_MSINT (0x01)
+
+/******************************************************************************
+ * Keyboard Interrupt Clear Register
+ *****************************************************************************/
+#define TC_REG_KBDIC (0x08) /* Write Only */
+
+/*
+ * Switches off scanning of special function
+ * keys, when keyboard has no special function
+ * layout.
+ * 0: Scans keyboard layout with or without special function keys
+ * 1: Scans keyboard layout without special function keys
+ */
+#define TC_VAL_SFOFF (0x01 << 7)
+
+/*
+ * Clear event buffer an corresponding interrupts
+ * REVTINT and RELINT. The host does not need to write "0".
+ * Write "1" every time when clearing the event buffer.
+ * 0: No action
+ * 1: Clear event buffer and corresponding interrupts REVTINT and RELINT
+ */
+#define TC_VAL_EVTIC (0x01 << 1)
+
+/*
+ * Clear RSINT and RKLINT interrupt bits.
+ * The host does not need to write "0". Write "1" every time when clearing
+ * RSINT and RKLINT.
+ * 0: No action
+ * 1: Clear RSINT and RKLINT interrupt bits.
+*/
+#define TC_VAL_KBDIC (0x01)
+
+/******************************************************************************
+ * Keyboard Mask Register
+ *****************************************************************************/
+#define TC_REG_KBDMSK (0x09)
+
+/*
+ * Enable keyboard event lost interrupt
+ * 0: Enabled
+ * 1: Disabled
+ */
+#define TC_VAL_MSKELINT (0x01 << 3)
+
+/*
+ * Enable keyboard event interrupt
+ * 0: Enabled
+ * 1: Disabled
+ */
+#define TC_VAL_MSKEINT (0x01 << 2)
+
+/*
+ * Enable keycode lost interrupt
+ * 0: Enabled
+ * 1: Disabled
+ */
+#define TC_VAL_MSKKLINT (0x01 << 1)
+
+/*
+ * Enable keyboard status interrupt
+ * 0: Enable
+ * 1: Disable
+ */
+#define TC_VAL_MSKSINT (0x01)
+
+/****************************************************************************
+ * Keyboard Code Registers
+ ***************************************************************************/
+#define TC_REG_KBDCODE0 (0x0B)
+#define TC_REG_KBDCODE1 (0x0C)
+#define TC_REG_KBDCODE2 (0x0D)
+#define TC_REG_KBDCODE3 (0x0E)
+
+/*
+ * Multiple key press. Another key code is available in KEYCODE(X+1) register
+ * 0: Another key code is not available
+ * 1: Another key code is available.
+ */
+#define TC_VAL_MULTIKEY (0x01 << 7)
+
+/* Row index of key that is pressed (0..7) */
+#define TC_VAL_KEYROW_MASK (0x70)
+
+/*
+ * Column index of key that is pressed (0..11 and 12 for special
+ * function key)
+ */
+#define TC_VAL_KEYCOL_MASK (0x0F)
+
+/******************************************************************************
+ * Event Code Register
+ *****************************************************************************/
+#define TC_REG_EVTCODE (0x10)
+
+/*
+ * Indicates, whether keyboard event was a key press or a key release
+ * 0: Key was pressed
+ * 1: Key was released
+ */
+#define TC_VAL_RELEASE (0x01 << 7)
+
+
+/******************************************************************************
+ * Timer configuration registers
+ *****************************************************************************/
+#define TC_REG_TIMCFG0 (0x60)
+#define TC_REG_TIMCFG1 (0x68)
+#define TC_REG_TIMCFG2 (0x70)
+
+/*
+ * Interrupt mask for CYCIRQ
+ * 0: interrupt enabled
+ * 1: interrupt masked
+ */
+#define TC_VAL_TIM_IRQMASK (0x01 << 4)
+
+/*
+ * CYCLE counter control register
+ * 0: Timer/counter stops after TIMLOAD cycles of CNTCLK (One-shot operation)
+ * An interrupt is (only) issued, when the NUM Counter (TIMCYCLE controlled)
+ * is at 0.
+ * 1: Timer/counter counts down from TIMLOAD to 0 as many times as are
+ * specified in the TIMCYCLE register. The, the timer stops and an
+ * interrupt is generated.
+ */
+#define TC_VAL_CYCCTRL (0x01 << 3)
+
+/*
+ * Switches between free-running timer and one time count. In both operating
+ * modes the register TIMCYCLE influences the behavior of the interrupt
+ * generation.
+ * 0: CYCLE mode, behavior depends on CYCLE bit
+ * 1: Timer/counter counts down from TIMLOAD to 0, re-loads the value of
+ * TIMLOAD and restarts counting down. (FREE-running mode)
+ */
+#define TC_VAL_FREE (0x01 << 2)
+
+/*
+ * Synchronization of pattern generator and timer
+ * 0: Pattern generator is started and stopped by the PWMCFG. PGE bit
+ * 1: Pattern generator and Timer are enabled simultaneously setting bit
+ * TIMCFG START, pattern generator is stopped by PWMCFG.PGE=0, timer
+ * is stopped by TIMCFG.START=0
+ */
+#define TC_VAL_SYNC (0x01 << 1)
+
+/*
+ * Timer start/stop control (WRITE_ONLY)
+ * 0: Timer is stopped (can also be stopped from internal state machine)
+ * 1: Timer is started
+ */
+#define TC_VAL_START (0x01)
+
+/******************************************************************************
+ * Pattern Configuration registers
+ *****************************************************************************/
+#define TC_REG_PWMCFG0 (0x61)
+#define TC_REG_PWMCFG1 (0x69)
+#define TC_REG_PWMCFG2 (0x71)
+
+/*
+ * Mask for CDIRQ
+ * 0: CDIRQ enabled
+ * 1: CDIRQ disabled/masked
+ */
+#define TC_VAL_PWM_MASK (0x01 << 3)
+
+/*
+ * Pattern Generator Enable
+ * This bit is ignored, if the SYCN bit of the corresponding
+ * TIMCFG register is set
+ * 0: Pattern generator disabled
+ * 1: Pattern generator enabled
+ */
+#define TC_VAL_PGE (0x01 << 2)
+
+/*
+ * PWM Enable
+ * 0: PWM disabled
+ * PWM timer output assumes value programmed in PWMPOL
+ * 1: PWM enabled
+ */
+#define TC_VAL_PWMEN (0x01 << 1)
+
+/* OFF-state of PWM output, when PWMEN=0
+ * 0: PWM off-state is low
+ * 1: PWM off-state is high
+ */
+#define TC_VAL_PWMPOL (0x01)
+
+/******************************************************************************
+ * Timer Scale registers
+ *
+ * SCAL7:0 : Load value for timer pre-scaler.
+ * The system clock is divided by (SCAL+1). The resulting CNTCLK is
+ * the reference clock for timer related operations.
+ ******************************************************************************/
+#define TC_REG_TIMSCAL0 (0x62)
+#define TC_REG_TIMSCAL1 (0x6A)
+#define TC_REG_TIMSCAL2 (0x72)
+#define TC_VAL_SCAL_MASK (0xFF)
+
+/******************************************************************************
+ * Timer CYCLE registers
+ *
+ * CYCLE7:0 : Additional number of elapsed timer/counter expires, before
+ * CYCIRQ is released. When programmed to a value N, an interrupt
+ * is issued every (N+1) expiry. This register is active in
+ * one-shot and free-running mode. In one-shot mode, the timer
+ * needs to be restarted under host control N times before an
+ * interrupt is generated.
+ * 0: Interrupt generated immediately, when timer/counter expired
+ * 1: Interrupt generated after N+1 expires of timer/counter
+ *****************************************************************************/
+#define TC_REG_TIMCYCLE0 (0x63)
+#define TC_REG_TIMCYCLE1 (0x6B)
+#define TC_REG_TIMCYCLE2 (0x73)
+#define TC_VAL_CYCLE_MASK (0xFF)
+
+/******************************************************************************
+ * Timer LOAD registers
+ *
+ * LOAD7:0 : The register contents define together with TIMSCAL the PWM
+ * frequency. The timer/counter counts down from LOAD value to 0 in
+ * (LOAD+1) steps. The value programmed into this register is
+ * transferred into the timer/counter synchronously to the pre-scaled
+ * timer clock CNTCLK. Therefore, the settings become only effective,
+ * when the timer clock is running (TIMCFG.START bit set). If duty
+ * cycle modulation is enabled, this register defines also the
+ * resolution of possible duty cycle settings
+ *
+ *****************************************************************************/
+#define TC_REG_TIM_LOAD0 (0x64)
+#define TC_REG_TIM_LOAD1 (0x6C)
+#define TC_REG_TIM_LOAD2 (0x74)
+#define TC_VAL_LOAD_MASK (0xFF)
+
+/******************************************************************************
+ * Timer Software Reset register
+ *****************************************************************************/
+#define TC_REG_SWRES (0x78)
+
+/*
+ * Software reset of TIMER2
+ * 0: no action
+ * 1: Software reset on timer 2, needs not to be
+ * written back to 0
+ */
+#define TC_VAL_SWRES2 (0x01 << 2)
+
+/*
+ * Software reset of TIMER1
+ * 0: no action
+ * 1: Software reset on timer 1, needs not to be
+ * written back to 0
+ */
+#define TC_VAL_SWRES1 (0x01 << 1)
+
+/*
+ * Software reset of TIMER0
+ * 0: no action
+ * 1: Software reset on timer 0, needs not to be
+ * written back to 0
+ */
+#define TC_VAL_SWRES0 (0x01)
+
+/******************************************************************************
+ * Timer Raw input status register
+ *
+ * CDIRQ2:0 : Raw interrupt status for CDIRQ timer2,1 and 0
+ * 0: No interrupt pending
+ * 1: Unmasked interrupt generated
+ *
+ * CYCIRQ2:0 : Raw interrupt status for CYCIRQ timer 2, 1 and 0
+ *
+ *****************************************************************************/
+#define TC_REG_TIMRIS (0x7A)
+
+/******************************************************************************
+ * Timer Mask Interrupt Status register
+ *
+ * CDIRQ2:0 : Interrupt after masking, indicates active contribution to the
+ * interrupt ball, when set. Status for CDIRQ timer2, 1 and 0
+ * 0: No interrupt pending
+ * 1: Interrupt generated.
+ *
+ * CYCIRQ2:0 : Interrupt after masking, indicates active contribution to the
+ * interrupt ball, when set. Status for CYCIRQtimer2,1 and 0
+ * 0: No interrupt pending
+ * 1: interrupt generated
+ *****************************************************************************/
+#define TC_REG_TIMMIS (0x7B)
+
+/******************************************************************************
+ * Timer Interrupt Clear register
+ *
+ * CDIRQ2:0: Clears interrupt CDIRQ timer 2,1, and 0
+ * 0: No effect
+ * 1: Interrupt is cleared. Does not need to be written back to 0
+ *
+ * CYCIRQ2:0 Clears interrupt CYCIRQ timer 2,1, and 0
+ * 0: No effect
+ * 1: Interrupt is cleared. Does not need to be written back to 0
+ *****************************************************************************/
+#define TC_REG_TIMIC (0x7C)
+#define TC_VAL_CDIRQ2 (0x01 << 5)
+#define TC_VAL_CDIRQ1 (0x01 << 4)
+#define TC_VAL_CDIRQ0 (0x01 << 3)
+#define TC_VAL_CYCIRQ2 (0x01 << 2)
+#define TC_VAL_CYCIRQ1 (0x01 << 1)
+#define TC_VAL_CYCIRQ0 (0x01)
+
+/******************************************************************************
+ * Patter Storage Register
+ *****************************************************************************/
+#define TC_REG_PWMWP (0x7D)
+
+/*
+ * POINTER6:0 Points to the pattern position configuration register,
+ * which will be overwritten by the next write access
+ * to the PWMPAT register
+ * 0 <= POINTER < 32 : Timer0 patterns 0 to 31
+ * 32 <= POINTER < 64 : Timer1 patterns 0 to 31
+ * 64 <= POINTER < 96 : Timer2 patterns 0 to 31
+ * 96 <= POINTER < 128: Not Valid
+ */
+#define TC_VAL_POINTER_MASK (0x7F)
+
+/******************************************************************************
+ * PWMPAT register
+ *
+ * PAT15:0 : Input port to the pattern storage register indexed by PWMWP,
+ * After I2C write, PWMWP is incremented. Cannot be written in two
+ * byte accesses, must be written in a single I2C burst command.
+ *
+ *****************************************************************************/
+#define TC_REG_PWMPAT_HIGH (0x7E)
+#define TC_REG_PWMPAT_LOW (0x7F)
+
+/******************************************************************************
+ * Manufacture Code register
+ *****************************************************************************/
+#define TC_REG_MANUFACT_CODE (0x80) /* Read Only */
+#define TC_VAL_MANUFACTURE_CODE (0x03)
+
+/******************************************************************************
+ * Software Version register
+ *****************************************************************************/
+#define TC_REG_SW_VERSION (0x81)
+#define TC_VAL_SW_VERSION (0xC0)
+
+/******************************************************************************
+ * I2C register
+ *****************************************************************************/
+#define TC_REG_I2CA (0x80) /* Write Only */
+
+/******************************************************************************
+ * Reset Register
+ *****************************************************************************/
+#define TC_REG_RSTCTRL (0x82)
+
+/*
+ * Interrupt Controller Reset
+ * Status on ball IRQN remains unaffected. This register bit is only used
+ * to control IRA module register. Interrupt status read out is not
+ * possible, when this bit is set. It is recommended to leave this bit always
+ * at zero.
+ * 0: Interrupt Controller not reset
+ * 1: Interrupt Controller is reset (Need to write back to 0, once reset)
+ */
+#define TC_VAL_IRQRST (0x01 << 4)
+
+/*
+ * Timer Reset for timers 0,1,2
+ * 0: Timer not reset
+ * 1: Timer is reset (Need to write back to 0, once reset)
+ */
+#define TC_VAL_TIMRST (0x01 << 3)
+
+/*
+ * Keyboard interface reset
+ * 0: Keyboard not reset
+ * 1: Keyboard is reset (Need to write back to 0, once reset)
+ */
+#define TC_VAL_KBDRST (0x01 << 1)
+
+/*
+ * GPIO reset
+ * 0: GPIO not reset
+ * 1: GPIO reset (Need to write back to 0, once reset)
+ */
+#define TC_VAL_GPIRST (0x01)
+
+/******************************************************************************
+ * External Reset Register
+ *****************************************************************************/
+#define TC_REG_EXTRSTN (0x83)
+
+/*
+ * External Reset ball (RESETN) enable
+ * This register is not on the global reset line, it is reset
+ * only by a power-on reset
+ * 0: RESETN ball is not used as hardware reset
+ * 1: RESETN is used as hardware reset
+ */
+#define TC_VAL_EXTRSTN (0x01)
+
+/******************************************************************************
+ * Reset Interrupt Clear register
+ *****************************************************************************/
+#define TC_REG_RSTINTCLR (0x84)
+
+/*
+ * Clears the RSTINT interrupt
+ * 0: No impact
+ * 1: Clear PORSTN interrupt (does not need to be re-written to 0)
+ */
+#define TC_VAL_IRQCLR (0X01)
+
+/******************************************************************************
+ * Power on Watch dog Register
+ *****************************************************************************/
+#define TC_REG_PORTRIM (0X85)
+
+/*
+ * Override factory setting for Power-on-reset with PRO_TRIMSEL value
+ * 0: Use factory setting
+ * 1: Use value defined in POR_TRIM
+ */
+#define TC_VAL_POR_SEL (0x01 << 7)
+
+/*
+ * 5 bit setting for Power-on-reset level, twos complement
+ * This value affects reset behavior for power-on reset judged on the
+ * voltage found on VCC.
+ */
+#define TC_VAL_POR_TRIM_MASK (0x1F)
+
+/******************************************************************************
+ * Clock Mode register
+ *****************************************************************************/
+#define TC_REG_CLKMODE (0x88)
+
+/*
+ * This register determines the operating mode
+ * 0: SLEEP mode, no SYSCLK generation
+ * 1: OPERATION mode
+ */
+#define TC_VAL_MODCTL (0x01)
+
+/******************************************************************************
+ * Clock Configure Register
+ *****************************************************************************/
+#define TC_REG_CLKCFG (0x89)
+
+/*
+ * Clock source selector
+ * This switch shall not be modified, if CLKMODE.MODCTL is at SLEEP
+ * 0: LVCMOS clock input
+ * 1: Internal RC-oscillator
+ */
+#define TC_VAL_CLKSRCSEL (0x01 << 6)
+
+/*
+ * Clock frequency doubler enable (should only be enabled when CLKDIV=0)
+ * 0: Disable clock frequency doubler
+ * 1: Enable clock frequency doubler
+ */
+#define TC_VAL_CLKFDEN (0x01 << 4)
+
+/* Clock divider for SYSCLK
+ * Used to divide a high frequency LVCMOS input clock DIR24 or alternatively
+ * the internal RC clock to the SYSCLK frequency. Keep in mind that SYSCLK
+ * frequency *6.5 must exceed the maximum allowed SCL frequency.
+ * Clock division ratio is 2
+ *
+ * 0x0: Divide by 1
+ * 0x1: Divide by 2
+ * 0x2: Divide by 4
+ * ...
+ * 0x9: Divide by 512 (Maximum legal division factor)
+ * 0xA: Not allowed
+ * ...
+ * 0xF: Not allowed
+ */
+#define TC_VAL_CLKDIV_MASK (0x0F)
+
+/******************************************************************************
+ * Clock Enable Register
+ *****************************************************************************/
+#define TC_REG_CLKEN (0x8A)
+
+/* Clock output enable Mask */
+#define TC_VAL_CLKOUTEN_MASK (0xC0)
+/* CLKOUT clock disabled */
+#define TC_VAL_CLKOUTEN_DISABLE (0x00)
+/* CLKOUT clock frequency = SYSCLK frequency */
+#define TC_VAL_CLKOUTEN_SYSCLK (0x40)
+/* CLKOUT clock frequency = 1/2 SYSCLK frequency */
+#define TC_VAL_CLKOUTEN_HALF_SYSCLK (0x80)
+
+/*
+ * Timer 0,1,2 clock enable
+ * 0: Timer 0,1 and 2 disabled
+ * 1: Timer 0,1 and 2 enabled
+ * The Timer clock can only be enabled, if an external clock feed
+ * (LVCMOS line) is used.
+ */
+#define TC_VAL_TIMEN (0x01 << 2)
+
+/*
+ * Keyboard clock enable
+ * 0: Keyboard clock disabled
+ * 1: Keyboard clock enabled
+ */
+#define TC_VAL_KBDEN (0x01)
+
+/******************************************************************************
+ * Auto Sleep Timer Enable register
+ *****************************************************************************/
+#define TC_REG_AUTOSLPENA (0x8B)
+
+/*
+ * Auto Sleep feature enable
+ * When Auto-sleep is on, the register MODCTL is controlled
+ * under a state machine and should not be programmed directly
+ * via I2C. Also, the register CLKCFG should not be programmed,
+ * when Auto-sleep is enabled
+ * 0: Auto-sleep feature is off
+ * 1: Auto-sleep feature is on
+ */
+#define TC_VAL_AUTO_ENABLE (0x01)
+
+/******************************************************************************
+ * AUTO Sleep Timer Register
+ *
+ * UPTIME10:0 : Minimum time the TC35894XBG stays in OPERATION mode
+ * Counts SYSCLK cycles before going into SLEEP mode
+ * The value programmed here is multiplied by 64 and copied into
+ * the timer at the time AUTOSLPENA.ENABLE is set to 1.
+ *****************************************************************************/
+#define TC_REG_AUTOSLPTIMER_HIGH (0x8C)
+#define TC_REG_AUTOSLPTIMER_LOW (0x8D)
+#define TC_VAL_UPTIME_LOW_MASK (0x03)
+
+/******************************************************************************
+ * I2C wakeup register
+ *****************************************************************************/
+#define TC_REG_I2CWAKEUP_EN (0x8E)
+
+/*
+ * I2C wake-up enable
+ * 0: Device does not wake-up b I2C access to KBD/TIM module when in SLEEP
+ * 1: Device wakes up by I2C access to KBD/TIM module in SLEEP.
+ */
+#define TC_VAL_I2CWEN (0x01)
+
+/******************************************************************************
+ * Modified Feature Set Register
+ *****************************************************************************/
+#define TC_REG_KBDMFS (0x8F) /* Write Only */
+
+/*
+ * Modified feature set enable / disable
+ * 0: TC35892XBG compatibility mode (modified features disabled)
+ * 1: Modified features enabled
+ */
+#define TC_VAL_MFSEN (0x01)
+
+/******************************************************************************
+ * Interrupt Status Register
+ *****************************************************************************/
+#define TC_REG_IRQST (0x91) /* Read Only */
+
+/*
+ * Supply failure on VCC. Also Power-on is considered
+ * as an initial supply failure.
+ * 0: No failure recoreded
+ * 1: Failure Occurred
+ */
+#define TC_VAL_PORIRQ (0x01 << 7)
+
+/*
+ * Keyboard Interrupt (further key selection in keyboard
+ * module)
+ * 0: Inactive
+ * 1: Active
+ */
+#define TC_VAL_KBDIRQ (0x01 << 6)
+
+/*
+ * Direct keyboard interrupt (further key selection
+ * in GPIO module)
+ * 0: Inactive
+ * 1: Active
+ */
+#define TC_VAL_DKBD_IRQ (0x01 << 5)
+
+/*
+ * Timer 2 Expire (CDIRQ or CYCIRG)
+ * 0: Inactive
+ * 1: Active
+ */
+#define TC_VAL_TIM2IRQ (0x01 << 3)
+
+/*
+ * Timer 1 Expire (CDIRA or CYCIRQ)
+ * 0: Inactive
+ * 1: Active
+ */
+#define TC_VAL_TIM1IRQ (0x01 << 2)
+
+/*
+ * Timer 0 Expire (CDIRA or CYCIRQ)
+ * 0: Inactive
+ * 1: Active
+ */
+#define TC_VAL_TIM0IRQ (0x01 << 1)
+
+/*
+ * GPIO interrupt (further selectionin GPIO module)
+ * 0: Inactive
+ * 1: Active
+ */
+#define TC_VAL_GPIIRQ (0x01)
+
+/******************************************************************************
+ * Drive0 Strength register
+ *
+ * KPX[7:0]DRV1:0 : Output drive strength for KPX[7:0] ball
+ * 00: Lowest strength
+ * 01: Medium strength
+ * 10: Medium strength
+ * 11: Highest strength
+ *
+ ******************************************************************************/
+#define TC_REG_DRIVE0_HIGH (0xA0)
+#define TC_VAL_KPX7_LOW (0x00)
+#define TC_VAL_KPX7_MED_LOW (0x40)
+#define TC_VAL_KPX7_MED_HI (0x80)
+#define TC_VAL_KPX7_HI (0xC0)
+#define TC_VAL_KPX6_LOW (0x00)
+#define TC_VAL_KPX6_MED_LOW (0x01)
+#define TC_VAL_KPX6_MED_HI (0x02)
+#define TC_VAL_KPX6_HI (0x03)
+#define TC_VAL_KPX5_LOW (0x00)
+#define TC_VAL_KPX5_MED_LOW (0x04)
+#define TC_VAL_KPX5_MED_HI (0x08)
+#define TC_VAL_KPX5_HI (0x0C)
+#define TC_VAL_KPX4_LOW (0x00)
+#define TC_VAL_KPX4_MED_LOW (0x01)
+#define TC_VAL_KPX4_MED_HI (0x02)
+#define TC_VAL_KPX4_HI (0x03)
+
+#define TC_REG_DRIVE0_LOW (0xA1)
+#define TC_VAL_KPX3_LOW (0x00)
+#define TC_VAL_KPX3_MED_LOW (0x40)
+#define TC_VAL_KPX3_MED_HI (0x80)
+#define TC_VAL_KPX3_HI (0xC0)
+#define TC_VAL_KPX2_LOW (0x00)
+#define TC_VAL_KPX2_MED_LOW (0x01)
+#define TC_VAL_KPX2_MED_HI (0x02)
+#define TC_VAL_KPX2_HI (0x03)
+#define TC_VAL_KPX1_LOW (0x00)
+#define TC_VAL_KPX1_MED_LOW (0x04)
+#define TC_VAL_KPX1_MED_HI (0x08)
+#define TC_VAL_KPX1_HI (0x0C)
+#define TC_VAL_KPX0_LOW (0x00)
+#define TC_VAL_KPX0_MED_LOW (0x01)
+#define TC_VAL_KPX0_MED_HI (0x02)
+#define TC_VAL_KPX0_HI (0x03)
+
+/******************************************************************************
+ * Drive1 Strength register
+ *
+ * KPY[7:0]DRV1:0 : Output drive strength for KPY[7:0] ball
+ * 00: Lowest strength
+ * 01: Medium strength
+ * 10: Medium strength
+ * 11: Highest strength
+ *
+ *****************************************************************************/
+#define TC_REG_DRIVE1_HIGH (0xA2)
+#define TC_VAL_KPY7_LOW (0x00)
+#define TC_VAL_KPY7_MED_LOW (0x40)
+#define TC_VAL_KPY7_MED_HI (0x80)
+#define TC_VAL_KPY7_HI (0xC0)
+#define TC_VAL_KPY6_LOW (0x00)
+#define TC_VAL_KPY6_MED_LOW (0x01)
+#define TC_VAL_KPY6_MED_HI (0x02)
+#define TC_VAL_KPY6_HI (0x03)
+#define TC_VAL_KPY5_LOW (0x00)
+#define TC_VAL_KPY5_MED_LOW (0x04)
+#define TC_VAL_KPY5_MED_HI (0x08)
+#define TC_VAL_KPY5_HI (0x0C)
+#define TC_VAL_KPY4_LOW (0x00)
+#define TC_VAL_KPY4_MED_LOW (0x01)
+#define TC_VAL_KPY4_MED_HI (0x02)
+#define TC_VAL_KPY4_HI (0x03)
+
+#define TC_REG_DRIVE1_LOW (0xA3)
+#define TC_VAL_KPY3_LOW (0x00)
+#define TC_VAL_KPY3_MED_LOW (0x40)
+#define TC_VAL_KPY3_MED_HI (0x80)
+#define TC_VAL_KPY3_HI (0xC0)
+#define TC_VAL_KPY2_LOW (0x00)
+#define TC_VAL_KPY2_MED_LOW (0x01)
+#define TC_VAL_KPY2_MED_HI (0x02)
+#define TC_VAL_KPY2_HI (0x03)
+#define TC_VAL_KPY1_LOW (0x00)
+#define TC_VAL_KPY1_MED_LOW (0x04)
+#define TC_VAL_KPY1_MED_HI (0x08)
+#define TC_VAL_KPY1_HI (0x0C)
+#define TC_VAL_KPY0_LOW (0x00)
+#define TC_VAL_KPY0_MED_LOW (0x01)
+#define TC_VAL_KPY0_MED_HI (0x02)
+#define TC_VAL_KPY0_HI (0x03)
+
+/******************************************************************************
+ * Drive2 Strength register
+ *
+ * EXTIO0DRV1:0 : Output drive strength for EXTIO0 ball
+ * 00: Lowest strength
+ * 01: Medium strength
+ * 10: Medium strength
+ * 11: Highest strength
+ *
+ * PWM[2:0]DRV1:0 : Output drive strength for PWM2, PWM1, PWM0 ball
+ * 00: Lowest strength
+ * 01: Medium strength
+ * 10: Medium strength
+ * 11: Highest strength
+ *
+ * KPY[11:8]DRV1:0 : Output drive strength for KPY[11:8] ball
+ * 00: Lowest strength
+ * 01: Medium strength
+ * 10: Medium strength
+ * 11: Highest strength
+ *
+ *
+ *****************************************************************************/
+#define TC_REG_DRIVE2_HIGH (0xA4)
+#define TC_VAL_EXTIO0_LOW (0x00)
+#define TC_VAL_EXTIO0_MED_LOW (0x40)
+#define TC_VAL_EXTIO0_MED_HI (0x80)
+#define TC_VAL_EXTIO0_HI (0xC0)
+#define TC_VAL_PWM2_LOW (0x00)
+#define TC_VAL_PWM2_MED_LOW (0x10)
+#define TC_VAL_PWM2_MED_HI (0x20)
+#define TC_VAL_PWM2_HI (0x30)
+#define TC_VAL_PWM1_LOW (0x00)
+#define TC_VAL_PWM1_MED_LOW (0x04)
+#define TC_VAL_PWM1_MED_HI (0x08)
+#define TC_VAL_PWM1_HI (0x0C)
+#define TC_VAL_PWM0_LOW (0x00)
+#define TC_VAL_PWM0_MED_LOW (0x01)
+#define TC_VAL_PWM0_MED_HI (0x02)
+#define TC_VAL_PWM0_HI (0x03)
+
+#define TC_REG_DRIVE2_LOW (0xA5)
+#define TC_VAL_KPY11_LOW (0x00)
+#define TC_VAL_KPY11_MED_LOW (0x40)
+#define TC_VAL_KPY11_MED_HI (0x80)
+#define TC_VAL_KPY11_HI (0xC0)
+#define TC_VAL_KPY10_LOW (0x00)
+#define TC_VAL_KPY10_MED_LOW (0x01)
+#define TC_VAL_KPY10_MED_HI (0x02)
+#define TC_VAL_KPY10_HI (0x03)
+#define TC_VAL_KPY9_LOW (0x00)
+#define TC_VAL_KPY9_MED_LOW (0x04)
+#define TC_VAL_KPY9_MED_HI (0x08)
+#define TC_VAL_KPY9_HI (0x0C)
+#define TC_VAL_KPY8_LOW (0x00)
+#define TC_VAL_KPY8_MED_LOW (0x01)
+#define TC_VAL_KPY8_MED_HI (0x02)
+#define TC_VAL_KPY8_HI (0x03)
+
+/******************************************************************************
+ * Drive3 Strength register
+ *
+ * IRQNDRV1:0 : Output drive strength for IRANDRV ball
+ * 00: Lowest strength
+ * 01: Medium strength
+ * 10: Medium strength
+ * 11: Highest strength
+ *
+ * SDADRV1:0 : Output drive strength for SDADRV ball
+ * 00: Lowest strength
+ * 01: Medium strength
+ * 10: Medium strength
+ * 11: Highest strength
+ *
+ *****************************************************************************/
+#define TC_REG_DRIVE_3 (0xA6)
+#define TC_VAL_IRQNDRV_LOW (0x00)
+#define TC_VAL_IRQNDRV_MED_LOW (0x04)
+#define TC_VAL_IRQNDRV_MED_HI (0x08)
+#define TC_VAL_IRQNDRV_HI (0x0C)
+#define TC_VAL_SDADRV_LOW (0x00)
+#define TC_VAL_SDADRV_MED_LOW (0x01)
+#define TC_VAL_SDADRV_MED_HI (0x02)
+#define TC_VAL_SDADRV_HI (0x03)
+
+/******************************************************************************
+ * IOCF Configuration register
+ *
+ * GPIOSEL3:0 : Overrides BALLCFG with GPIO functionality for DIR24 and
+ * PWM[2:0] balls.
+ * 0: Use functionality defined in BALLCFG for DIR24 and
+ * PWM[2:0] balls
+ * 1: Override DIR24 and PWM[2:0] functionality with GPIO
+ *
+ * IG : Global input gate
+ * 0: Disable all inputs
+ * 1: Enable all inputs
+ *
+ * BALLCFG1:0 : Ball configuration Setting
+ * See Data sheet for tables.
+ *****************************************************************************/
+#define TC_REG_IOCFG (0xA7)
+
+/******************************************************************************
+ * IOPC Ext registers
+ *
+ * DIR[25:24]PR 1:0 : Resistor enable for DIR[25:24] ball
+ * 00: No pull resistor
+ * 01: Pull down resistor
+ * 10: Pull up resistor
+ * 11: Pull up resistor
+ *****************************************************************************/
+#define TC_REG_IOPCEXT (0xA8)
+#define TC_VAL_DIR25_NO_RESISTOR (0x00)
+#define TC_VAL_DIR25_PULL_DOWN (0x04)
+#define TC_VAL_DIR25_PULL_UP (0x08)
+#define TC_VAL_DIR25_PULL_UP_HI (0x0C)
+#define TC_VAL_DIR24_NO_RESISTOR (0x00)
+#define TC_VAL_DIR24_PULL_DOWN (0x01)
+#define TC_VAL_DIR24_PULL_UP (0x02)
+#define TC_VAL_DIR24_PULL_UP_HI (0x03)
+
+/******************************************************************************
+ * IOPC0 Registers
+ *
+ * KPX[7:0]DRV1:0 : Resistor enable for KPX[7:0] ball
+ * 00: No pull resistor
+ * 01: Pull down resistor
+ * 10: Pull up resistor
+ * 11: Pull up resistor
+ *****************************************************************************/
+#define TC_REG_IOPC0_HIGH (0xAA)
+#define TC_VAL_KPX7_NO_RESISTOR (0x00)
+#define TC_VAL_KPX7_PULL_DOWN (0x40)
+#define TC_VAL_KPX7_PULL_UP (0x80)
+#define TC_VAL_KPX7_PULL_UP_HI (0xC0)
+#define TC_VAL_KPX6_NO_RESISTOR (0x00)
+#define TC_VAL_KPX6_PULL_DOWN (0x01)
+#define TC_VAL_KPX6_PULL_UP (0x02)
+#define TC_VAL_KPX6_PULL_UP_HI (0x03)
+#define TC_VAL_KPX5_NO_RESISTOR (0x00)
+#define TC_VAL_KPX5_PULL_DOWN (0x04)
+#define TC_VAL_KPX5_PULL_UP (0x08)
+#define TC_VAL_KPX5_PULL_UP_HI (0x0C)
+#define TC_VAL_KPX4_NO_RESISTOR (0x00)
+#define TC_VAL_KPX4_PULL_DOWN (0x01)
+#define TC_VAL_KPX4_PULL_UP (0x02)
+#define TC_VAL_KPX4_PULL_UP_HI (0x03)
+
+#define TC_REG_IOPC0_LOW (0xAB)
+#define TC_VAL_KPX3_NO_RESISTOR (0x00)
+#define TC_VAL_KPX3_PULL_DOWN (0x40)
+#define TC_VAL_KPX3_PULL_UP (0x80)
+#define TC_VAL_KPX3_PULL_UP_HI (0xC0)
+#define TC_VAL_KPX2_NO_RESISTOR (0x00)
+#define TC_VAL_KPX2_PULL_DOWN (0x01)
+#define TC_VAL_KPX2_PULL_UP (0x02)
+#define TC_VAL_KPX2_PULL_UP_HI (0x03)
+#define TC_VAL_KPX1_NO_RESISTOR (0x00)
+#define TC_VAL_KPX1_PULL_DOWN (0x04)
+#define TC_VAL_KPX1_PULL_UP (0x08)
+#define TC_VAL_KPX1_PULL_UP_HI (0x0C)
+#define TC_VAL_KPX0_NO_RESISTOR (0x00)
+#define TC_VAL_KPX0_PULL_DOWN (0x01)
+#define TC_VAL_KPX0_PULL_UP (0x02)
+#define TC_VAL_KPX0_PULL_UP_HI (0x03)
+
+/******************************************************************************
+ * IOPC1 Registers (0xAC, 0xAD)
+ *
+ * KPY[7:0]DRV1:0 : Resistor enable for KPY[7:0] ball
+ * 00: No pull resistor
+ * 01: Pull down resistor
+ * 10: Pull up resistor
+ * 11: Pull up resistor
+ *****************************************************************************/
+#define TC_REG_IOPC1_HIGH (0xAC)
+#define TC_VAL_KPY7_NO_RESISTOR (0x00)
+#define TC_VAL_KPY7_PULL_DOWN (0x40)
+#define TC_VAL_KPY7_PULL_UP (0x80)
+#define TC_VAL_KPY7_PULL_UP_HI (0xC0)
+#define TC_VAL_KPY6_NO_RESISTOR (0x00)
+#define TC_VAL_KPY6_PULL_DOWN (0x01)
+#define TC_VAL_KPY6_PULL_UP (0x02)
+#define TC_VAL_KPY6_PULL_UP_HI (0x03)
+#define TC_VAL_KPY5_NO_RESISTOR (0x00)
+#define TC_VAL_KPY5_PULL_DOWN (0x04)
+#define TC_VAL_KPY5_PULL_UP (0x08)
+#define TC_VAL_KPY5_PULL_UP_HI (0x0C)
+#define TC_VAL_KPY4_NO_RESISTOR (0x00)
+#define TC_VAL_KPY4_PULL_DOWN (0x01)
+#define TC_VAL_KPY4_PULL_UP (0x02)
+#define TC_VAL_KPY4_PULL_UP_HI (0x03)
+
+#define TC_REG_IOPC1_LOW (0xAD)
+#define TC_VAL_KPY3_NO_RESISTOR (0x00)
+#define TC_VAL_KPY3_PULL_DOWN (0x40)
+#define TC_VAL_KPY3_PULL_UP (0x80)
+#define TC_VAL_KPY3_PULL_UP_HI (0xC0)
+#define TC_VAL_KPY2_NO_RESISTOR (0x00)
+#define TC_VAL_KPY2_PULL_DOWN (0x01)
+#define TC_VAL_KPY2_PULL_UP (0x02)
+#define TC_VAL_KPY2_PULL_UP_HI (0x03)
+#define TC_VAL_KPY1_NO_RESISTOR (0x00)
+#define TC_VAL_KPY1_PULL_DOWN (0x04)
+#define TC_VAL_KPY1_PULL_UP (0x08)
+#define TC_VAL_KPY1_PULL_UP_HI (0x0C)
+#define TC_VAL_KPY0_NO_RESISTOR (0x00)
+#define TC_VAL_KPY0_PULL_DOWN (0x01)
+#define TC_VAL_KPY0_PULL_UP (0x02)
+#define TC_VAL_KPY0_PULL_UP_HI (0x03)
+
+/******************************************************************************
+ * IOPC2 Registers (0xAE, 0xAF)
+ *
+ * EXTIO0PR1:0 : Resistor enable for EXTIO0 ball
+ * 00: No pull resistor
+ * 01: Pull down resistor
+ * 10: Pull up resistor
+ * 11: Pull up resistor
+ * PWM[2:0]PR1:0 : Resistor enable for PWM[2:0] ball
+ * 00: No pull resistor
+ * 01: Pull down resistor
+ * 10: Pull up resistor
+ * 11: Pull up resistor
+ * KPY[11:8]PR1:0: Resistor enable for KPY[11:8] ball
+ * 00: No pull resistor
+ * 01: Pull down resistor
+ * 10: Pull up resistor
+ * 11: Pull up resistor
+ *****************************************************************************/
+#define TC_REG_IOPC2_HIGH (0xAE)
+#define TC_VAL_EXTIO0_NO_RESISTOR (0x00)
+#define TC_VAL_EXTIO0_PULL_DOWN (0x40)
+#define TC_VAL_EXTIO0_PULL_UP (0x80)
+#define TC_VAL_EXTIO0_PULL_UP_HI (0xC0)
+#define TC_VAL_PWM2_NO_RESISTOR (0x00)
+#define TC_VAL_PWM2_PULL_DOWN (0x10)
+#define TC_VAL_PWM2_PULL_UP (0x20)
+#define TC_VAL_PWM2_PULL_UP_HI (0x30)
+#define TC_VAL_PWM1_NO_RESISTOR (0x00)
+#define TC_VAL_PWM1_PULL_DOWN (0x04)
+#define TC_VAL_PWM1_PULL_UP (0x08)
+#define TC_VAL_PWM1_PULL_UP_HI (0x0C)
+#define TC_VAL_PWM0_NO_RESISTOR (0x00)
+#define TC_VAL_PWM0_PULL_DOWN (0x01)
+#define TC_VAL_PWM0_PULL_UP (0x02)
+#define TC_VAL_PWM0_PULL_UP_HI (0x03)
+
+#define TC_REG_IOPC2_LOW (0xAF)
+#define TC_VAL_KPY11_NO_RESISTOR (0x00)
+#define TC_VAL_KPY11_PULL_DOWN (0x40)
+#define TC_VAL_KPY11_PULL_UP (0x80)
+#define TC_VAL_KPY11_PULL_UP_HI (0xC0)
+#define TC_VAL_KPY10_NO_RESISTOR (0x00)
+#define TC_VAL_KPY10_PULL_DOWN (0x01)
+#define TC_VAL_KPY10_PULL_UP (0x02)
+#define TC_VAL_KPY10_PULL_UP_HI (0x03)
+#define TC_VAL_KPY9_NO_RESISTOR (0x00)
+#define TC_VAL_KPY9_PULL_DOWN (0x04)
+#define TC_VAL_KPY9_PULL_UP (0x08)
+#define TC_VAL_KPY9_PULL_UP_HI (0x0C)
+#define TC_VAL_KPY8_NO_RESISTOR (0x00)
+#define TC_VAL_KPY8_PULL_DOWN (0x01)
+#define TC_VAL_KPY8_PULL_UP (0x02)
+#define TC_VAL_KPY8_PULL_UP_HI (0x03)
+
+/******************************************************************************
+ * GPIO Dat registers
+ *
+ * DATA23:0 : Data 23:0 (on ball EXTIO0, PWM[2:0], KPY[11:0] and KPX[7:0] when
+ * GPIO selected)
+ * 0: Output "0" when corresponding MASK bit is set to "1"
+ * 1: Output "1" when corresponding MASK bit is set to "1"
+ *****************************************************************************/
+#define TC_REG_GPIODATA0 (0xC0)
+#define TC_REG_GPIODATA1 (0xC2)
+#define TC_REG_GPIODATA2 (0xC4)
+
+/******************************************************************************
+ * GPIO Data Mask Registers
+ *
+ * MASK23:0 Mask bit for DATA23:0 (WRITE_ONLY)
+ * 0: Disbale DATA23:0 bit setting
+ * 1: Enable DATA23:0 bit setting
+ *****************************************************************************/
+#define TC_REG_GPIODATA0_MASK (0xC1)
+#define TC_REG_GPIODATA1_MASK (0xC3)
+#define TC_REG_GPIODATA2_MASK (0xC5)
+
+/******************************************************************************
+ * GPIO Direction Registers
+ *
+ * DIR23:0 : Direction bits for DATA23:0 (EXTIO0, PWM[2:0], KPY[11:0] and
+ * KPX[7:0])
+ * 0: Input Mode
+ * 1: Output Mode
+ *****************************************************************************/
+#define TC_REG_GPIODIR0 (0xC6)
+#define TC_REG_GPIODIR1 (0xC7)
+#define TC_REG_GPIODIR2 (0xC8)
+
+/******************************************************************************
+ * GPIO Interrupt Sense register
+ *
+ * IS23:0 : Interrupt sense bits for DATA23:0 (EXTIO0, PWM[2:0], KPY[11:0] and
+ * KPX[7:0])
+ * 0: Edge sensitive interrupt
+ * 1: Level sensitive
+ *****************************************************************************/
+#define TC_REG_GPIOIS0 (0xC9)
+#define TC_REG_GPIOIS1 (0xCA)
+#define TC_REG_GPIOIS2 (0xCB)
+
+/*****************************************************************************
+ * GPIO Both Edges Interrupt register
+ *
+ * BE23:0 : Interrupt both edges bits for DATA23:0 (EXTIO0, PWM[2:0],
+ * KPY[11:0] and KPX[7:0]) IBE23 register bit is used also for DIR24
+ * input and DIR25 input when they are configured as direct key input.
+ * 0: Interrupt generated at the active edges
+ * 1: Interrupt generated at both edges
+ *****************************************************************************/
+#define TC_REG_GPIOIBE0 (0xCC)
+#define TC_REG_GPIOIBE1 (0xCD)
+#define TC_REG_GPIOIBE2 (0xCE)
+
+/******************************************************************************
+ * GPIO Interrupt Event register
+ *
+ * IEV23:0 : Interrupt event select from DATA23:0 (EXTIO0, PWM[2:0], KPY[11:0]
+ * and KPX[7:0]) IEV23 register bit is used also for DIR24 input and
+ * DIR25 input when they are configured as direct key input
+ * 0: Interrupt at low level of falling edge
+ * 1: Interrupt at high level of rising edge
+ *****************************************************************************/
+#define TC_REG_GPIOIEV0 (0xCF)
+#define TC_REG_GPIOIEV1 (0xD0)
+#define TC_REG_GPIOIEV2 (0xD1)
+
+/******************************************************************************
+ * GPIO Interrupt Enable register
+ *
+ * IE23:0 : Interrupt enable for DATE23:0 (EXTIO0, PWM[2:0], KPY[11:0] and
+ * KPX[7:0])
+ * 0: Disable Interrupt
+ * 1: Enable Interrupt
+ *****************************************************************************/
+#define TC_REG_GPIOIE0 (0xD2)
+#define TC_REG_GPIOIE1 (0xD3)
+#define TC_REG_GPIOIE2 (0xD4)
+
+/******************************************************************************
+ * GPIO Raw Input Status register
+ *
+ * RIS23:0 : Raw interrupt status for DATA23:0 (EXTIO0, PWM[2:0], KPY[11:0] and
+ * KPX[7:0])
+ * 0: No interrupt condition at GPIO
+ * 1: Interrupt condtionat GPIO
+ *****************************************************************************/
+#define TC_REG_GPIORIS0 (0xD6)
+#define TC_REG_GPIORIS1 (0xD7)
+#define TC_REG_GPIORIS2 (0xD8)
+
+/******************************************************************************
+ * GPIO Mask Interrupt Status register
+ *
+ * MIS23:0 : Masked interrupt status for (EXTIO0, PWM[2:0], KPY[11:0] and
+ * KPX[7:0])
+ * 0: No interrupt condition from GPIO
+ * 1: Interrupt at GPIO is active
+ *****************************************************************************/
+#define TC_REG_GPIOMIS0 (0xD9)
+#define TC_REG_GPIOMIS1 (0xDA)
+#define TC_REG_GPIOMIS2 (0xDB)
+
+/******************************************************************************
+ * GPIO Interrupt Clear register
+ *
+ * IC23:0 : Clear interrupt of DATA23:0 (EXTIO0, PWM[2:0], KPY[11:0] and
+ * KPX[7:0])
+ * 0: No effect
+ * 1: Clear corresponding interrupt
+ *****************************************************************************/
+#define TC_REG_GPIOIC0 (0xDC)
+#define TC_REG_GPIOIC1 (0xDD)
+#define TC_REG_GPIOIC2 (0xDE)
+
+/******************************************************************************
+ * GPIO OMS Registers
+ *
+ * ODM23:0 : Open Drain Mode Select for DATA23:0 (EXTIO0, PWM[2:0], KPY[11:0]
+ * and KPX[7:0])
+ * 0: Only N-MOS transistor is active in output driver stage.
+ * Output can be driven to GND or HI-Z
+ * 1: Only P-MOS transistor is active in output driver stage.
+ * Output can be driven to VCC or Hi-Z
+ *
+ * ODE23:0: Open Drain Enable for DATA23:0 (EXTIO0, PWM[2:0], KPY[11:0]
+ * and KPX[7:0])
+ * 0: Full buffer
+ * 1: Open Drain Functionality
+ *****************************************************************************/
+#define TC_REG_GPIOOMS0_A (0xE0)
+#define TC_REG_GPIOOMS0_B (0xE1)
+#define TC_REG_GPIOOMS1_A (0xE2)
+#define TC_REG_GPIOOMS1_B (0xE3)
+#define TC_REG_GPIOOMS2_A (0xE4)
+#define TC_REG_GPIOOMS2_B (0xE5)
+
+/******************************************************************************
+ * GPIO Wake Registers
+ *
+ * WAKE23:0 : Each bit corresponds to a ball except WAKE23. WAKE23 is
+ * corresponding DIR25:24 and EXTIO0 balls. When bit set, the
+ * corresponding ball contributes to wake-up from Auto-sleep
+ * mode. When set, the corresponding ball is also used as a trigger
+ * event to the TRIGGER pattern of the Timer module.
+ * 0: Wakeup from Auto-sleep mode on corresponding ball is disabled.
+ * 1: The corresponding ball contributes to wake-up from Auto-Sleep
+ * mode. And, the corresponding ball is also used as a trigger
+ * event to the TRIGGER pattern of the timer module.
+ *****************************************************************************/
+#define TC_REG_GPIOWAKE0 (0xE9)
+#define TC_REG_GPIOWAKE1 (0xEA)
+#define TC_REG_GPIOWAKE2 (0xEB)
+
+/******************************************************************************
+ * Direct Key Event Code register
+ *****************************************************************************/
+#define TC_REG_DEVTCODE (0xE6)
+
+/*
+ * Indicates, whether keyboard event was a key press or a key relese
+ * 0: Key was pressed
+ * 1: Key was released
+ */
+#define TC_VAL_DKEYSTAT (0x01 << 5)
+
+/*
+ * Direct key event code
+ * 0x01: event on KPX0 ball
+ * 0x02: event on KPX1 ball
+ * ...
+ * 0x19: event on DIR24 ball
+ * 0x1A: event on DIR25 ball
+ * 0x1F: event buffer empty
+ */
+#define TC_VAL_DKEYCODE_MASK (0x1F)
+
+/******************************************************************************
+ * Input De-Bounce register
+ *****************************************************************************/
+#define TC_REG_DBOUNCE (0xE8)
+
+/*
+ * Enables de-bouncing feature on general purpose input lines.
+ * Debouncing makes the input lines immune to noise.
+ * 0: No synchronization
+ * 1: Synchronization of the GPIO input lines according the value
+ * conf. in DBOUNCE.
+ */
+#define TC_VAL_DB_SYNC (0x01 << 5)
+
+/*
+ * De-Bounce time for the inputs.
+ * 00: 1.5ms
+ * 01: 3.0ms
+ * 02: 4.5ms
+ * ...
+ * 1F: 48ms
+ */
+#define TC_VAL_DBOUNCE_MASK (0x1F)
+
+/******************************************************************************
+ * Direct Keypad Registers (0-3)
+ *
+ * DIRECT23-0: Direct keypad bits take priority over anything else These bits
+ * must be cleared to '0' before IOCFG is accessed to set other
+ * functions for the pins.
+ * 0: General purpose input/output functionality is active
+ * 1: Direct keypad functionality is active.
+ *****************************************************************************/
+#define TC_REG_DIRECT0 (0xEC)
+#define TC_VAL_DIRECT7 (0x01 << 7)
+#define TC_VAL_DIRECT6 (0x01 << 6)
+#define TC_VAL_DIRECT5 (0x01 << 5)
+#define TC_VAL_DIRECT4 (0x01 << 4)
+#define TC_VAL_DIRECT3 (0x01 << 3)
+#define TC_VAL_DIRECT2 (0x01 << 2)
+#define TC_VAL_DIRECT1 (0x01 << 1)
+#define TC_VAL_DIRECT0 (0x01)
+
+#define TC_REG_DIRECT1 (0xED)
+#define TC_VAL_DIRECT15 (0x01 << 7)
+#define TC_VAL_DIRECT14 (0x01 << 6)
+#define TC_VAL_DIRECT13 (0x01 << 5)
+#define TC_VAL_DIRECT12 (0x01 << 4)
+#define TC_VAL_DIRECT11 (0x01 << 3)
+#define TC_VAL_DIRECT10 (0x01 << 2)
+#define TC_VAL_DIRECT9 (0x01 << 1)
+#define TC_VAL_DIRECT8 (0x01)
+
+#define TC_REG_DIRECT2 (0xEE)
+#define TC_VAL_DIRECT23 (0x01 << 7)
+#define TC_VAL_DIRECT22 (0x01 << 6)
+#define TC_VAL_DIRECT21 (0x01 << 5)
+#define TC_VAL_DIRECT20 (0x01 << 4)
+#define TC_VAL_DIRECT19 (0x01 << 3)
+#define TC_VAL_DIRECT18 (0x01 << 2)
+#define TC_VAL_DIRECT17 (0x01 << 1)
+#define TC_VAL_DIRECT16 (0x01)
+
+#define TC_REG_DIRECT3 (0xEF)
+#define TC_VAL_DIRECT25 (0x01 << 1)
+#define TC_VAL_DIRECT24 (0x01)
+
+/******************************************************************************
+ * Direct Key Raw Interrupt register
+ *****************************************************************************/
+#define TC_REG_DKBDRIS (0xF0)
+
+/*
+ * Raw Event Lost Interrupt
+ * This bit is cleared by writing int DEVTIC
+ * 0: No interrupt
+ * 1: More than 8 direct key events have been detected and
+ * caused the event buffer to overflow.
+ */
+#define TC_VAL_DRELINT (0x01 << 1)
+
+/*
+ * Raw direct key event interrupt
+ * Reading from DEVTCODE until the buffer is empty will automatically clear
+ * this interrupt
+ * 0: No interrupt
+ * 1: At lest one direct key press or direct key release in the event buffer.
+ */
+#define TC_VAL_DREVTINT (0x01)
+
+/******************************************************************************
+ * Direct Key Mask Interrupt register
+ *****************************************************************************/
+#define TC_REG_DKBDMIS (0xF1)
+
+/*
+ * Masked Event Lost Interrupt
+ * 0: No interrupt
+ * 1: More than 8 direct key events have been detected and
+ * and caused the event buffer to overflow.
+ */
+#define TC_VAL_DMELINT (0x01 << 1)
+
+/*
+ * Masked Direct key Event interrupt
+ * 0: No interrupt
+ * 1: At least one direct key press or direct key release is in
+ * the event buffer.
+ */
+#define TC_VAL_DMEVTINT (0x01)
+
+/******************************************************************************
+ * Direct Key Interrupt Clear register
+ *****************************************************************************/
+#define TC_REG_DKBDIC (0xF2)
+
+/*
+ * Clear event buffer an corresponding interrupt DREVTINT and DRELINT
+ * The host does not need to write "0". Write "1" every time when clearing
+ * the event buffer.
+ * 0: No action
+ * 1: Clear event buffer and corresponding interrupts REVTINT and RELINT
+ */
+#define TC_VAL_DEVTIC (0x01)
+
+/******************************************************************************
+ * Direct Key Mask Register
+ *****************************************************************************/
+#define TC_REG_DKBDMSK (0xF3)
+
+/*
+ * Enable keyboard event lost interrupt
+ * 0: Keyboard event lost interrupt is enabled
+ * 1: Keyboard event lost interrupt is disabled
+ */
+#define TC_VAL_DMSKELINT (0x01 << 1)
+
+/* Enable keyboard event interrupt
+ * 0: Keyboard event interrupt is enabled
+ * 1: Keyboard event interrupt is disabled
+ */
+#define TC_VAL_DMSKEINT (0x01)
+
+#endif /* __TC3589XBG_REGS_H */
diff --git a/include/linux/i2c/tc35894xbg.h b/include/linux/i2c/tc35894xbg.h
new file mode 100644
index 00000000000..7e3fec345a8
--- /dev/null
+++ b/include/linux/i2c/tc35894xbg.h
@@ -0,0 +1,72 @@
+/*
+ * tc35894xbg.h - Configuration for TC35894XBG keypad driver.
+ *
+ * (C) Copyright 2010 Intel Corporation
+ * Author: Charlie Paul (z8cpaul@windriver.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifndef __LINUX_TC35894XBG_H
+#define __LINUX_TC35894XBG_H
+
+#include <linux/types.h>
+
+/*
+ * Largest keycode that the chip can send, plus one,
+ * so keys can be mapped directly at the index of the
+ * TC35894XBG keycode instead of subtracting one.
+ */
+#define TC35894XBG_KEYMAP_SIZE (0x7f + 1)
+
+#define SHIFT_NEEDED (0x1000)
+
+#define KEY_EXCLAM (KEY_1 + SHIFT_NEEDED) /* '!' -> shift+1 */
+#define KEY_AT (KEY_2 + SHIFT_NEEDED) /* '@' -> shift+2 */
+#define KEY_NUMBER_SIGN (KEY_3 + SHIFT_NEEDED) /* '#' -> shift+3 */
+#define KEY_DOLLAR_SIGN (KEY_4 + SHIFT_NEEDED) /* '$' -> shift+4 */
+#define KEY_NOR (KEY_6 + SHIFT_NEEDED) /* '^' -> shift+6 */
+#define KEY_PERCENT (KEY_5 + SHIFT_NEEDED) /* '%' -> shift+5 */
+#define KEY_AMPERSAND (KEY_7 + SHIFT_NEEDED) /* '&' -> shift+7 */
+#define KEY_PLUS (KEY_EQUAL + SHIFT_NEEDED) /* '+' -> shift+= */
+
+#define KEY_BAR (KEY_BACKSLASH + SHIFT_NEEDED) /* '|' -> shift+\ */
+#define KEY_COLON (KEY_SEMICOLON + SHIFT_NEEDED) /* ':' -> shift+; */
+#define KEY_UNDERSCORE (KEY_MINUS + SHIFT_NEEDED) /* '_' -> shift+- */
+#define KEY_QUOTE_DBL (KEY_APOSTROPHE + SHIFT_NEEDED) /* '"' -> shift+' */
+
+
+#define TC_MAX_KEYMAPS (2)
+#define TC_DEFAULT_KEYMAP (0)
+#define TC_ALT_KEYMAP (1)
+#define TC35894XBG_MAX_FIFO (8)
+
+
+struct tc35894xbg_platform_data {
+
+ unsigned char debounce_time; /* Time to watch for bouncing, in ms. */
+ unsigned char settle_time; /* Idle time until sleep, in ms. */
+ unsigned char col_setting; /* Sets up ball settings in reg 0x04 */
+ unsigned char rowcol_setting; /* Sets up ball settings in reg 0x05 */
+
+ int gpio_reset; /* reset output GPIO index (-1 if not implemented) */
+ int gpio_irq; /* interrupt GPIO */
+ int keymap_size;
+ int size_x;
+ int size_y;
+ int function_key;
+ int right_shift_key;
+
+ void (*reset_ctrl)(struct i2c_client *client, int value);
+
+ int n_keymaps;
+ unsigned short keymap[TC_MAX_KEYMAPS][TC35894XBG_KEYMAP_SIZE];
+
+ /* Device name. */
+ const char *name;
+};
+
+#endif /* __LINUX_TC35894XBG_H */