input: touchscreen: DirectTouch Synaptics driver
Ali Ekici [Wed, 11 Jan 2012 22:10:13 +0000 (14:10 -0800)]
This is Synaptics' open source driver except one line
change to accomodate an SPI kernel driver feature
which does not accomodate optional byte-delay. It
will be fully original driver when we add byte-delay
into Tegra SPI kernel drivers.

Bug 912775

Reviewed-on: http://git-master/r/74642

Change-Id: I0f39928c48bc0e633de0d2c1f595bcef47268d52
Signed-off-by: Peter Zu <pzu@nvidia.com>
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Reviewed-on: http://git-master/r/77774
Reviewed-by: Automatic_Commit_Validation_User

16 files changed:
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/rmi4/Makefile [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_bus.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_dev.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_driver.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_driver.h [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f01.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f09.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f11.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f19.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f34.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f54.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_i2c.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_spi.c [new file with mode: 0644]
include/linux/rmi.h [new file with mode: 0644]

index a452383..a8fc74f 100644 (file)
@@ -758,4 +758,16 @@ config TOUCHSCREEN_RM31080A
          To compile this driver as a module, choose M here: the
          module will be called RAYDIUM_31080A.
 
+config TOUCHSCREEN_SYN_RMI4_SPI
+       tristate "RMI4 SPI Support"
+       depends on SPI_MASTER
+       help
+         Say Y here if you want to support RMI4 devices connect
+         to an SPI bus.
+
+         If unsure, say Y.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-spi.
+
 endif
index 8a38afe..9c42d21 100644 (file)
@@ -63,3 +63,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)     += zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)      += w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)     += tps6507x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_RM31080A)     += rm31080a_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI)  += rmi4/
diff --git a/drivers/input/touchscreen/rmi4/Makefile b/drivers/input/touchscreen/rmi4/Makefile
new file mode 100644 (file)
index 0000000..a7375ed
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for Synaptics Touchscreen (RMI4/SPI)
+#
+GCOV_PROFILE := y
+
+ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
+
+#Synaptics SPI Sensor (2002)
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_bus.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_spi.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_driver.o rmi_f01.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f09.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f11.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f19.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f34.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f54.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_dev.o
diff --git a/drivers/input/touchscreen/rmi4/rmi_bus.c b/drivers/input/touchscreen/rmi4/rmi_bus.c
new file mode 100644 (file)
index 0000000..6a269df
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/rmi.h>
+
+static struct rmi_function_list {
+       struct list_head list;
+       struct rmi_function_handler *fh;
+} rmi_supported_functions;
+
+static int rmi_bus_match(struct device *dev, struct device_driver *driver)
+{
+       struct rmi_driver *rmi_driver;
+       struct rmi_device *rmi_dev;
+       struct rmi_device_platform_data *pdata;
+
+       pr_info("in function ____%s____  \n", __func__);
+       rmi_driver = to_rmi_driver(driver);
+       rmi_dev = to_rmi_device(dev);
+       pdata = to_rmi_platform_data(rmi_dev);
+
+       pr_info("        rmi_driver->driver.name =  %s\n", rmi_driver->driver.name);
+        pr_info("        device:rmi_device = 0x%x \n", rmi_dev);
+       pr_info("             device:rmi_device:rmi_device_platform_data:driver_name = %s \n", pdata->driver_name);
+        pr_info("                    rmi_device:driver = 0x%x \n", rmi_dev->driver);
+
+       if (!strcmp(pdata->driver_name, rmi_driver->driver.name)) {
+               rmi_dev->driver = rmi_driver;
+               pr_info("             names match, so now rmi_device:driver = 0x%x \n",rmi_dev->driver);
+               return 1;
+       }
+       pr_info("             names DO NOT match, so return nothing \n");
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rmi_bus_suspend(struct device *dev)
+{
+#ifdef GENERIC_SUBSYS_PM_OPS
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+       if (pm && pm->suspend)
+               return pm->suspend(dev);
+#endif
+
+       return 0;
+}
+
+static int rmi_bus_resume(struct device *dev)
+{
+#ifdef GENERIC_SUBSYS_PM_OPS
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       pr_info("in function ____%s____  \n", __func__);
+
+       if (pm && pm->resume)
+               return pm->resume(dev);
+#endif
+
+       return 0;
+}
+#endif
+
+static int rmi_bus_probe(struct device *dev)
+{
+       struct rmi_driver *driver;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
+
+       pr_info("in function ____%s____  \n", __func__);
+       driver = rmi_dev->driver;
+       if (driver && driver->probe)
+               return driver->probe(rmi_dev);
+
+       return 0;
+}
+
+static int rmi_bus_remove(struct device *dev)
+{
+       struct rmi_driver *driver;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
+
+       pr_info("in function ____%s____  \n", __func__);
+       driver = rmi_dev->driver;
+       if (driver && driver->remove)
+               return driver->remove(rmi_dev);
+
+       return 0;
+}
+
+static void rmi_bus_shutdown(struct device *dev)
+{
+       struct rmi_driver *driver;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
+
+       driver = rmi_dev->driver;
+       if (driver && driver->shutdown)
+               driver->shutdown(rmi_dev);
+}
+
+static SIMPLE_DEV_PM_OPS(rmi_bus_pm_ops,
+                        rmi_bus_suspend, rmi_bus_resume);
+
+struct bus_type rmi_bus_type = {
+       .name           = "rmi",
+       .match          = rmi_bus_match,
+       .probe          = rmi_bus_probe,
+       .remove         = rmi_bus_remove,
+       .shutdown       = rmi_bus_shutdown,
+       .pm             = &rmi_bus_pm_ops
+};
+
+int rmi_register_phys_device(struct rmi_phys_device *phys)
+{
+       static int phys_device_num;
+       struct rmi_device_platform_data *pdata = phys->dev->platform_data;
+       struct rmi_device *rmi_dev;
+
+       pr_info("in function ____%s____  \n", __func__);
+
+       if (!pdata) {
+               dev_err(phys->dev, "no platform data!\n");
+               return -EINVAL;
+       }
+
+       rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL);
+       if (!rmi_dev)
+               return -ENOMEM;
+
+       rmi_dev->phys = phys;
+       rmi_dev->dev.bus = &rmi_bus_type;
+       dev_set_name(&rmi_dev->dev, "sensor%02d", phys_device_num++);
+
+       phys->rmi_dev = rmi_dev;
+       pr_info("                 registering physical device:\n");
+       pr_info("                 dev.init_name = \n", rmi_dev->dev.init_name);
+       pr_info("                 dev.bus->name = \n", rmi_dev->dev.bus->name);
+       return device_register(&rmi_dev->dev);
+}
+EXPORT_SYMBOL(rmi_register_phys_device);
+
+void rmi_unregister_phys_device(struct rmi_phys_device *phys)
+{
+       struct rmi_device *rmi_dev = phys->rmi_dev;
+       pr_info("in function ____%s____  \n", __func__);
+
+       device_unregister(&rmi_dev->dev);
+       kfree(rmi_dev);
+}
+EXPORT_SYMBOL(rmi_unregister_phys_device);
+
+int rmi_register_driver(struct rmi_driver *driver)
+{
+       pr_info("in function ____%s____  \n", __func__);
+       driver->driver.bus = &rmi_bus_type;
+       return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL(rmi_register_driver);
+
+static int __rmi_driver_remove(struct device *dev, void *data)
+{
+       struct rmi_driver *driver = data;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
+
+       if (rmi_dev->driver == driver)
+               rmi_dev->driver = NULL;
+
+       return 0;
+}
+
+void rmi_unregister_driver(struct rmi_driver *driver)
+{
+       bus_for_each_dev(&rmi_bus_type, NULL, driver, __rmi_driver_remove);
+       driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL(rmi_unregister_driver);
+
+static int __rmi_bus_fh_add(struct device *dev, void *data)
+{
+       struct rmi_driver *driver;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
+       pr_info("in function ____%s____  \n", __func__);
+
+       driver = rmi_dev->driver;
+       if (driver && driver->fh_add)
+               driver->fh_add(rmi_dev, data);
+
+       return 0;
+}
+
+int rmi_register_function_driver(struct rmi_function_handler *fh)
+{
+       struct rmi_function_list *entry;
+       struct rmi_function_handler *fh_dup;
+
+       fh_dup = rmi_get_function_handler(fh->func);
+       if (fh_dup) {
+               pr_err("%s: function f%.2x already registered!\n", __func__,
+                       fh->func);
+               return -EINVAL;
+       }
+
+       entry = kzalloc(sizeof(struct rmi_function_list), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       entry->fh = fh;
+       list_add_tail(&entry->list, &rmi_supported_functions.list);
+
+       /* notify devices of the new function handler */
+       bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_add);
+
+       return 0;
+}
+EXPORT_SYMBOL(rmi_register_function_driver);
+
+static int __rmi_bus_fh_remove(struct device *dev, void *data)
+{
+       struct rmi_driver *driver;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
+
+       pr_info("in function ____%s____  \n", __func__);
+       driver = rmi_dev->driver;
+       if (driver && driver->fh_remove)
+               driver->fh_remove(rmi_dev, data);
+
+       return 0;
+}
+
+void rmi_unregister_function_driver(struct rmi_function_handler *fh)
+{
+       struct rmi_function_list *entry, *n;
+       pr_info("in function ____%s____  \n", __func__);
+
+       /* notify devices of the removal of the function handler */
+       bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_remove);
+
+       list_for_each_entry_safe(entry, n, &rmi_supported_functions.list, list)
+               if (entry->fh->func == fh->func) {
+                       list_del(&entry->list);
+                       kfree(entry);
+               }
+}
+EXPORT_SYMBOL(rmi_unregister_function_driver);
+
+struct rmi_function_handler *rmi_get_function_handler(int id)
+{
+       struct rmi_function_list *entry;
+       pr_info("in function ____%s____  \n", __func__);
+
+       list_for_each_entry(entry, &rmi_supported_functions.list, list)
+               if (entry->fh->func == id)
+                       return entry->fh;
+
+       return NULL;
+}
+EXPORT_SYMBOL(rmi_get_function_handler);
+
+static int __init rmi_bus_init(void)
+{
+       int error;
+
+       pr_info("in function ____%s____  \n", __func__);
+       INIT_LIST_HEAD(&rmi_supported_functions.list);
+
+       error = bus_register(&rmi_bus_type);
+       if (error < 0) {
+               pr_err("%s: error registering the RMI bus: %d\n", __func__,
+                      error);
+               return error;
+       }
+       pr_info("%s: successfully registered RMI bus.\n", __func__);
+
+       return 0;
+}
+
+static void __exit rmi_bus_exit(void)
+{
+       struct rmi_function_list *entry, *n;
+       pr_info("in function ____%s____  \n", __func__);
+
+       list_for_each_entry_safe(entry, n, &rmi_supported_functions.list,
+                                list) {
+               list_del(&entry->list);
+               kfree(entry);
+       }
+
+       bus_unregister(&rmi_bus_type);
+}
+
+module_init(rmi_bus_init);
+module_exit(rmi_bus_exit);
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("RMI bus");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi4/rmi_dev.c b/drivers/input/touchscreen/rmi4/rmi_dev.c
new file mode 100644 (file)
index 0000000..fa21ef9
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/syscalls.h>
+
+#include <linux/rmi.h>
+#include "rmi_driver.h"
+
+#define CHAR_DEVICE_NAME "rmi"
+
+#define REG_ADDR_LIMIT 0xFFFF
+
+/*store dynamically allocated major number of char device*/
+static int rmi_char_dev_major_num;
+
+
+/* file operations for RMI char device */
+
+/*
+ * rmi_char_dev_llseek: - use to setup register address
+ *
+ * @filp: file structure for seek
+ * @off: offset
+ *       if whence == SEEK_SET,
+ *       high 16 bits: page address
+ *       low 16 bits: register address
+ *
+ *       if whence == SEEK_CUR,
+ *       offset from current position
+ *
+ *       if whence == SEEK_END,
+ *       offset from END(0xFFFF)
+ *
+ * @whence: SEEK_SET , SEEK_CUR or SEEK_END
+ */
+static loff_t rmi_char_dev_llseek(struct file *filp, loff_t off, int whence)
+{
+       loff_t newpos;
+       struct rmi_char_dev *my_char_dev = filp->private_data;
+
+       if (IS_ERR(my_char_dev)) {
+               pr_err("%s: pointer of char device is invalid", __func__);
+               return -EBADF;
+       }
+
+       mutex_lock(&(my_char_dev->mutex_file_op));
+
+       switch (whence) {
+       case SEEK_SET:
+               newpos = off;
+               break;
+
+       case SEEK_CUR:
+               newpos = filp->f_pos + off;
+               break;
+
+       case SEEK_END:
+               newpos = REG_ADDR_LIMIT + off;
+               break;
+
+       default:                /* can't happen */
+               newpos = -EINVAL;
+               goto clean_up;
+       }
+
+       if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
+               dev_err(my_char_dev->phys->dev, "newpos 0x%04x is invalid.\n",
+                       (unsigned int)newpos);
+               newpos = -EINVAL;
+               goto clean_up;
+       }
+
+       filp->f_pos = newpos;
+
+clean_up:
+       mutex_unlock(&(my_char_dev->mutex_file_op));
+       return newpos;
+}
+
+/*
+ *  rmi_char_dev_read: - use to read data from RMI stream
+ *
+ *  @filp: file structure for read
+ *  @buf: user-level buffer pointer
+ *
+ *  @count: number of byte read
+ *  @f_pos: offset (starting register address)
+ *
+ *     @return number of bytes read into user buffer (buf) if succeeds
+ *          negative number if error occurs.
+ */
+static ssize_t rmi_char_dev_read(struct file *filp, char __user *buf,
+               size_t count, loff_t *f_pos)
+{
+       struct rmi_char_dev *my_char_dev = filp->private_data;
+       ssize_t ret_value  = 0;
+       unsigned char tmpbuf[count+1];
+       struct rmi_phys_device *phys;
+
+       /* limit offset to REG_ADDR_LIMIT-1 */
+       if (count > (REG_ADDR_LIMIT - *f_pos))
+               count = REG_ADDR_LIMIT - *f_pos;
+
+       if (count == 0)
+               return 0;
+
+       if (IS_ERR(my_char_dev)) {
+               pr_err("%s: pointer of char device is invalid", __func__);
+               ret_value = -EBADF;
+               return ret_value;
+       }
+
+       mutex_lock(&(my_char_dev->mutex_file_op));
+
+       phys = my_char_dev->phys;
+       /*
+        * just let it go through , because we do not know the register is FIFO
+        * register or not
+        */
+
+       ret_value = phys->read_block(phys, *f_pos, tmpbuf, count);
+
+       if (ret_value < 0)
+               goto clean_up;
+       else
+               *f_pos += ret_value;
+
+       if (copy_to_user(buf, tmpbuf, count))
+               ret_value = -EFAULT;
+
+clean_up:
+
+       mutex_unlock(&(my_char_dev->mutex_file_op));
+
+       return ret_value;
+}
+
+/*
+ * rmi_char_dev_write: - use to write data into RMI stream
+ *
+ * @filep : file structure for write
+ * @buf: user-level buffer pointer contains data to be written
+ * @count: number of byte be be written
+ * @f_pos: offset (starting register address)
+ *
+ * @return number of bytes written from user buffer (buf) if succeeds
+ *         negative number if error occurs.
+ */
+static ssize_t rmi_char_dev_write(struct file *filp, const char __user *buf,
+               size_t count, loff_t *f_pos)
+{
+       struct rmi_char_dev *my_char_dev = filp->private_data;
+       ssize_t ret_value  = 0;
+       unsigned char tmpbuf[count+1];
+       struct rmi_phys_device *phys;
+
+       /* limit offset to REG_ADDR_LIMIT-1 */
+       if (count > (REG_ADDR_LIMIT - *f_pos))
+               count = REG_ADDR_LIMIT - *f_pos;
+
+       if (count == 0)
+               return 0;
+
+       if (IS_ERR(my_char_dev)) {
+               pr_err("%s: pointer of char device is invalid", __func__);
+               ret_value = -EBADF;
+               return ret_value;
+       }
+
+       if (copy_from_user(tmpbuf, buf, count)) {
+               ret_value = -EFAULT;
+               return ret_value;
+       }
+
+       mutex_lock(&(my_char_dev->mutex_file_op));
+
+       phys = my_char_dev->phys;
+       /*
+        * just let it go through , because we do not know the register is FIFO
+        * register or not
+        */
+
+       ret_value = phys->write_block(phys, *f_pos, tmpbuf, count);
+
+       if (ret_value >= 0)
+               *f_pos += count;
+
+       mutex_unlock(&(my_char_dev->mutex_file_op));
+
+       return ret_value;
+}
+
+/*
+ * rmi_char_dev_open: - get a new handle for from RMI stream
+ * @inp : inode struture
+ * @filp: file structure for read/write
+ *
+ * @return 0 if succeeds
+ */
+static int rmi_char_dev_open(struct inode *inp, struct file *filp)
+{
+       /* store the device pointer to file structure */
+       struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
+                       struct rmi_char_dev, main_dev);
+       struct rmi_phys_device *phys = my_dev->phys;
+       int ret_value = 0;
+
+       filp->private_data = my_dev;
+
+       if (!phys)
+               return -EACCES;
+
+       mutex_lock(&(my_dev->mutex_file_op));
+       if (my_dev->ref_count < 1)
+               my_dev->ref_count++;
+       else
+               ret_value = -EACCES;
+
+       mutex_unlock(&(my_dev->mutex_file_op));
+
+       return ret_value;
+}
+
+/*
+ *  rmi_char_dev_release: - release an existing handle
+ *  @inp: inode structure
+ *  @filp: file structure for read/write
+ *
+ *  @return 0 if succeeds
+ */
+static int rmi_char_dev_release(struct inode *inp, struct file *filp)
+{
+       struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
+                       struct rmi_char_dev, main_dev);
+       struct rmi_phys_device *phys = my_dev->phys;
+
+       if (!phys)
+               return -EACCES;
+
+       mutex_lock(&(my_dev->mutex_file_op));
+
+       my_dev->ref_count--;
+       if (my_dev->ref_count < 0)
+               my_dev->ref_count = 0;
+
+       mutex_unlock(&(my_dev->mutex_file_op));
+
+       return 0;
+}
+
+static const struct file_operations rmi_char_dev_fops = {
+       .owner =    THIS_MODULE,
+       .llseek =   rmi_char_dev_llseek,
+       .read =     rmi_char_dev_read,
+       .write =    rmi_char_dev_write,
+       .open =     rmi_char_dev_open,
+       .release =  rmi_char_dev_release,
+};
+
+/*
+ * rmi_char_dev_clean_up - release memory or unregister driver
+ * @rmi_char_dev: rmi_char_dev structure
+ *
+ */
+static void rmi_char_dev_clean_up(struct rmi_char_dev *char_dev,
+                       struct class *char_device_class)
+{
+       dev_t devno;
+
+       /* Get rid of our char dev entries */
+       if (char_dev) {
+               devno = char_dev->main_dev.dev;
+
+               cdev_del(&char_dev->main_dev);
+               kfree(char_dev);
+
+               if (char_device_class) {
+                       device_destroy(char_device_class, devno);
+                       class_unregister(char_device_class);
+                       class_destroy(char_device_class);
+               }
+
+               /* cleanup_module is never called if registering failed */
+               unregister_chrdev_region(devno, 1);
+               pr_debug("%s: rmi_char_dev is removed\n", __func__);
+       }
+}
+
+/*
+ * rmi_char_devnode - return device permission
+ *
+ * @dev: char device structure
+ * @mode: file permission
+ *
+ */
+static char *rmi_char_devnode(struct device *dev, mode_t *mode)
+{
+       if (!mode)
+               return NULL;
+       /* rmi** */
+       /**mode = 0666*/
+       *mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+
+       return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
+}
+
+/*
+ * rmi_char_dev_register - register char device (called from up-level)
+ *
+ * @phy: a pointer to an rmi_phys_devices structure
+ *
+ * @return: zero if suceeds
+ */
+int rmi_char_dev_register(struct rmi_phys_device *phys)
+{
+       struct rmi_char_dev *char_dev;
+       dev_t dev_no;
+       int err;
+       int result;
+       struct device *device_ptr;
+
+       if (rmi_char_dev_major_num) {
+               dev_no = MKDEV(rmi_char_dev_major_num, 0);
+               result = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
+       } else {
+               result = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
+               /* let kernel allocate a major for us */
+               rmi_char_dev_major_num = MAJOR(dev_no);
+               dev_info(phys->dev, "Major number of rmi_char_dev: %d\n",
+                                rmi_char_dev_major_num);
+       }
+       if (result < 0)
+               return result;
+
+       char_dev = kzalloc(sizeof(struct rmi_char_dev), GFP_KERNEL);
+       if (!char_dev) {
+               dev_err(phys->dev, "Failed to allocate rmi_char_dev.\n");
+               /* unregister the char device region */
+               __unregister_chrdev(rmi_char_dev_major_num, MINOR(dev_no), 1,
+                               CHAR_DEVICE_NAME);
+               return -ENOMEM;
+       }
+
+       mutex_init(&char_dev->mutex_file_op);
+
+       phys->char_dev = char_dev;
+       char_dev->phys = phys;
+
+       cdev_init(&char_dev->main_dev, &rmi_char_dev_fops);
+
+       err = cdev_add(&char_dev->main_dev, dev_no, 1);
+       if (err) {
+               dev_err(phys->dev, "Error %d adding rmi_char_dev.\n", err);
+               rmi_char_dev_clean_up(phys->char_dev,
+                                phys->rmi_char_device_class);
+               return err;
+       }
+
+       /* create device node */
+       phys->rmi_char_device_class =
+               class_create(THIS_MODULE, CHAR_DEVICE_NAME);
+
+       if (IS_ERR(phys->rmi_char_device_class)) {
+               dev_err(phys->dev, "Failed to create /dev/%s.\n",
+                       CHAR_DEVICE_NAME);
+               rmi_char_dev_clean_up(phys->char_dev,
+                                phys->rmi_char_device_class);
+               return -ENODEV;
+       }
+       /* setup permission */
+       phys->rmi_char_device_class->devnode = rmi_char_devnode;
+
+       /* class creation */
+       device_ptr = device_create(
+                       phys->rmi_char_device_class,
+                       NULL, dev_no, NULL,
+                       CHAR_DEVICE_NAME"%d",
+                       MINOR(dev_no));
+
+       if (IS_ERR(device_ptr)) {
+               dev_err(phys->dev, "Failed to create rmi device.\n");
+               rmi_char_dev_clean_up(phys->char_dev,
+                                phys->rmi_char_device_class);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(rmi_char_dev_register);
+
+/* rmi_char_dev_unregister - unregister char device (called from up-level)
+ *
+ * @phys: pointer to an rmi_phys_device structure
+ */
+
+void rmi_char_dev_unregister(struct rmi_phys_device *phys)
+{
+       /* clean up */
+       if (phys)
+               rmi_char_dev_clean_up(phys->char_dev,
+                                phys->rmi_char_device_class);
+}
+EXPORT_SYMBOL(rmi_char_dev_unregister);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Char Device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi4/rmi_driver.c b/drivers/input/touchscreen/rmi4/rmi_driver.c
new file mode 100644 (file)
index 0000000..6aeb3b9
--- /dev/null
@@ -0,0 +1,1354 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * This driver adds support for generic RMI4 devices from Synpatics. It
+ * implements the mandatory f01 RMI register and depends on the presence of
+ * other required RMI functions.
+ *
+ * The RMI4 specification can be found here (URL split after files/ for
+ * style reasons):
+ * http://www.synaptics.com/sites/default/files/
+ *           511-000136-01-Rev-E-RMI4%20Intrfacing%20Guide.pdf
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/rmi.h>
+#include "rmi_driver.h"
+
+#define DELAY_DEBUG 0
+#define REGISTER_DEBUG 0
+
+#define PDT_END_SCAN_LOCATION  0x0005
+#define PDT_PROPERTIES_LOCATION 0x00EF
+#define BSR_LOCATION 0x00FE
+#define HAS_BSR_MASK 0x20
+#define HAS_NONSTANDARD_PDT_MASK 0x40
+#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
+#define RMI4_MAX_PAGE 0xff
+#define RMI4_PAGE_SIZE 0x100
+
+#define RMI_DEVICE_RESET_CMD   0x01
+#define INITIAL_RESET_WAIT_MS  20
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void rmi_driver_early_suspend(struct early_suspend *h);
+static void rmi_driver_late_resume(struct early_suspend *h);
+#endif
+
+
+/* sysfs files for attributes for driver values. */
+static ssize_t rmi_driver_hasbsr_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_driver_bsr_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_driver_bsr_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count);
+
+static ssize_t rmi_driver_enabled_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf);
+
+static ssize_t rmi_driver_enabled_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count);
+
+static ssize_t rmi_driver_phys_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf);
+
+static ssize_t rmi_driver_version_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf);
+
+#if REGISTER_DEBUG
+static ssize_t rmi_driver_reg_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count);
+#endif
+
+#if DELAY_DEBUG
+static ssize_t rmi_delay_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf);
+
+static ssize_t rmi_delay_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count);
+#endif
+
+static struct device_attribute attrs[] = {
+       __ATTR(hasbsr, RMI_RO_ATTR,
+              rmi_driver_hasbsr_show, rmi_store_error),
+       __ATTR(bsr, RMI_RW_ATTR,
+              rmi_driver_bsr_show, rmi_driver_bsr_store),
+       __ATTR(enabled, RMI_RW_ATTR,
+              rmi_driver_enabled_show, rmi_driver_enabled_store),
+       __ATTR(phys, RMI_RO_ATTR,
+              rmi_driver_phys_show, rmi_store_error),
+#if REGISTER_DEBUG
+       __ATTR(reg, RMI_WO_ATTR,
+              rmi_show_error, rmi_driver_reg_store),
+#endif
+#if DELAY_DEBUG
+       __ATTR(delay, RMI_RW_ATTR,
+              rmi_delay_show, rmi_delay_store),
+#endif
+       __ATTR(version, RMI_RO_ATTR,
+              rmi_driver_version_show, rmi_store_error),
+};
+
+
+/*
+** ONLY needed for POLLING mode of the driver
+*/
+struct rmi_device *polled_synaptics_rmi_device = NULL;
+EXPORT_SYMBOL(polled_synaptics_rmi_device);
+
+/* Useful helper functions for u8* */
+
+void u8_set_bit(u8 *target, int pos)
+{
+       target[pos/8] |= 1<<pos%8;
+}
+
+void u8_clear_bit(u8 *target, int pos)
+{
+       target[pos/8] &= ~(1<<pos%8);
+}
+
+bool u8_is_set(u8 *target, int pos)
+{
+       return target[pos/8] & 1<<pos%8;
+}
+
+bool u8_is_any_set(u8 *target, int size)
+{
+       int i;
+       for (i = 0; i < size; i++) {
+               if (target[i])
+                       return true;
+       }
+       return false;
+}
+
+void u8_or(u8 *dest, u8 *target1, u8 *target2, int size)
+{
+       int i;
+       for (i = 0; i < size; i++)
+               dest[i] = target1[i] | target2[i];
+}
+
+void u8_and(u8 *dest, u8 *target1, u8 *target2, int size)
+{
+       int i;
+       for (i = 0; i < size; i++)
+               dest[i] = target1[i] & target2[i];
+}
+
+/* Helper fn to convert a byte array representing a short in the RMI
+ * endian-ness to a short in the native processor's specific endianness.
+ * We don't use ntohs/htons here because, well, we're not dealing with
+ * a pair of shorts. And casting dest to short* wouldn't work, because
+ * that would imply knowing the byte order of short in the first place.
+ */
+void batohs(unsigned short *dest, unsigned char *src)
+{
+       *dest = src[1] * 0x100 + src[0];
+}
+
+/* Helper function to convert a short (in host processor endianess) to
+ * a byte array in the RMI endianess for shorts.  See above comment for
+ * why we dont us htons or something like that.
+ */
+void hstoba(unsigned char *dest, unsigned short src)
+{
+       dest[0] = src % 0x100;
+       dest[1] = src / 0x100;
+}
+
+static bool has_bsr(struct rmi_driver_data *data)
+{
+       return (data->pdt_props & HAS_BSR_MASK) != 0;
+}
+
+/* Utility routine to set bits in a register. */
+int rmi_set_bits(struct rmi_device *rmi_dev, unsigned short address,
+                unsigned char bits)
+{
+       unsigned char reg_contents;
+       int retval;
+
+       retval = rmi_read_block(rmi_dev, address, &reg_contents, 1);
+       if (retval)
+               return retval;
+       reg_contents = reg_contents | bits;
+       retval = rmi_write_block(rmi_dev, address, &reg_contents, 1);
+       if (retval == 1)
+               return 0;
+       else if (retval == 0)
+               return -EIO;
+       return retval;
+}
+EXPORT_SYMBOL(rmi_set_bits);
+
+/* Utility routine to clear bits in a register. */
+int rmi_clear_bits(struct rmi_device *rmi_dev, unsigned short address,
+                  unsigned char bits)
+{
+       unsigned char reg_contents;
+       int retval;
+
+       retval = rmi_read_block(rmi_dev, address, &reg_contents, 1);
+       if (retval)
+               return retval;
+       reg_contents = reg_contents & ~bits;
+       retval = rmi_write_block(rmi_dev, address, &reg_contents, 1);
+       if (retval == 1)
+               return 0;
+       else if (retval == 0)
+               return -EIO;
+       return retval;
+}
+EXPORT_SYMBOL(rmi_clear_bits);
+
+static void rmi_free_function_list(struct rmi_device *rmi_dev)
+{
+       struct rmi_function_container *entry, *n;
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+
+       list_for_each_entry_safe(entry, n, &data->rmi_functions.list, list) {
+               kfree(entry->irq_mask);
+               list_del(&entry->list);
+       }
+}
+
+static int init_one_function(struct rmi_device *rmi_dev,
+                            struct rmi_function_container *fc)
+{
+       int retval;
+
+       dev_info(&rmi_dev->dev, "Initializing F%02X.\n",
+                       fc->fd.function_number);
+       dev_dbg(&rmi_dev->dev, "Initializing F%02X.\n",
+                       fc->fd.function_number);
+
+       if (!fc->fh) {
+               struct rmi_function_handler *fh =
+                       rmi_get_function_handler(fc->fd.function_number);
+               if (!fh) {
+                       dev_dbg(&rmi_dev->dev, "No handler for F%02X.\n",
+                               fc->fd.function_number);
+                       return 0;
+               }
+               fc->fh = fh;
+       }
+
+       if (!fc->fh->init)
+               return 0;
+
+       dev_set_name(&(fc->dev), "fn%02x", fc->fd.function_number);
+
+       fc->dev.parent = &rmi_dev->dev;
+
+       retval = device_register(&fc->dev);
+       if (retval) {
+               dev_err(&rmi_dev->dev, "Failed device_register for F%02X.\n",
+                       fc->fd.function_number);
+               return retval;
+       }
+
+       retval = fc->fh->init(fc);
+       if (retval < 0) {
+               dev_err(&rmi_dev->dev, "Failed to initialize function F%02x\n",
+                       fc->fd.function_number);
+               goto error_exit;
+       }
+
+       return 0;
+
+error_exit:
+       device_unregister(&fc->dev);
+       return retval;
+}
+
+static void rmi_driver_fh_add(struct rmi_device *rmi_dev,
+                             struct rmi_function_handler *fh)
+{
+       struct rmi_function_container *entry;
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+
+       if (fh->func == 0x01)
+               data->f01_container->fh = fh;
+       else {
+               list_for_each_entry(entry, &data->rmi_functions.list, list)
+                       if (entry->fd.function_number == fh->func) {
+                               entry->fh = fh;
+                               init_one_function(rmi_dev, entry);
+                       }
+       }
+
+}
+
+static void rmi_driver_fh_remove(struct rmi_device *rmi_dev,
+                                struct rmi_function_handler *fh)
+{
+       struct rmi_function_container *entry;
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+
+       list_for_each_entry(entry, &data->rmi_functions.list, list)
+               if (entry->fd.function_number == fh->func) {
+                       if (fh->remove)
+                               fh->remove(entry);
+
+                       entry->fh = NULL;
+               }
+}
+
+static void construct_mask(u8 *mask, int num, int pos)
+{
+       int i;
+
+       for (i = 0; i < num; i++)
+               u8_set_bit(mask, pos+i);
+}
+
+static int process_interrupt_requests(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct device *dev = &rmi_dev->dev;
+       struct rmi_function_container *entry;
+       u8 irq_status[data->num_of_irq_regs];
+       u8 irq_bits[data->num_of_irq_regs];
+       int error;
+
+       error = rmi_read_block(rmi_dev,
+                               data->f01_container->fd.data_base_addr + 1,
+                               irq_status, data->num_of_irq_regs);
+       if (error < 0) {
+               dev_err(dev, "%s: failed to read irqs.", __func__);
+               return error;
+       }
+       /* Device control (F01) is handled before anything else. */
+       u8_and(irq_bits, irq_status, data->f01_container->irq_mask,
+                       data->num_of_irq_regs);
+       if (u8_is_any_set(irq_bits, data->num_of_irq_regs))
+               data->f01_container->fh->attention(
+                               data->f01_container, irq_bits);
+
+       //dev_info(dev, "  irq_status = 0x%2x data->current_irq_mask = 0x%2x data->num_of_irq_regs = %d\n",
+       //       irq_status[0], data->current_irq_mask[0], data->num_of_irq_regs );
+
+
+       u8_and(irq_status, irq_status, data->current_irq_mask,
+              data->num_of_irq_regs);
+
+       /* At this point, irq_status has all bits that are set in the
+        * interrupt status register and are enabled.
+        */
+
+       list_for_each_entry(entry, &data->rmi_functions.list, list){
+               if (entry->irq_mask && entry->fh && entry->fh->attention) {
+
+                       u8_and(irq_bits, irq_status, entry->irq_mask,
+                              data->num_of_irq_regs);
+                       if (u8_is_any_set(irq_bits, data->num_of_irq_regs)) {
+                               error = entry->fh->attention(entry, irq_bits);
+                               if (error < 0)
+                                       dev_err(dev, "%s: f%.2x"
+                                               " attention handler failed:"
+                                               " %d\n", __func__,
+                                               entry->fh->func, error);
+                       }
+               }
+       }
+       return 0;
+}
+
+
+static int rmi_driver_irq_handler(struct rmi_device *rmi_dev, int irq)
+{
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+
+       /* Can get called before the driver is fully ready to deal with
+        * interrupts.
+        */
+       if (!data || !data->f01_container || !data->f01_container->fh) {
+               dev_warn(&rmi_dev->dev,
+                        "Not ready to handle interrupts yet!\n");
+               return 0;
+       }
+
+       return process_interrupt_requests(rmi_dev);
+}
+
+/*
+ * Construct a function's IRQ mask. This should
+ * be called once and stored.
+ */
+static u8 *rmi_driver_irq_get_mask(struct rmi_device *rmi_dev,
+                                  struct rmi_function_container *fc) {
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+
+       /* TODO: Where should this be freed? */
+       u8 *irq_mask = kzalloc(sizeof(u8) * data->num_of_irq_regs, GFP_KERNEL);
+       if (irq_mask)
+               construct_mask(irq_mask, fc->num_of_irqs, fc->irq_pos);
+
+       return irq_mask;
+}
+
+/*
+ * This pair of functions allows functions like function 54 to request to have
+ * other interupts disabled until the restore function is called. Only one store
+ * happens at a time.
+ */
+static int rmi_driver_irq_save(struct rmi_device *rmi_dev, u8 * new_ints)
+{
+       int retval = 0;
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct device *dev = &rmi_dev->dev;
+
+       mutex_lock(&data->irq_mutex);
+       if (!data->irq_stored) {
+               /* Save current enabled interupts */
+               retval = rmi_read_block(rmi_dev,
+                               data->f01_container->fd.control_base_addr+1,
+                               data->irq_mask_store, data->num_of_irq_regs);
+               if (retval < 0) {
+                       dev_err(dev, "%s: Failed to read enabled interrupts!",
+                                                               __func__);
+                       goto error_unlock;
+               }
+               /*
+                * Disable every interupt except for function 54
+                * TODO:Will also want to not disable function 1-like functions.
+                * No need to take care of this now, since there's no good way
+                * to identify them.
+                */
+               retval = rmi_write_block(rmi_dev,
+                               data->f01_container->fd.control_base_addr+1,
+                               new_ints, data->num_of_irq_regs);
+               if (retval < 0) {
+                       dev_err(dev, "%s: Failed to change enabled interrupts!",
+                                                               __func__);
+                       goto error_unlock;
+               }
+               memcpy(data->current_irq_mask, new_ints,
+                                       data->num_of_irq_regs * sizeof(u8));
+               data->irq_stored = true;
+       } else {
+               retval = -ENOSPC; /* No space to store IRQs.*/
+               dev_err(dev, "%s: Attempted to save values when"
+                                               " already stored!", __func__);
+       }
+
+error_unlock:
+       mutex_unlock(&data->irq_mutex);
+       return retval;
+}
+
+static int rmi_driver_irq_restore(struct rmi_device *rmi_dev)
+{
+       int retval = 0;
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct device *dev = &rmi_dev->dev;
+       mutex_lock(&data->irq_mutex);
+
+       if (data->irq_stored) {
+               retval = rmi_write_block(rmi_dev,
+                               data->f01_container->fd.control_base_addr+1,
+                               data->irq_mask_store, data->num_of_irq_regs);
+               if (retval < 0) {
+                       dev_err(dev, "%s: Failed to write enabled interupts!",
+                                                               __func__);
+                       goto error_unlock;
+               }
+               memcpy(data->current_irq_mask, data->irq_mask_store,
+                                       data->num_of_irq_regs * sizeof(u8));
+               data->irq_stored = false;
+       } else {
+               retval = -EINVAL;
+               dev_err(dev, "%s: Attempted to restore values when not stored!",
+                       __func__);
+       }
+
+error_unlock:
+       mutex_unlock(&data->irq_mutex);
+       return retval;
+}
+
+static int rmi_driver_fn_01_specific(struct rmi_device *rmi_dev,
+                                    struct pdt_entry *pdt_ptr,
+                                    int *current_irq_count,
+                                    u16 page_start)
+{
+       struct rmi_driver_data *data = NULL;
+       struct rmi_function_container *fc = NULL;
+       int retval = 0;
+       struct device *dev = &rmi_dev->dev;
+       struct rmi_function_handler *fh =
+               rmi_get_function_handler(0x01);
+
+       data = rmi_get_driverdata(rmi_dev);
+
+       dev_info(dev, "%s: Found F01, initializing.\n", __func__);
+       if (!fh)
+               dev_dbg(dev, "%s: No function handler for F01?!", __func__);
+
+       fc = kzalloc(sizeof(struct rmi_function_container), GFP_KERNEL);
+       if (!fc) {
+               retval = -ENOMEM;
+               return retval;
+       }
+
+       copy_pdt_entry_to_fd(pdt_ptr, &fc->fd, page_start);
+       fc->num_of_irqs = pdt_ptr->interrupt_source_count;
+       fc->irq_pos = *current_irq_count;
+
+       *current_irq_count += fc->num_of_irqs;
+
+       fc->rmi_dev        = rmi_dev;
+       fc->dev.parent     = &fc->rmi_dev->dev;
+       fc->fh = fh;
+
+       dev_set_name(&(fc->dev), "fn%02x", fc->fd.function_number);
+
+       retval = device_register(&fc->dev);
+       if (retval) {
+               dev_err(dev, "%s: Failed device_register for F01.\n", __func__);
+               goto error_free_data;
+       }
+
+       data->f01_container = fc;
+
+       return retval;
+
+error_free_data:
+       kfree(fc);
+       return retval;
+}
+
+/*
+ * Scan the PDT for F01 so we can force a reset before anything else
+ * is done.  This forces the sensor into a known state, and also
+ * forces application of any pending updates from reflashing the
+ * firmware or configuration.  We have to do this before actually
+ * building the PDT because the reflash might cause various registers
+ * to move around.
+ */
+static int do_initial_reset(struct rmi_device* rmi_dev)
+{
+       struct pdt_entry pdt_entry;
+       int page;
+       struct device *dev = &rmi_dev->dev;
+       bool done = false;
+       int i;
+       int retval;
+
+       pr_info("in function ____%s____  \n", __func__);
+
+       polled_synaptics_rmi_device = rmi_dev;
+
+       for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
+
+               u16 page_start = RMI4_PAGE_SIZE * page;
+               u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
+               u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
+               pr_info("               reading page = %d\n", page );
+               done = true;
+               for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) {
+
+                       pr_info("               reading PDT entry %3d (block %3d)\n",
+                               i%sizeof(pdt_entry), i);
+
+                       retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry,
+                                              sizeof(pdt_entry));
+                       if (retval != sizeof(pdt_entry)) {
+                               dev_err(dev, "Read PDT entry at 0x%04x"
+                                       "failed, code = %d.\n", i, retval);
+                               return retval;
+                       }
+
+                       if (RMI4_END_OF_PDT(pdt_entry.function_number))
+                               break;
+                       done = false;
+
+                       if (pdt_entry.function_number == 0x01) {
+                               u16 cmd_addr = page_start +
+                                       pdt_entry.command_base_addr;
+                               u8 cmd_buf = RMI_DEVICE_RESET_CMD;
+                               retval = rmi_write_block(rmi_dev, cmd_addr,
+                                               &cmd_buf, 1);
+                               if (retval < 0) {
+                                       dev_err(dev, "Initial reset failed. "
+                                               "Code = %d.\n", retval);
+                                       return retval;
+                               }
+                               mdelay(INITIAL_RESET_WAIT_MS);
+                               return 0;
+                       }
+               }
+       }
+
+       dev_warn(dev, "WARNING: Failed to find F01 for initial reset.\n");
+       return -ENODEV;
+}
+
+
+static int rmi_scan_pdt(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data;
+       struct rmi_function_container *fc;
+       struct pdt_entry pdt_entry;
+       int page;
+       struct device *dev = &rmi_dev->dev;
+       int irq_count = 0;
+       bool done = false;
+       int i;
+       int retval;
+        pr_info("in function ____%s____  \n", __func__);
+        pr_info("   doing initial reset  \n");
+
+       retval = do_initial_reset(rmi_dev);
+        pr_info("   back in %s  \n", __func__);
+
+       if (retval)
+               dev_err(dev, "WARNING: Initial reset failed! Soldiering on.\n");
+
+       data = rmi_get_driverdata(rmi_dev);
+
+       INIT_LIST_HEAD(&data->rmi_functions.list);
+
+       /* parse the PDT */
+       for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
+               u16 page_start = RMI4_PAGE_SIZE * page;
+               u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
+               u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
+
+               done = true;
+               for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) {
+                       retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry,
+                                              sizeof(pdt_entry));
+                       if (retval != sizeof(pdt_entry)) {
+                               dev_err(dev, "Read PDT entry at 0x%04x"
+                                       "failed.\n", i);
+                               goto error_exit;
+                       }
+
+                       if (RMI4_END_OF_PDT(pdt_entry.function_number))
+                               break;
+
+                       dev_dbg(dev, "%s: Found F%.2X on page 0x%02X\n",
+                               __func__, pdt_entry.function_number, page);
+                       done = false;
+
+                       /*
+                        * F01 is handled by rmi_driver. Hopefully we will get
+                        * rid of the special treatment of f01 at some point
+                        * in time.
+                        */
+                       if (pdt_entry.function_number == 0x01) {
+                               retval = rmi_driver_fn_01_specific(rmi_dev,
+                                               &pdt_entry, &irq_count,
+                                               page_start);
+                               if (retval)
+                                       goto error_exit;
+                               continue;
+                       }
+
+                       fc = kzalloc(sizeof(struct rmi_function_container),
+                                    GFP_KERNEL);
+                       if (!fc) {
+                               dev_err(dev, "Failed to allocate function "
+                                       "container for F%02X.\n",
+                                       pdt_entry.function_number);
+                               retval = -ENOMEM;
+                               goto error_exit;
+                       }
+
+                       copy_pdt_entry_to_fd(&pdt_entry, &fc->fd, page_start);
+
+                       fc->rmi_dev = rmi_dev;
+                       fc->num_of_irqs = pdt_entry.interrupt_source_count;
+                       fc->irq_pos = irq_count;
+                       irq_count += fc->num_of_irqs;
+
+                       retval = init_one_function(rmi_dev, fc);
+                       if (retval < 0) {
+                               dev_err(dev, "Failed to initialize F%.2x\n",
+                                       pdt_entry.function_number);
+                               kfree(fc);
+                               goto error_exit;
+                       }
+
+                       list_add_tail(&fc->list, &data->rmi_functions.list);
+               }
+       }
+       data->num_of_irq_regs = (irq_count + 7) / 8;
+       dev_dbg(dev, "%s: Done with PDT scan.\n", __func__);
+       return 0;
+
+error_exit:
+       return retval;
+}
+
+
+#ifdef SYNAPTICS_SENSOR_POLL
+void synaptics_sensor_poller(unsigned long data){
+  pr_info("in function ____%s____ ,  rmi_device= 0x%8x \n", __func__, polled_synaptics_rmi_device);
+  // msleep(10000);
+  for (;;) {
+    msleep(100);
+    rmi_driver_irq_handler(polled_synaptics_rmi_device, 0);
+  }
+
+  return;
+}
+
+struct workqueue_struct *synaptics_rmi_polling_queue = NULL;
+struct delayed_work synaptics_rmi_polling_work;
+
+#endif
+
+
+static int rmi_driver_probe(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data;
+       struct rmi_function_container *fc;
+       struct rmi_device_platform_data *pdata;
+       int error = 0;
+       struct device *dev = &rmi_dev->dev;
+       int attr_count = 0;
+
+       dev_dbg(dev, "%s: Starting probe.\n", __func__);
+
+       pdata = to_rmi_platform_data(rmi_dev);
+
+       data = kzalloc(sizeof(struct rmi_driver_data), GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "%s: Failed to allocate driver data.\n", __func__);
+               return -ENOMEM;
+       }
+
+       rmi_set_driverdata(rmi_dev, data);
+
+       error = rmi_scan_pdt(rmi_dev);
+       if (error) {
+               dev_err(dev, "PDT scan failed with code %d.\n", error);
+               goto err_free_data;
+       }
+
+       if (!data->f01_container) {
+               dev_err(dev, "missing f01 function!\n");
+               error = -EINVAL;
+               goto err_free_data;
+       }
+
+       data->f01_container->irq_mask = kzalloc(
+                       sizeof(u8) * data->num_of_irq_regs, GFP_KERNEL);
+       if (!data->f01_container->irq_mask) {
+               dev_err(dev, "Failed to allocate F01 IRQ mask.\n");
+               error = -ENOMEM;
+               goto err_free_data;
+       }
+       construct_mask(data->f01_container->irq_mask,
+                      data->f01_container->num_of_irqs,
+                      data->f01_container->irq_pos);
+       list_for_each_entry(fc, &data->rmi_functions.list, list)
+               fc->irq_mask = rmi_driver_irq_get_mask(rmi_dev, fc);
+
+       error = rmi_driver_f01_init(rmi_dev);
+       if (error < 0) {
+               dev_err(dev, "Failed to initialize F01.\n");
+               goto err_free_data;
+       }
+
+       error = rmi_read(rmi_dev, PDT_PROPERTIES_LOCATION,
+                        (char *) &data->pdt_props);
+       if (error < 0) {
+               /* we'll print out a warning and continue since
+                * failure to get the PDT properties is not a cause to fail
+                */
+               dev_warn(dev, "Could not read PDT properties from 0x%04x. "
+                        "Assuming 0x00.\n", PDT_PROPERTIES_LOCATION);
+       }
+
+       dev_dbg(dev, "%s: Creating sysfs files.", __func__);
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               error = device_create_file(dev, &attrs[attr_count]);
+               if (error < 0) {
+                       dev_err(dev, "%s: Failed to create sysfs file %s.\n",
+                               __func__, attrs[attr_count].attr.name);
+                       goto err_free_data;
+               }
+       }
+
+       __mutex_init(&data->irq_mutex, "irq_mutex", &data->irq_key);
+       data->current_irq_mask = kzalloc(sizeof(u8) * data->num_of_irq_regs,
+                                        GFP_KERNEL);
+       if (!data->current_irq_mask) {
+               dev_err(dev, "Failed to allocate current_irq_mask.\n");
+               error = -ENOMEM;
+               goto err_free_data;
+       }
+       error = rmi_read_block(rmi_dev,
+                               data->f01_container->fd.control_base_addr+1,
+                               data->current_irq_mask, data->num_of_irq_regs);
+       if (error < 0) {
+               dev_err(dev, "%s: Failed to read current IRQ mask.\n",
+                       __func__);
+               goto err_free_data;
+       }
+       data->irq_mask_store = kzalloc(sizeof(u8) * data->num_of_irq_regs,
+                                      GFP_KERNEL);
+       if (!data->irq_mask_store) {
+               dev_err(dev, "Failed to allocate mask store.\n");
+               error = -ENOMEM;
+               goto err_free_data;
+       }
+
+#if defined(CONFIG_RMI4_DEV)
+       if (rmi_char_dev_register(rmi_dev->phys))
+               pr_err("%s: error register char device", __func__);
+#endif /*CONFIG_RMI4_DEV*/
+
+#ifdef CONFIG_PM
+       data->pm_data = pdata->pm_data;
+       data->pre_suspend = pdata->pre_suspend;
+       data->post_resume = pdata->post_resume;
+
+       mutex_init(&data->suspend_mutex);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       rmi_dev->early_suspend_handler.level =
+               EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+       rmi_dev->early_suspend_handler.suspend = rmi_driver_early_suspend;
+       rmi_dev->early_suspend_handler.resume = rmi_driver_late_resume;
+       register_early_suspend(&rmi_dev->early_suspend_handler);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+#endif /* CONFIG_PM */
+       data->enabled = true;
+
+       dev_info(dev, "connected RMI device manufacturer: %s product: %s\n",
+                data->manufacturer_id == 1 ? "synaptics" : "unknown",
+                data->product_id);
+
+#ifdef SYNAPTICS_SENSOR_POLL
+       synaptics_rmi_polling_queue = create_singlethread_workqueue("rmi_poll_work");
+       INIT_DELAYED_WORK_DEFERRABLE(&synaptics_rmi_polling_work, synaptics_sensor_poller);
+       pr_info("%s: setting up POLLING mode, rmi_device= 0x%8x \n", __func__, polled_synaptics_rmi_device);
+       queue_delayed_work(synaptics_rmi_polling_queue, &synaptics_rmi_polling_work, 1000);
+#endif
+       return 0;
+
+ err_free_data:
+       rmi_free_function_list(rmi_dev);
+       for (attr_count--; attr_count >= 0; attr_count--)
+               device_remove_file(dev, &attrs[attr_count]);
+       kfree(data->f01_container->irq_mask);
+       kfree(data->irq_mask_store);
+       kfree(data->current_irq_mask);
+       kfree(data);
+       return error;
+}
+
+#ifdef CONFIG_PM
+static int rmi_driver_suspend(struct device *dev)
+{
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+       struct rmi_function_container *entry;
+       int retval = 0;
+
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       mutex_lock(&data->suspend_mutex);
+       if (data->suspended)
+               goto exit;
+
+       if (data->pre_suspend) {
+               retval = data->pre_suspend(data->pm_data);
+               if (retval)
+                       goto exit;
+       }
+
+       list_for_each_entry(entry, &data->rmi_functions.list, list)
+               if (entry->fh && entry->fh->suspend) {
+                       retval = entry->fh->suspend(entry);
+                       if (retval < 0)
+                               goto exit;
+               }
+
+       if (data->f01_container && data->f01_container->fh
+                               && data->f01_container->fh->suspend) {
+               retval = data->f01_container->fh->suspend(data->f01_container);
+               if (retval < 0)
+                       goto exit;
+       }
+       data->suspended = true;
+
+exit:
+       mutex_unlock(&data->suspend_mutex);
+       return retval;
+}
+
+static int rmi_driver_resume(struct device *dev)
+{
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+       struct rmi_function_container *entry;
+       int retval = 0;
+
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       mutex_lock(&data->suspend_mutex);
+       if (!data->suspended)
+               goto exit;
+
+       if (data->f01_container && data->f01_container->fh
+                               && data->f01_container->fh->resume) {
+               retval = data->f01_container->fh->resume(data->f01_container);
+               if (retval < 0)
+                       goto exit;
+       }
+
+       list_for_each_entry(entry, &data->rmi_functions.list, list)
+               if (entry->fh && entry->fh->resume) {
+                       retval = entry->fh->resume(entry);
+                       if (retval < 0)
+                               goto exit;
+               }
+
+       if (data->post_resume) {
+               retval = data->post_resume(data->pm_data);
+               if (retval)
+                       goto exit;
+       }
+
+       data->suspended = false;
+
+exit:
+       mutex_unlock(&data->suspend_mutex);
+       return retval;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void rmi_driver_early_suspend(struct early_suspend *h)
+{
+       struct rmi_device *rmi_dev =
+           container_of(h, struct rmi_device, early_suspend_handler);
+
+       dev_dbg(&rmi_dev->dev, "Early suspend.\n");
+       rmi_driver_suspend(&rmi_dev->dev);
+}
+
+static void rmi_driver_late_resume(struct early_suspend *h)
+{
+       struct rmi_device *rmi_dev =
+           container_of(h, struct rmi_device, early_suspend_handler);
+
+       dev_dbg(&rmi_dev->dev, "Late resume.\n");
+       rmi_driver_resume(&rmi_dev->dev);
+}
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+#endif /* CONFIG_PM */
+
+static int __devexit rmi_driver_remove(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct rmi_function_container *entry;
+       int i;
+
+       list_for_each_entry(entry, &data->rmi_functions.list, list)
+               if (entry->fh && entry->fh->remove)
+                       entry->fh->remove(entry);
+
+       rmi_free_function_list(rmi_dev);
+       for (i = 0; i < ARRAY_SIZE(attrs); i++)
+               device_remove_file(&rmi_dev->dev, &attrs[i]);
+       kfree(data->f01_container->irq_mask);
+       kfree(data->irq_mask_store);
+       kfree(data->current_irq_mask);
+       kfree(data);
+
+       return 0;
+}
+
+#ifdef UNIVERSAL_DEV_PM_OPS
+static UNIVERSAL_DEV_PM_OPS(rmi_driver_pm, rmi_driver_suspend,
+                           rmi_driver_resume, NULL);
+#endif
+
+static struct rmi_driver sensor_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               // .name = "rmi-generic",
+               .name = "rmi_generic",
+#ifdef UNIVERSAL_DEV_PM_OPS
+               .pm = &rmi_driver_pm,
+#endif
+       },
+       .probe = rmi_driver_probe,
+       .irq_handler = rmi_driver_irq_handler,
+       .fh_add = rmi_driver_fh_add,
+       .fh_remove = rmi_driver_fh_remove,
+       .get_func_irq_mask = rmi_driver_irq_get_mask,
+       .store_irq_mask = rmi_driver_irq_save,
+       .restore_irq_mask = rmi_driver_irq_restore,
+       .remove = __devexit_p(rmi_driver_remove)
+};
+
+/* Utility routine to handle writes to read-only attributes.  Hopefully
+ * this will never happen, but if the user does something stupid, we don't
+ * want to accept it quietly (which is what can happen if you just put NULL
+ * for the attribute's store function).
+ */
+ssize_t rmi_store_error(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       dev_warn(dev,
+                "RMI4 WARNING: Attempt to write %d characters to read-only "
+                "attribute %s.", count, attr->attr.name);
+       return -EPERM;
+}
+
+/* Utility routine to handle reads of write-only attributes.  Hopefully
+ * this will never happen, but if the user does something stupid, we don't
+ * want to accept it quietly (which is what can happen if you just put NULL
+ * for the attribute's show function).
+ */
+ssize_t rmi_show_error(struct device *dev,
+                      struct device_attribute *attr,
+                      char *buf)
+{
+       dev_warn(dev,
+                "RMI4 WARNING: Attempt to read from write-only attribute %s.",
+                attr->attr.name);
+       return -EPERM;
+}
+
+/* sysfs show and store fns for driver attributes */
+static ssize_t rmi_driver_hasbsr_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", has_bsr(data));
+}
+
+static ssize_t rmi_driver_bsr_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", data->bsr);
+}
+
+static ssize_t rmi_driver_bsr_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       int retval;
+       unsigned long val;
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       /* need to convert the string data to an actual value */
+       retval = strict_strtoul(buf, 10, &val);
+       if (retval < 0) {
+               dev_err(dev, "Invalid value '%s' written to BSR.\n", buf);
+               return -EINVAL;
+       }
+
+       retval = rmi_write(rmi_dev, BSR_LOCATION, (unsigned char)val);
+       if (retval) {
+               dev_err(dev, "%s : failed to write bsr %u to 0x%x\n",
+                       __func__, (unsigned int)val, BSR_LOCATION);
+               return retval;
+       }
+
+       data->bsr = val;
+
+       return count;
+}
+
+static void disable_sensor(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+
+       rmi_dev->phys->disable_device(rmi_dev->phys);
+
+       data->enabled = false;
+}
+
+static int enable_sensor(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       int retval = 0;
+       pr_info("in function ____%s____  \n", __func__);
+       retval = rmi_dev->phys->enable_device(rmi_dev->phys);
+       /* non-zero means error occurred */
+       if (retval)
+               return retval;
+
+       data->enabled = true;
+
+       return 0;
+}
+
+static ssize_t rmi_driver_enabled_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", data->enabled);
+}
+
+static ssize_t rmi_driver_enabled_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int retval;
+       int new_value;
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       if (sysfs_streq(buf, "0"))
+               new_value = false;
+       else if (sysfs_streq(buf, "1"))
+               new_value = true;
+       else
+               return -EINVAL;
+
+       if (new_value) {
+               retval = enable_sensor(rmi_dev);
+               if (retval) {
+                       dev_err(dev, "Failed to enable sensor, code=%d.\n",
+                               retval);
+                       return -EIO;
+               }
+       } else {
+               disable_sensor(rmi_dev);
+       }
+
+       return count;
+}
+
+#if REGISTER_DEBUG
+static ssize_t rmi_driver_reg_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int retval;
+       unsigned int address;
+       unsigned int bytes;
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
+       u8 readbuf[128];
+       unsigned char outbuf[512];
+       unsigned char *bufptr = outbuf;
+       int i;
+
+       rmi_dev = to_rmi_device(dev);
+       data = rmi_get_driverdata(rmi_dev);
+
+       retval = sscanf(buf, "%x %u", &address, &bytes);
+       if (retval != 2) {
+               dev_err(dev, "Invalid input (code %d) for reg store: %s",
+                       retval, buf);
+               return -EINVAL;
+       }
+       if (address < 0 || address > 0xFFFF) {
+               dev_err(dev, "Invalid address for reg store '%#06x'.\n",
+                       address);
+               return -EINVAL;
+       }
+       if (bytes < 0 || bytes >= sizeof(readbuf) || address+bytes > 65535) {
+               dev_err(dev, "Invalid byte count for reg store '%d'.\n",
+                       bytes);
+               return -EINVAL;
+       }
+
+       retval = rmi_read_block(rmi_dev, address, readbuf, bytes);
+       if (retval != bytes) {
+               dev_err(dev, "Failed to read %d registers at %#06x, code %d.\n",
+                       bytes, address, retval);
+               return retval;
+       }
+
+       dev_info(dev, "Reading %d bytes from %#06x.\n", bytes, address);
+       for (i = 0; i < bytes; i++) {
+               retval = snprintf(bufptr, 4, "%02X ", readbuf[i]);
+               if (retval < 0) {
+                       dev_err(dev, "Failed to format string. Code: %d",
+                               retval);
+                       return retval;
+               }
+               bufptr += retval;
+       }
+       dev_info(dev, "%s\n", outbuf);
+
+       return count;
+}
+#endif
+
+#if DELAY_DEBUG
+static ssize_t rmi_delay_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int retval;
+       struct rmi_device *rmi_dev;
+       struct rmi_device_platform_data *pdata;
+       unsigned int new_read_delay;
+       unsigned int new_write_delay;
+       unsigned int new_block_delay;
+       unsigned int new_pre_delay;
+       unsigned int new_post_delay;
+
+       retval = sscanf(buf, "%u %u %u %u %u", &new_read_delay,
+                       &new_write_delay, &new_block_delay,
+                       &new_pre_delay, &new_post_delay);
+       if (retval != 5) {
+               dev_err(dev, "Incorrect number of values provided for delay.");
+               return -EINVAL;
+       }
+       if (new_read_delay < 0) {
+               dev_err(dev, "Byte delay must be positive microseconds.\n");
+               return -EINVAL;
+       }
+       if (new_write_delay < 0) {
+               dev_err(dev, "Write delay must be positive microseconds.\n");
+               return -EINVAL;
+       }
+       if (new_block_delay < 0) {
+               dev_err(dev, "Block delay must be positive microseconds.\n");
+               return -EINVAL;
+       }
+       if (new_pre_delay < 0) {
+               dev_err(dev,
+                       "Pre-transfer delay must be positive microseconds.\n");
+               return -EINVAL;
+       }
+       if (new_post_delay < 0) {
+               dev_err(dev,
+                       "Post-transfer delay must be positive microseconds.\n");
+               return -EINVAL;
+       }
+
+       rmi_dev = to_rmi_device(dev);
+       pdata = rmi_dev->phys->dev->platform_data;
+
+       dev_info(dev, "Setting delays to %u %u %u %u %u.\n", new_read_delay,
+                new_write_delay, new_block_delay, new_pre_delay,
+                new_post_delay);
+       pdata->spi_data.read_delay_us = new_read_delay;
+       pdata->spi_data.write_delay_us = new_write_delay;
+       pdata->spi_data.block_delay_us = new_block_delay;
+       pdata->spi_data.pre_delay_us = new_pre_delay;
+       pdata->spi_data.post_delay_us = new_post_delay;
+
+       return count;
+}
+
+static ssize_t rmi_delay_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct rmi_device *rmi_dev;
+       struct rmi_device_platform_data *pdata;
+
+       rmi_dev = to_rmi_device(dev);
+       pdata = rmi_dev->phys->dev->platform_data;
+
+       return snprintf(buf, PAGE_SIZE, "%d %d %d %d %d\n",
+               pdata->spi_data.read_delay_us, pdata->spi_data.write_delay_us,
+               pdata->spi_data.block_delay_us,
+               pdata->spi_data.pre_delay_us, pdata->spi_data.post_delay_us);
+}
+#endif
+
+static ssize_t rmi_driver_phys_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct rmi_device *rmi_dev;
+       struct rmi_phys_info *info;
+
+       rmi_dev = to_rmi_device(dev);
+       info = &rmi_dev->phys->info;
+
+       return snprintf(buf, PAGE_SIZE, "%-5s %ld %ld %ld %ld %ld %ld %ld\n",
+                info->proto ? info->proto : "unk",
+                info->tx_count, info->tx_bytes, info->tx_errs,
+                info->rx_count, info->rx_bytes, info->rx_errs,
+                info->attn_count);
+}
+
+static ssize_t rmi_driver_version_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                RMI_DRIVER_VERSION_STRING);
+}
+
+static int __init rmi_driver_init(void)
+{
+       return rmi_register_driver(&sensor_driver);
+}
+
+static void __exit rmi_driver_exit(void)
+{
+       rmi_unregister_driver(&sensor_driver);
+}
+
+module_init(rmi_driver_init);
+module_exit(rmi_driver_exit);
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("RMI generic driver");
diff --git a/drivers/input/touchscreen/rmi4/rmi_driver.h b/drivers/input/touchscreen/rmi4/rmi_driver.h
new file mode 100644 (file)
index 0000000..9e9f2c0
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _RMI_DRIVER_H
+#define _RMI_DRIVER_H
+
+#define RMI_DRIVER_MAJOR_VERSION     1
+#define RMI_DRIVER_MINOR_VERSION     3
+#define RMI_DRIVER_SUB_MINOR_VERSION 0
+
+/* TODO: Figure out some way to construct this string in the define macro
+ * using the values defined above.
+ */
+#define RMI_DRIVER_VERSION_STRING "1.3.0"
+
+
+#define RMI_PRODUCT_ID_LENGTH    10
+#define RMI_PRODUCT_INFO_LENGTH   2
+#define RMI_DATE_CODE_LENGTH      3
+
+struct rmi_driver_data {
+       struct rmi_function_container rmi_functions;
+
+       struct rmi_function_container *f01_container;
+
+       int num_of_irq_regs;
+       u8 *current_irq_mask;
+       u8 *irq_mask_store;
+       bool irq_stored;
+       struct mutex irq_mutex;
+       struct lock_class_key irq_key;
+
+       unsigned char pdt_props;
+       unsigned char bsr;
+       bool enabled;
+
+       u8 manufacturer_id;
+       /* product id + null termination */
+       u8 product_id[RMI_PRODUCT_ID_LENGTH + 1];
+
+#ifdef CONFIG_PM
+       bool suspended;
+       struct mutex suspend_mutex;
+
+       void *pm_data;
+       int (*pre_suspend) (const void *pm_data);
+       int (*post_resume) (const void *pm_data);
+#endif
+
+       void *data;
+};
+
+struct pdt_entry {
+       u8 query_base_addr:8;
+       u8 command_base_addr:8;
+       u8 control_base_addr:8;
+       u8 data_base_addr:8;
+       u8 interrupt_source_count:3;
+       u8 bits3and4:2;
+       u8 function_version:2;
+       u8 bit7:1;
+       u8 function_number:8;
+};
+
+int rmi_driver_f01_init(struct rmi_device *rmi_dev);
+
+static inline void copy_pdt_entry_to_fd(struct pdt_entry *pdt,
+                                struct rmi_function_descriptor *fd,
+                                u16 page_start)
+{
+       fd->query_base_addr = pdt->query_base_addr + page_start;
+       fd->command_base_addr = pdt->command_base_addr + page_start;
+       fd->control_base_addr = pdt->control_base_addr + page_start;
+       fd->data_base_addr = pdt->data_base_addr + page_start;
+       fd->function_number = pdt->function_number;
+       fd->interrupt_source_count = pdt->interrupt_source_count;
+       fd->function_version = pdt->function_version;
+}
+
+/* Helper function to convert a short (in host processor endianess) to
+ * a byte array in the RMI endianess for shorts.  See above comment for
+ * why we dont us htons or something like that.
+ */
+void hstoba(u8 *dest, u16 src);
+
+/* Helper fn to convert a byte array representing a short in the RMI
+ * endian-ness to a short in the native processor's specific endianness.
+ * We don't use ntohs/htons here because, well, we're not dealing with
+ * a pair of shorts. And casting dest to short* wouldn't work, because
+ * that would imply knowing the byte order of short in the first place.
+ */
+void batohs(u16 *dest, u8 *src);
+
+#endif
diff --git a/drivers/input/touchscreen/rmi4/rmi_f01.c b/drivers/input/touchscreen/rmi4/rmi_f01.c
new file mode 100644 (file)
index 0000000..ef9adb0
--- /dev/null
@@ -0,0 +1,775 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+/* control register bits */
+#define RMI_SLEEP_MODE_NORMAL (0x00)
+#define RMI_SLEEP_MODE_SENSOR_SLEEP (0x01)
+#define RMI_SLEEP_MODE_RESERVED0 (0x02)
+#define RMI_SLEEP_MODE_RESERVED1 (0x03)
+
+#define RMI_IS_VALID_SLEEPMODE(mode) \
+       (mode >= RMI_SLEEP_MODE_NORMAL && mode <= RMI_SLEEP_MODE_RESERVED1)
+
+union f01_device_commands {
+       struct {
+               u8 reset:1;
+               u8 reserved:1;
+       };
+       u8 reg;
+};
+
+union f01_device_control {
+       struct {
+               u8 sleep_mode:2;
+               u8 nosleep:1;
+               u8 reserved:2;
+               u8 charger_input:1;
+               u8 report_rate:1;
+               u8 configured:1;
+       };
+       u8 reg;
+};
+
+union f01_device_status {
+       struct {
+               u8 status_code:4;
+               u8 reserved:2;
+               u8 flash_prog:1;
+               u8 unconfigured:1;
+       };
+       u8 reg;
+};
+
+union f01_basic_queries {
+       struct {
+               u8 manufacturer_id:8;
+
+               u8 custom_map:1;
+               u8 non_compliant:1;
+               u8 q1_bit_2:1;
+               u8 has_sensor_id:1;
+               u8 has_charger_input:1;
+               u8 has_adjustable_doze:1;
+               u8 has_adjustable_doze_holdoff:1;
+               u8 q1_bit_7:1;
+
+               u8 productinfo_1:7;
+               u8 q2_bit_7:1;
+               u8 productinfo_2:7;
+               u8 q3_bit_7:1;
+
+               u8 year:5;
+               u8 month:4;
+               u8 day:5;
+               u8 cp1:1;
+               u8 cp2:1;
+               u8 wafer_id1_lsb:8;
+               u8 wafer_id1_msb:8;
+               u8 wafer_id2_lsb:8;
+               u8 wafer_id2_msb:8;
+               u8 wafer_id3_lsb:8;
+       };
+       u8 regs[11];
+};
+
+struct f01_data {
+       union f01_device_control device_control;
+       union f01_basic_queries basic_queries;
+       union f01_device_status device_status;
+       u8 product_id[RMI_PRODUCT_ID_LENGTH+1];
+
+#ifdef CONFIG_PM
+       bool suspended;
+       bool old_nosleep;
+#endif
+};
+
+
+static ssize_t rmi_fn_01_productinfo_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf);
+
+static ssize_t rmi_fn_01_productid_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf);
+
+static ssize_t rmi_fn_01_manufacturer_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf);
+
+static ssize_t rmi_fn_01_datecode_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf);
+
+static ssize_t rmi_fn_01_reportrate_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+
+static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count);
+
+static ssize_t rmi_fn_01_reset_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count);
+
+static ssize_t rmi_fn_01_sleepmode_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf);
+
+static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+
+static ssize_t rmi_fn_01_nosleep_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count);
+
+static ssize_t rmi_fn_01_chargerinput_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+static ssize_t rmi_fn_01_chargerinput_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count);
+
+static ssize_t rmi_fn_01_configured_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+static ssize_t rmi_fn_01_unconfigured_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+static ssize_t rmi_fn_01_flashprog_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+static ssize_t rmi_fn_01_statuscode_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+static struct device_attribute fn_01_attrs[] = {
+       __ATTR(productinfo, RMI_RO_ATTR,
+              rmi_fn_01_productinfo_show, rmi_store_error),
+       __ATTR(productid, RMI_RO_ATTR,
+              rmi_fn_01_productid_show, rmi_store_error),
+       __ATTR(manufacturer, RMI_RO_ATTR,
+              rmi_fn_01_manufacturer_show, rmi_store_error),
+       __ATTR(datecode, RMI_RO_ATTR,
+              rmi_fn_01_datecode_show, rmi_store_error),
+
+       /* control register access */
+       __ATTR(sleepmode, RMI_RW_ATTR,
+              rmi_fn_01_sleepmode_show, rmi_fn_01_sleepmode_store),
+       __ATTR(nosleep, RMI_RW_ATTR,
+              rmi_fn_01_nosleep_show, rmi_fn_01_nosleep_store),
+       __ATTR(chargerinput, RMI_RW_ATTR,
+              rmi_fn_01_chargerinput_show, rmi_fn_01_chargerinput_store),
+       __ATTR(reportrate, RMI_RW_ATTR,
+              rmi_fn_01_reportrate_show, rmi_fn_01_reportrate_store),
+       /* We make report rate RO, since the driver uses that to look for
+        * resets.  We don't want someone faking us out by changing that
+        * bit.
+        */
+       __ATTR(configured, RMI_RO_ATTR,
+              rmi_fn_01_configured_show, rmi_store_error),
+
+       /* Command register access. */
+       __ATTR(reset, RMI_WO_ATTR,
+              rmi_show_error, rmi_fn_01_reset_store),
+
+       /* STatus register access. */
+       __ATTR(unconfigured, RMI_RO_ATTR,
+              rmi_fn_01_unconfigured_show, rmi_store_error),
+       __ATTR(flashprog, RMI_RO_ATTR,
+              rmi_fn_01_flashprog_show, rmi_store_error),
+       __ATTR(statuscode, RMI_RO_ATTR,
+              rmi_fn_01_statuscode_show, rmi_store_error),
+};
+
+/* Utility routine to set the value of a bit field in a register. */
+int rmi_set_bit_field(struct rmi_device *rmi_dev,
+                     unsigned short address,
+                     unsigned char field_mask,
+                     unsigned char bits)
+{
+       unsigned char reg_contents;
+       int retval;
+
+       retval = rmi_read(rmi_dev, address, &reg_contents);
+       if (retval)
+               return retval;
+       reg_contents = (reg_contents & ~field_mask) | bits;
+       retval = rmi_write(rmi_dev, address, reg_contents);
+       if (retval == 1)
+               return 0;
+       else if (retval == 0)
+               return -EIO;
+       return retval;
+}
+
+static ssize_t rmi_fn_01_productinfo_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n",
+                       data->basic_queries.productinfo_1,
+                       data->basic_queries.productinfo_2);
+}
+
+static ssize_t rmi_fn_01_productid_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", data->product_id);
+}
+
+static ssize_t rmi_fn_01_manufacturer_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "0x%02x\n",
+                       data->basic_queries.manufacturer_id);
+}
+
+static ssize_t rmi_fn_01_datecode_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "20%02u-%02u-%02u\n",
+                       data->basic_queries.year,
+                       data->basic_queries.month,
+                       data->basic_queries.day);
+}
+
+static ssize_t rmi_fn_01_reset_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct rmi_function_container *fc = NULL;
+       unsigned int reset;
+       int retval = 0;
+       /* Command register always reads as 0, so we can just use a local. */
+       union f01_device_commands commands = {};
+
+       fc = to_rmi_function_container(dev);
+
+       if (sscanf(buf, "%u", &reset) != 1)
+               return -EINVAL;
+       if (reset < 0 || reset > 1)
+               return -EINVAL;
+
+       /* Per spec, 0 has no effect, so we skip it entirely. */
+       if (reset) {
+               commands.reset = 1;
+               retval = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr,
+                               &commands.reg, sizeof(commands.reg));
+               if (retval < 0) {
+                       dev_err(dev, "%s: failed to issue reset command, "
+                               "error = %d.", __func__, retval);
+                       return retval;
+               }
+       }
+
+       return count;
+}
+
+static ssize_t rmi_fn_01_sleepmode_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE,
+                       "%d\n", data->device_control.sleep_mode);
+}
+
+static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf,
+                                        size_t count)
+{
+       struct f01_data *data = NULL;
+       unsigned long new_value;
+       int retval;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       retval = strict_strtoul(buf, 10, &new_value);
+       if (retval < 0 || !RMI_IS_VALID_SLEEPMODE(new_value)) {
+               dev_err(dev, "%s: Invalid sleep mode %s.", __func__, buf);
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "Setting sleep mode to %ld.", new_value);
+       data->device_control.sleep_mode = new_value;
+       retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (retval >= 0)
+               retval = count;
+       else
+               dev_err(dev, "Failed to write sleep mode, code %d.\n", retval);
+       return retval;
+}
+
+static ssize_t rmi_fn_01_nosleep_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", data->device_control.nosleep);
+}
+
+static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf,
+                                      size_t count)
+{
+       struct f01_data *data = NULL;
+       unsigned long new_value;
+       int retval;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       retval = strict_strtoul(buf, 10, &new_value);
+       if (retval < 0 || new_value < 0 || new_value > 1) {
+               dev_err(dev, "%s: Invalid nosleep bit %s.", __func__, buf);
+               return -EINVAL;
+       }
+
+       data->device_control.nosleep = new_value;
+       retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (retval >= 0)
+               retval = count;
+       else
+               dev_err(dev, "Failed to write nosleep bit.\n");
+       return retval;
+}
+
+static ssize_t rmi_fn_01_chargerinput_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->device_control.charger_input);
+}
+
+static ssize_t rmi_fn_01_chargerinput_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf,
+                                      size_t count)
+{
+       struct f01_data *data = NULL;
+       unsigned long new_value;
+       int retval;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       retval = strict_strtoul(buf, 10, &new_value);
+       if (retval < 0 || new_value < 0 || new_value > 1) {
+               dev_err(dev, "%s: Invalid chargerinput bit %s.", __func__, buf);
+               return -EINVAL;
+       }
+
+       data->device_control.charger_input = new_value;
+       retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (retval >= 0)
+               retval = count;
+       else
+               dev_err(dev, "Failed to write chargerinput bit.\n");
+       return retval;
+}
+
+static ssize_t rmi_fn_01_reportrate_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->device_control.report_rate);
+}
+
+static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf,
+                                      size_t count)
+{
+       struct f01_data *data = NULL;
+       unsigned long new_value;
+       int retval;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       retval = strict_strtoul(buf, 10, &new_value);
+       if (retval < 0 || new_value < 0 || new_value > 1) {
+               dev_err(dev, "%s: Invalid reportrate bit %s.", __func__, buf);
+               return -EINVAL;
+       }
+
+       data->device_control.report_rate = new_value;
+       retval = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (retval >= 0)
+               retval = count;
+       else
+               dev_err(dev, "Failed to write reportrate bit.\n");
+       return retval;
+}
+
+static ssize_t rmi_fn_01_configured_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->device_control.configured);
+}
+
+static ssize_t rmi_fn_01_unconfigured_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->device_status.unconfigured);
+}
+
+static ssize_t rmi_fn_01_flashprog_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->device_status.flash_prog);
+}
+
+static ssize_t rmi_fn_01_statuscode_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_container *fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "0x%02x\n",
+                       data->device_status.status_code);
+}
+
+int rmi_driver_f01_init(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *driver_data = rmi_get_driverdata(rmi_dev);
+       struct rmi_function_container *fc = driver_data->f01_container;
+       struct f01_data *data;
+       int error;
+       u8 temp;
+       int attr_count;
+
+       data = kzalloc(sizeof(struct f01_data), GFP_KERNEL);
+       if (!data) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F01 data.\n");
+               return -ENOMEM;
+       }
+       fc->data = data;
+
+       /* Set the configured bit. */
+       error = rmi_read_block(rmi_dev, fc->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (error < 0) {
+               dev_err(&fc->dev, "Failed to read F01 control.\n");
+               goto error_exit;
+       }
+
+       /* Sleep mode might be set as a hangover from a system crash or
+        * reboot without power cycle.  If so, clear it so the sensor
+        * is certain to function.
+        */
+       if (data->device_control.sleep_mode != RMI_SLEEP_MODE_NORMAL) {
+               dev_warn(&fc->dev,
+                        "WARNING: Non-zero sleep mode found. Clearing...\n");
+               data->device_control.sleep_mode = RMI_SLEEP_MODE_NORMAL;
+       }
+
+       data->device_control.configured = 1;
+       error = rmi_write_block(rmi_dev, fc->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (error < 0) {
+               dev_err(&fc->dev, "Failed to write F01 control.\n");
+               goto error_exit;
+       }
+
+       /* dummy read in order to clear irqs */
+       error = rmi_read(rmi_dev, fc->fd.data_base_addr + 1, &temp);
+       if (error < 0) {
+               dev_err(&fc->dev, "Failed to read Interrupt Status.\n");
+               goto error_exit;
+       }
+
+       error = rmi_read_block(rmi_dev, fc->fd.query_base_addr,
+                               data->basic_queries.regs,
+                               sizeof(data->basic_queries.regs));
+       if (error < 0) {
+               dev_err(&fc->dev, "Failed to read device query registers.\n");
+               goto error_exit;
+       }
+       driver_data->manufacturer_id = data->basic_queries.manufacturer_id;
+
+       error = rmi_read_block(rmi_dev,
+               fc->fd.query_base_addr + sizeof(data->basic_queries.regs),
+               data->product_id, RMI_PRODUCT_ID_LENGTH);
+       if (error < 0) {
+               dev_err(&fc->dev, "Failed to read product ID.\n");
+               goto error_exit;
+       }
+       data->product_id[RMI_PRODUCT_ID_LENGTH] = '\0';
+       memcpy(driver_data->product_id, data->product_id,
+              sizeof(data->product_id));
+
+       error = rmi_read_block(rmi_dev, fc->fd.data_base_addr,
+                       &data->device_status.reg,
+                       sizeof(data->device_status.reg));
+       if (error < 0) {
+               dev_err(&fc->dev, "Failed to read device status.\n");
+               goto error_exit;
+       }
+       if (data->device_status.unconfigured) {
+               dev_err(&fc->dev,
+                       "Device reset during configuration process, status: "
+                       "%#02x!\n", data->device_status.status_code);
+               error = -EINVAL;
+               goto error_exit;
+       }
+       /*
+       **  attach the routines that handle sysfs interaction
+       ** Meaning:  Set up sysfs device attributes.
+       */
+       for (attr_count = 0; attr_count < ARRAY_SIZE(fn_01_attrs);
+                       attr_count++) {
+               if (sysfs_create_file(&fc->dev.kobj,
+                                     &fn_01_attrs[attr_count].attr) < 0) {
+                       dev_err(&fc->dev, "Failed to create sysfs file for %s.",
+                              fn_01_attrs[attr_count].attr.name);
+                       error = -ENODEV;
+                       goto error_exit;
+               }
+       }
+
+       return error;
+
+ error_exit:
+       kfree(data);
+       return error;
+}
+
+#ifdef CONFIG_PM
+
+static int rmi_f01_suspend(struct rmi_function_container *fc)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct rmi_driver_data *driver_data = rmi_get_driverdata(rmi_dev);
+       struct f01_data *data = driver_data->f01_container->data;
+       int retval = 0;
+
+       dev_dbg(&fc->dev, "Suspending...\n");
+       if (data->suspended)
+               return 0;
+
+       data->old_nosleep = data->device_control.nosleep;
+       data->device_control.nosleep = 0;
+       data->device_control.sleep_mode = RMI_SLEEP_MODE_SENSOR_SLEEP;
+
+       retval = rmi_write_block(rmi_dev,
+                       driver_data->f01_container->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (retval < 0) {
+               dev_err(&fc->dev, "Failed to write sleep mode. "
+                       "Code: %d.\n", retval);
+               data->device_control.nosleep = data->old_nosleep;
+               data->device_control.sleep_mode = RMI_SLEEP_MODE_NORMAL;
+       } else {
+               data->suspended = true;
+               retval = 0;
+       }
+
+       return retval;
+}
+
+static int rmi_f01_resume(struct rmi_function_container *fc)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct rmi_driver_data *driver_data = rmi_get_driverdata(rmi_dev);
+       struct f01_data *data = driver_data->f01_container->data;
+       int retval = 0;
+
+       dev_dbg(&fc->dev, "Resuming...\n");
+       if (!data->suspended)
+               return 0;
+
+       data->device_control.nosleep = data->old_nosleep;
+       data->device_control.sleep_mode = RMI_SLEEP_MODE_NORMAL;
+
+       retval = rmi_write_block(rmi_dev,
+                       driver_data->f01_container->fd.control_base_addr,
+                       &data->device_control.reg,
+                       sizeof(data->device_control.reg));
+       if (retval < 0)
+               dev_err(&fc->dev, "Failed to restore normal operation. "
+                       "Code: %d.\n", retval);
+       else {
+               data->suspended = false;
+               retval = 0;
+       }
+
+       return retval;
+}
+#endif /* CONFIG_PM */
+
+static int rmi_f01_init(struct rmi_function_container *fc)
+{
+       return 0;
+}
+
+static int rmi_f01_attention(struct rmi_function_container *fc, u8 *irq_bits)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct f01_data *data = fc->data;
+       int error;
+
+       error = rmi_read_block(rmi_dev, fc->fd.data_base_addr,
+                       &data->device_status.reg,
+                       sizeof(data->device_status.reg));
+       if (error < 0) {
+               dev_err(&fc->dev, "Failed to read device status.\n");
+               return error;
+       }
+
+       /* TODO: Do we handle reset here or elsewhere? */
+       if (data->device_status.unconfigured)
+               dev_warn(&rmi_dev->dev, "Reset detected! Status code: %#04x.\n",
+                       data->device_status.status_code);
+       return 0;
+}
+
+static struct rmi_function_handler function_handler = {
+       .func = 0x01,
+       .init = rmi_f01_init,
+       .attention = rmi_f01_attention,
+#ifdef CONFIG_PM
+       .suspend = rmi_f01_suspend,
+       .resume = rmi_f01_resume,
+#endif
+};
+
+static int __init rmi_f01_module_init(void)
+{
+       int error;
+
+       error = rmi_register_function_driver(&function_handler);
+       if (error < 0) {
+               pr_err("%s: register failed!\n", __func__);
+               return error;
+       }
+
+       return 0;
+}
+
+static void __exit rmi_f01_module_exit(void)
+{
+       rmi_unregister_function_driver(&function_handler);
+}
+
+module_init(rmi_f01_module_init);
+module_exit(rmi_f01_module_exit);
+
+MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
+MODULE_DESCRIPTION("RMI F01 module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi4/rmi_f09.c b/drivers/input/touchscreen/rmi4/rmi_f09.c
new file mode 100644 (file)
index 0000000..0ec980d
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#define QUERY_BASE_INDEX 1
+#define MAX_LEN 256
+
+/* data specific to fn $09 that needs to be kept around */
+struct f09_query {
+       u8 Limit_Register_Count;
+       union {
+               struct {
+                       u8 Result_Register_Count:3;
+                       u8 Reserved:3;
+                       u8 InternalLimits:1;
+                       u8 HostTestEn:1;
+               };
+               u8 f09_bist_query1;
+       };
+};
+
+struct f09_control {
+       /* test1 */
+       u8 Test1LimitLo;
+       u8 Test1LimitHi;
+       u8 Test1LimitDiff;
+       /* test2 */
+       u8 Test2LimitLo;
+       u8 Test2LimitHi;
+       u8 Test2LimitDiff;
+};
+
+struct f09_data {
+       u8 TestNumberControl;
+       u8 Overall_BIST_Result;
+       u8 TestResult1;
+       u8 TestResult2;
+       u8 Transmitter_Number;
+
+       union {
+               struct {
+                       u8 Receiver_Number:6;
+                       u8 Limit_Failure_Code:2;
+               };
+               u8 f09_bist_data2;
+       };
+};
+
+struct f09_cmd {
+       union {
+               struct {
+                       u8 RunBIST:1;
+               };
+               u8 f09_bist_cmd0;
+       };
+};
+
+struct rmi_fn_09_data {
+       struct f09_query query;
+};
+
+static ssize_t rmi_f09_Limit_Register_Count_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                       char *buf, size_t count);
+
+static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f09_Overall_BIST_Result_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f09_Overall_BIST_Result_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count);
+
+static struct device_attribute attrs[] = {
+       __ATTR(Limit_Register_Count, RMI_RO_ATTR,
+              rmi_f09_Limit_Register_Count_show, rmi_store_error),
+       __ATTR(HostTestEn, RMI_RW_ATTR,
+              rmi_f09_HostTestEn_show, rmi_f09_HostTestEn_store),
+       __ATTR(InternalLimits, RMI_RO_ATTR,
+              rmi_f09_Limit_Register_Count_show, rmi_store_error),
+       __ATTR(Result_Register_Count, RMI_RO_ATTR,
+              rmi_f09_Result_Register_Count_show, rmi_store_error),
+};
+
+static int rmi_f09_init(struct rmi_function_container *fc)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct rmi_device_platform_data *pdata;
+       struct rmi_fn_09_data  *f09;
+       u8 query_base_addr;
+       int rc;
+       int i;
+       int attr_count = 0;
+       int retval = 0;
+
+       dev_info(&fc->dev, "Intializing F09 values.");
+
+       f09 = kzalloc(sizeof(struct rmi_fn_09_data), GFP_KERNEL);
+       if (!f09) {
+               dev_err(&fc->dev, "Failed to allocate rmi_fn_09_data.\n");
+               retval = -ENOMEM;
+               goto error_exit;
+       }
+       fc->data = f09;
+
+       pdata = to_rmi_platform_data(rmi_dev);
+       query_base_addr = fc->fd.query_base_addr;
+
+       /* initial all default values for f09 query here */
+       rc = rmi_read_block(rmi_dev, query_base_addr,
+               (u8 *)&f09->query, sizeof(f09->query));
+       if (rc < 0) {
+               dev_err(&fc->dev, "Failed to read query register."
+                       " from 0x%04x\n", query_base_addr);
+               goto error_exit;
+       }
+
+       dev_dbg(&fc->dev, "Creating sysfs files.");
+       /* Set up sysfs device attributes. */
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               if (sysfs_create_file
+                   (&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
+                       dev_err(&fc->dev, "Failed to create sysfs file for %s.",
+                            attrs[attr_count].attr.name);
+                       retval = -ENODEV;
+                       goto error_exit;
+               }
+       }
+       return 0;
+
+error_exit:
+       dev_err(&fc->dev, "An error occured in F09 init!\n");
+       for (attr_count--; attr_count >= 0; attr_count--)
+               sysfs_remove_file(&fc->dev.kobj,
+                                 &attrs[attr_count].attr);
+       kfree(f09);
+       return retval;
+}
+
+static void rmi_f09_remove(struct rmi_function_container *fc)
+{
+       struct rmi_fn_09_data *data = fc->data;
+       if (data) {
+               kfree(data->query.Limit_Register_Count);
+               kfree(data->query.f09_bist_query1);
+       }
+       kfree(fc->data);
+}
+
+static struct rmi_function_handler function_handler = {
+       .func = 0x09,
+       .init = rmi_f09_init,
+       .remove = rmi_f09_remove
+};
+
+static int __init rmi_f09_module_init(void)
+{
+       int error;
+
+       error = rmi_register_function_driver(&function_handler);
+       if (error < 0) {
+               pr_err("%s: register failed!\n", __func__);
+               return error;
+       }
+
+       return 0;
+}
+
+static void rmi_f09_module_exit(void)
+{
+       rmi_unregister_function_driver(&function_handler);
+}
+
+
+static ssize_t rmi_f09_Limit_Register_Count_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_09_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.Limit_Register_Count);
+}
+
+static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_09_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.HostTestEn);
+}
+
+static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                       char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_09_data *data;
+       unsigned int new_value;
+       int result;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       if (sscanf(buf, "%u", &new_value) != 1) {
+               dev_err(dev,
+               "%s: Error - HostTestEn_store has an "
+               "invalid len.\n",
+               __func__);
+               return -EINVAL;
+       }
+
+       if (new_value < 0 || new_value > 1) {
+               dev_err(dev, "%s: Invalid HostTestEn bit %s.", __func__, buf);
+               return -EINVAL;
+       }
+       data->query.HostTestEn = new_value;
+       result = rmi_write(fc->rmi_dev, fc->fd.query_base_addr,
+               data->query.HostTestEn);
+       if (result < 0) {
+               dev_err(dev, "%s : Could not write HostTestEn_store to 0x%x\n",
+                               __func__, fc->fd.query_base_addr);
+               return result;
+       }
+
+       return count;
+
+}
+
+static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_09_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.InternalLimits);
+}
+
+static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_09_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.Result_Register_Count);
+}
+
+module_init(rmi_f09_module_init);
+module_exit(rmi_f09_module_exit);
+
+MODULE_AUTHOR("Allie Xiong <axiong@Synaptics.com>");
+MODULE_DESCRIPTION("RMI F09 module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi4/rmi_f11.c b/drivers/input/touchscreen/rmi4/rmi_f11.c
new file mode 100644 (file)
index 0000000..35bb945
--- /dev/null
@@ -0,0 +1,1513 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/rmi.h>
+
+#define F11_MAX_NUM_OF_SENSORS         8
+#define F11_MAX_NUM_OF_FINGERS         10
+#define F11_MAX_NUM_OF_TOUCH_SHAPES    16
+
+#define F11_REL_POS_MIN                -128
+#define F11_REL_POS_MAX                127
+
+#define F11_FINGER_STATE_MASK  0x03
+#define F11_FINGER_STATE_SIZE  0x02
+#define F11_FINGER_STATE_MASK_N(i) \
+               (F11_FINGER_STATE_MASK << (i%4 * F11_FINGER_STATE_SIZE))
+
+#define F11_FINGER_STATE_VAL_N(f_state, i) \
+               (f_state >> (i%4 * F11_FINGER_STATE_SIZE))
+
+#define F11_CTRL_SENSOR_MAX_X_POS_OFFSET       6
+#define F11_CTRL_SENSOR_MAX_Y_POS_OFFSET       8
+
+#define F11_CEIL(x, y) (((x) + ((y)-1)) / (y))
+
+/* By default, we'll support two fingers if we can't figure out how many we
+ * really need to handle.
+ */
+#define DEFAULT_NR_OF_FINGERS 2
+#define DEFAULT_XY_MAX 9999
+#define DEFAULT_MAX_ABS_MT_PRESSURE 255
+#define DEFAULT_MAX_ABS_MT_TOUCH 15
+#define DEFAULT_MAX_ABS_MT_ORIENTATION 1
+#define DEFAULT_MIN_ABS_MT_TRACKING_ID 1
+#define DEFAULT_MAX_ABS_MT_TRACKING_ID 10
+#define MAX_LEN 256
+
+static ssize_t rmi_fn_11_flip_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_flip_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_clip_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_clip_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_offset_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_offset_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_swap_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_swap_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_relreport_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf);
+
+static ssize_t rmi_fn_11_relreport_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_maxPos_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f11_rezero_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+
+
+static struct device_attribute attrs[] = {
+       __ATTR(flip, RMI_RW_ATTR, rmi_fn_11_flip_show, rmi_fn_11_flip_store),
+       __ATTR(clip, RMI_RW_ATTR, rmi_fn_11_clip_show, rmi_fn_11_clip_store),
+       __ATTR(offset, RMI_RW_ATTR,
+               rmi_fn_11_offset_show, rmi_fn_11_offset_store),
+       __ATTR(swap, RMI_RW_ATTR, rmi_fn_11_swap_show, rmi_fn_11_swap_store),
+       __ATTR(relreport, RMI_RW_ATTR,
+               rmi_fn_11_relreport_show, rmi_fn_11_relreport_store),
+       __ATTR(maxPos, RMI_RO_ATTR, rmi_fn_11_maxPos_show, rmi_store_error),
+       __ATTR(rezero, RMI_WO_ATTR, rmi_show_error, rmi_f11_rezero_store)
+};
+
+
+union f11_2d_commands {
+       struct {
+               u8 rezero:1;
+       };
+       u8 reg;
+};
+
+
+struct f11_2d_device_query {
+       union {
+               struct {
+                       u8 nbr_of_sensors:3;
+                       u8 has_query9:1;
+                       u8 has_query11:1;
+               };
+               u8 f11_2d_query0;
+       };
+
+       u8 f11_2d_query9;
+
+       union {
+               struct {
+                       u8 has_z_tuning:1;
+                       u8 has_pos_interpolation_tuning:1;
+                       u8 has_w_tuning:1;
+                       u8 has_pitch_info:1;
+                       u8 has_default_finger_width:1;
+                       u8 has_segmentation_aggressiveness:1;
+                       u8 has_tx_rw_clip:1;
+                       u8 has_drumming_correction:1;
+               };
+               u8 f11_2d_query11;
+       };
+};
+
+struct f11_2d_sensor_query {
+       union {
+               struct {
+                       /* query1 */
+                       u8 number_of_fingers:3;
+                       u8 has_rel:1;
+                       u8 has_abs:1;
+                       u8 has_gestures:1;
+                       u8 has_sensitivity_adjust:1;
+                       u8 configurable:1;
+                       /* query2 */
+                       u8 num_of_x_electrodes:7;
+                       /* query3 */
+                       u8 num_of_y_electrodes:7;
+                       /* query4 */
+                       u8 max_electrodes:7;
+               };
+               u8 f11_2d_query1__4[4];
+       };
+
+       union {
+               struct {
+                       u8 abs_data_size:3;
+                       u8 has_anchored_finger:1;
+                       u8 has_adj_hyst:1;
+                       u8 has_dribble:1;
+               };
+               u8 f11_2d_query5;
+       };
+
+       u8 f11_2d_query6;
+
+       union {
+               struct {
+                       u8 has_single_tap:1;
+                       u8 has_tap_n_hold:1;
+                       u8 has_double_tap:1;
+                       u8 has_early_tap:1;
+                       u8 has_flick:1;
+                       u8 has_press:1;
+                       u8 has_pinch:1;
+                       u8 padding:1;
+
+                       u8 has_palm_det:1;
+                       u8 has_rotate:1;
+                       u8 has_touch_shapes:1;
+                       u8 has_scroll_zones:1;
+                       u8 has_individual_scroll_zones:1;
+                       u8 has_multi_finger_scroll:1;
+               };
+               u8 f11_2d_query7__8[2];
+       };
+
+       /* Empty */
+       u8 f11_2d_query9;
+
+       union {
+               struct {
+                       u8 nbr_touch_shapes:5;
+               };
+               u8 f11_2d_query10;
+       };
+};
+
+struct f11_2d_data_0 {
+       u8 finger_n;
+};
+
+struct f11_2d_data_1_5 {
+       u8 x_msb;
+       u8 y_msb;
+       u8 x_lsb:4;
+       u8 y_lsb:4;
+       u8 w_y:4;
+       u8 w_x:4;
+       u8 z;
+};
+
+struct f11_2d_data_6_7 {
+       s8 delta_x;
+       s8 delta_y;
+};
+
+struct f11_2d_data_8 {
+       u8 single_tap:1;
+       u8 tap_and_hold:1;
+       u8 double_tap:1;
+       u8 early_tap:1;
+       u8 flick:1;
+       u8 press:1;
+       u8 pinch:1;
+};
+
+struct f11_2d_data_9 {
+       u8 palm_detect:1;
+       u8 rotate:1;
+       u8 shape:1;
+       u8 scrollzone:1;
+       u8 finger_count:3;
+};
+
+struct f11_2d_data_10 {
+       u8 pinch_motion;
+};
+
+struct f11_2d_data_10_12 {
+       u8 x_flick_dist;
+       u8 y_flick_dist;
+       u8 flick_time;
+};
+
+struct f11_2d_data_11_12 {
+       u8 motion;
+       u8 finger_separation;
+};
+
+struct f11_2d_data_13 {
+       u8 shape_n;
+};
+
+struct f11_2d_data_14_15 {
+       u8 horizontal;
+       u8 vertical;
+};
+
+struct f11_2d_data_14_17 {
+       u8 x_low;
+       u8 y_right;
+       u8 x_upper;
+       u8 y_left;
+};
+
+struct f11_2d_data {
+       const struct f11_2d_data_0      *f_state;
+       const struct f11_2d_data_1_5    *abs_pos;
+       const struct f11_2d_data_6_7    *rel_pos;
+       const struct f11_2d_data_8      *gest_1;
+       const struct f11_2d_data_9      *gest_2;
+       const struct f11_2d_data_10     *pinch;
+       const struct f11_2d_data_10_12  *flick;
+       const struct f11_2d_data_11_12  *rotate;
+       const struct f11_2d_data_13     *shapes;
+       const struct f11_2d_data_14_15  *multi_scroll;
+       const struct f11_2d_data_14_17  *scroll_zones;
+};
+
+struct f11_2d_sensor {
+       struct rmi_f11_2d_axis_alignment axis_align;
+       struct f11_2d_sensor_query sens_query;
+       struct f11_2d_data data;
+       u16 max_x;
+       u16 max_y;
+       u8 nbr_fingers;
+       u8 finger_tracker[F11_MAX_NUM_OF_FINGERS];
+       u8 *data_pkt;
+       int pkt_size;
+       u8 sensor_index;
+       char input_name[MAX_LEN];
+       char input_phys[MAX_LEN];
+
+       struct input_dev *input;
+       struct input_dev *mouse_input;
+};
+
+struct f11_data {
+       struct f11_2d_device_query dev_query;
+       struct rmi_f11_2d_ctrl dev_controls;
+       struct f11_2d_sensor sensors[F11_MAX_NUM_OF_SENSORS];
+};
+
+enum finger_state_values {
+       F11_NO_FINGER   = 0x00,
+       F11_PRESENT     = 0x01,
+       F11_INACCURATE  = 0x02,
+       F11_RESERVED    = 0x03
+};
+
+static void rmi_f11_rel_pos_report(struct f11_2d_sensor *sensor, u8 n_finger)
+{
+       struct f11_2d_data *data = &sensor->data;
+       struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align;
+       s8 x, y;
+       s8 temp;
+
+       x = data->rel_pos[n_finger].delta_x;
+       y = data->rel_pos[n_finger].delta_y;
+
+       x = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)x));
+       y = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)y));
+
+       if (axis_align->swap_axes) {
+               temp = x;
+               x = y;
+               y = temp;
+       }
+       if (axis_align->flip_x)
+               x = min(F11_REL_POS_MAX, -x);
+       if (axis_align->flip_y)
+               y = min(F11_REL_POS_MAX, -y);
+
+       if (x || y) {
+               input_report_rel(sensor->input, REL_X, x);
+               input_report_rel(sensor->input, REL_Y, y);
+               input_report_rel(sensor->mouse_input, REL_X, x);
+               input_report_rel(sensor->mouse_input, REL_Y, y);
+       }
+       input_sync(sensor->mouse_input);
+}
+
+static void rmi_f11_abs_pos_report(struct f11_2d_sensor *sensor,
+                                       u8 finger_state, u8 n_finger)
+{
+       struct f11_2d_data *data = &sensor->data;
+       struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align;
+       int prev_state = sensor->finger_tracker[n_finger];
+       int x, y, z;
+       int w_x, w_y, w_max, w_min, orient;
+       int temp;
+       if (prev_state && !finger_state) {
+               /* this is a release */
+               x = y = z = w_max = w_min = orient = 0;
+       } else if (!prev_state && !finger_state) {
+               /* nothing to report */
+               return;
+       } else {
+               x = ((data->abs_pos[n_finger].x_msb << 4) |
+                       data->abs_pos[n_finger].x_lsb);
+               y = ((data->abs_pos[n_finger].y_msb << 4) |
+                       data->abs_pos[n_finger].y_lsb);
+               z = data->abs_pos[n_finger].z;
+               w_x = data->abs_pos[n_finger].w_x;
+               w_y = data->abs_pos[n_finger].w_y;
+               w_max = max(w_x, w_y);
+               w_min = min(w_x, w_y);
+
+               if (axis_align->swap_axes) {
+                       temp = x;
+                       x = y;
+                       y = temp;
+                       temp = w_x;
+                       w_x = w_y;
+                       w_y = temp;
+               }
+
+               orient = w_x > w_y ? 1 : 0;
+
+               if (axis_align->flip_x)
+                       x = max(sensor->max_x - x, 0);
+
+               if (axis_align->flip_y)
+                       y = max(sensor->max_y - y, 0);
+
+               /*
+               ** here checking if X offset or y offset are specified is
+               **  redundant.  We just add the offsets or, clip the values
+               **
+               ** note: offsets need to be done before clipping occurs,
+               ** or we could get funny values that are outside
+               ** clipping boundaries.
+               */
+               x += axis_align->offset_X;
+               y += axis_align->offset_Y;
+               x =  max(axis_align->clip_X_low, x);
+               y =  max(axis_align->clip_Y_low, y);
+               if (axis_align->clip_X_high)
+                       x = min(axis_align->clip_X_high, x);
+               if (axis_align->clip_Y_high)
+                       y =  min(axis_align->clip_Y_high, y);
+
+       }
+
+       pr_debug("%s: f_state[%d]:%d - x:%d y:%d z:%d w_max:%d w_min:%d\n",
+               __func__, n_finger, finger_state, x, y, z, w_max, w_min);
+
+
+#ifdef ABS_MT_PRESSURE
+       input_report_abs(sensor->input, ABS_MT_PRESSURE, z);
+#endif
+       input_report_abs(sensor->input, ABS_MT_TOUCH_MAJOR, w_max);
+       input_report_abs(sensor->input, ABS_MT_TOUCH_MINOR, w_min);
+       input_report_abs(sensor->input, ABS_MT_ORIENTATION, orient);
+       input_report_abs(sensor->input, ABS_MT_POSITION_X, x);
+       input_report_abs(sensor->input, ABS_MT_POSITION_Y, y);
+       input_report_abs(sensor->input, ABS_MT_TRACKING_ID, n_finger);
+
+       /* MT sync between fingers */
+       input_mt_sync(sensor->input);
+       sensor->finger_tracker[n_finger] = finger_state;
+}
+
+static void rmi_f11_finger_handler(struct f11_2d_sensor *sensor)
+{
+       const struct f11_2d_data_0 *f_state = sensor->data.f_state;
+       u8 finger_state;
+       u8 finger_pressed_count;
+       u8 i;
+
+       for (i = 0, finger_pressed_count = 0; i < sensor->nbr_fingers; i++) {
+               /* Possible of having 4 fingers per f_statet register */
+               finger_state = (f_state[i >> 2].finger_n &
+                                       F11_FINGER_STATE_MASK_N(i));
+               finger_state = F11_FINGER_STATE_VAL_N(finger_state, i);
+
+               if (finger_state == F11_RESERVED) {
+                       pr_err("%s: Invalid finger state[%d]:0x%02x.", __func__,
+                                       i, finger_state);
+                       continue;
+               } else if ((finger_state == F11_PRESENT) ||
+                               (finger_state == F11_INACCURATE)) {
+                       finger_pressed_count++;
+               }
+
+               if (sensor->data.abs_pos)
+                       rmi_f11_abs_pos_report(sensor, finger_state, i);
+
+               if (sensor->data.rel_pos)
+                       rmi_f11_rel_pos_report(sensor, i);
+       }
+       input_report_key(sensor->input, BTN_TOUCH, finger_pressed_count);
+       input_sync(sensor->input);
+}
+
+static inline int rmi_f11_2d_construct_data(struct f11_2d_sensor *sensor)
+{
+       struct f11_2d_sensor_query *query = &sensor->sens_query;
+       struct f11_2d_data *data = &sensor->data;
+       int i;
+
+       sensor->nbr_fingers = (query->number_of_fingers == 5 ? 10 :
+                               query->number_of_fingers + 1);
+
+       sensor->pkt_size = F11_CEIL(sensor->nbr_fingers, 4);
+
+       if (query->has_abs)
+               sensor->pkt_size += (sensor->nbr_fingers * 5);
+
+       if (query->has_rel)
+               sensor->pkt_size +=  (sensor->nbr_fingers * 2);
+
+       /* Check if F11_2D_Query7 is non-zero */
+       if (query->f11_2d_query7__8[0])
+               sensor->pkt_size += sizeof(u8);
+
+       /* Check if F11_2D_Query7 or F11_2D_Query8 is non-zero */
+       if (query->f11_2d_query7__8[0] || query->f11_2d_query7__8[1])
+               sensor->pkt_size += sizeof(u8);
+
+       if (query->has_pinch || query->has_flick || query->has_rotate) {
+               sensor->pkt_size += 3;
+               if (!query->has_flick)
+                       sensor->pkt_size--;
+               if (!query->has_rotate)
+                       sensor->pkt_size--;
+       }
+
+       if (query->has_touch_shapes)
+               sensor->pkt_size += F11_CEIL(query->nbr_touch_shapes + 1, 8);
+
+       sensor->data_pkt = kzalloc(sensor->pkt_size, GFP_KERNEL);
+       if (!sensor->data_pkt)
+               return -ENOMEM;
+
+       data->f_state = (struct f11_2d_data_0 *)sensor->data_pkt;
+       i = F11_CEIL(sensor->nbr_fingers, 4);
+
+       if (query->has_abs) {
+               data->abs_pos = (struct f11_2d_data_1_5 *)
+                               &sensor->data_pkt[i];
+               i += (sensor->nbr_fingers * 5);
+       }
+
+       if (query->has_rel) {
+               data->rel_pos = (struct f11_2d_data_6_7 *)
+                               &sensor->data_pkt[i];
+               i += (sensor->nbr_fingers * 2);
+       }
+
+       if (query->f11_2d_query7__8[0]) {
+               data->gest_1 = (struct f11_2d_data_8 *)&sensor->data_pkt[i];
+               i++;
+       }
+
+       if (query->f11_2d_query7__8[0] || query->f11_2d_query7__8[1]) {
+               data->gest_2 = (struct f11_2d_data_9 *)&sensor->data_pkt[i];
+               i++;
+       }
+
+       if (query->has_pinch) {
+               data->pinch = (struct f11_2d_data_10 *)&sensor->data_pkt[i];
+               i++;
+       }
+
+       if (query->has_flick) {
+               if (query->has_pinch) {
+                       data->flick = (struct f11_2d_data_10_12 *)data->pinch;
+                       i += 2;
+               } else {
+                       data->flick = (struct f11_2d_data_10_12 *)
+                                       &sensor->data_pkt[i];
+                       i += 3;
+               }
+       }
+
+       if (query->has_rotate) {
+               if (query->has_flick) {
+                       data->rotate = (struct f11_2d_data_11_12 *)
+                                       (data->flick + 1);
+               } else {
+                       data->rotate = (struct f11_2d_data_11_12 *)
+                                       &sensor->data_pkt[i];
+                       i += 2;
+               }
+       }
+
+       if (query->has_touch_shapes)
+               data->shapes = (struct f11_2d_data_13 *)&sensor->data_pkt[i];
+
+       return 0;
+}
+
+static int rmi_f11_read_control_parameters(struct rmi_device *rmi_dev,
+                                          struct f11_2d_device_query *query,
+                                          struct rmi_f11_2d_ctrl *ctrl,
+                                          int ctrl_base_addr) {
+       int read_address = ctrl_base_addr;
+       int error = 0;
+
+       if (ctrl->ctrl0) {
+               error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl0->reg,
+                       sizeof(union rmi_f11_2d_ctrl0));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F11 ctrl0, code: %d.\n", error);
+                       return error;
+               }
+               read_address = read_address + sizeof(union rmi_f11_2d_ctrl0);
+       }
+
+       if (ctrl->ctrl1) {
+               error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl1->reg,
+                       sizeof(union rmi_f11_2d_ctrl1));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F11 ctrl1, code: %d.\n", error);
+                       return error;
+               }
+               read_address = read_address + sizeof(union rmi_f11_2d_ctrl1);
+       }
+
+       if (ctrl->ctrl2__3) {
+               error = rmi_read_block(rmi_dev, read_address,
+                               ctrl->ctrl2__3->regs,
+                               sizeof(ctrl->ctrl2__3->regs));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F11 ctrl2__3, code: %d.\n",
+                               error);
+                       return error;
+               }
+               read_address = read_address + sizeof(ctrl->ctrl2__3->regs);
+       }
+
+       if (ctrl->ctrl4) {
+               error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl4->reg,
+                       sizeof(ctrl->ctrl4->reg));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F11 ctrl4, code: %d.\n", error);
+                       return error;
+               }
+               read_address = read_address + sizeof(ctrl->ctrl4->reg);
+       }
+
+       if (ctrl->ctrl5) {
+               error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl5->reg,
+                       sizeof(ctrl->ctrl5->reg));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F11 ctrl5, code: %d.\n", error);
+                       return error;
+               }
+               read_address = read_address + sizeof(ctrl->ctrl5->reg);
+       }
+
+       if (ctrl->ctrl6__7) {
+               error = rmi_read_block(rmi_dev, read_address,
+                               ctrl->ctrl6__7->regs,
+                               sizeof(ctrl->ctrl6__7->regs));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F11 ctrl6__7, code: %d.\n",
+                               error);
+                       return error;
+               }
+               read_address = read_address + sizeof(ctrl->ctrl6__7->regs);
+       }
+
+       if (ctrl->ctrl8__9) {
+               error = rmi_read_block(rmi_dev, read_address,
+                               ctrl->ctrl8__9->regs,
+                               sizeof(ctrl->ctrl8__9->regs));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F11 ctrl8__9, code: %d.\n",
+                               error);
+                       return error;
+               }
+               read_address = read_address + sizeof(ctrl->ctrl8__9->regs);
+       }
+
+       return 0;
+}
+
+static int rmi_f11_initialize_control_parameters(struct rmi_device *rmi_dev,
+                                          struct f11_2d_device_query *query,
+                                          struct rmi_f11_2d_ctrl *ctrl,
+                                          int ctrl_base_addr) {
+       int error = 0;
+
+       ctrl->ctrl0 = kzalloc(sizeof(union rmi_f11_2d_ctrl0), GFP_KERNEL);
+       if (!ctrl->ctrl0) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl0.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       ctrl->ctrl1 = kzalloc(sizeof(union rmi_f11_2d_ctrl1), GFP_KERNEL);
+       if (!ctrl->ctrl1) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl1.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       ctrl->ctrl2__3 = kzalloc(sizeof(union rmi_f11_2d_ctrl2__3), GFP_KERNEL);
+       if (!ctrl->ctrl2__3) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl2__3.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       ctrl->ctrl4 = kzalloc(sizeof(union rmi_f11_2d_ctrl4), GFP_KERNEL);
+       if (!ctrl->ctrl4) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl4.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       ctrl->ctrl5 = kzalloc(sizeof(union rmi_f11_2d_ctrl5), GFP_KERNEL);
+       if (!ctrl->ctrl5) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl5.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       ctrl->ctrl6__7 = kzalloc(sizeof(union rmi_f11_2d_ctrl6__7), GFP_KERNEL);
+       if (!ctrl->ctrl6__7) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl6__7.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       ctrl->ctrl8__9 = kzalloc(sizeof(union rmi_f11_2d_ctrl8__9), GFP_KERNEL);
+       if (!ctrl->ctrl8__9) {
+               dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl8__9.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       return rmi_f11_read_control_parameters(rmi_dev, query,
+                                              ctrl, ctrl_base_addr);
+
+error_exit:
+       kfree(ctrl->ctrl0);
+       kfree(ctrl->ctrl1);
+       kfree(ctrl->ctrl2__3);
+       kfree(ctrl->ctrl4);
+       kfree(ctrl->ctrl5);
+       kfree(ctrl->ctrl6__7);
+       kfree(ctrl->ctrl8__9);
+
+       return error;
+}
+
+static inline int rmi_f11_set_control_parameters(struct rmi_device *rmi_dev,
+                                       struct f11_2d_sensor_query *query,
+                                       struct rmi_f11_2d_ctrl *ctrl,
+                                       int ctrl_base_addr)
+{
+       int write_address = ctrl_base_addr;
+       int error;
+
+       if (ctrl->ctrl0) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl0->reg,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl1) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl1->reg,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl2__3) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       ctrl->ctrl2__3->regs,
+                                       sizeof(ctrl->ctrl2__3->regs));
+               if (error < 0)
+                       return error;
+               write_address += sizeof(ctrl->ctrl2__3->regs);
+       }
+
+       if (ctrl->ctrl4) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl4->reg,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl5) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl5->reg,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl6__7) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl6__7->regs[0],
+                                       sizeof(ctrl->ctrl6__7->regs));
+               if (error < 0)
+                       return error;
+               write_address += sizeof(ctrl->ctrl6__7->regs);
+       }
+
+       if (ctrl->ctrl8__9) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl8__9->regs[0],
+                                       sizeof(ctrl->ctrl8__9->regs));
+               if (error < 0)
+                       return error;
+               write_address += sizeof(ctrl->ctrl8__9->regs);
+       }
+
+       if (ctrl->ctrl10) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl10->reg,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl11) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       &ctrl->ctrl11->reg,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl12 && ctrl->ctrl12_size && query->configurable) {
+               if (ctrl->ctrl12_size > query->max_electrodes) {
+                       dev_err(&rmi_dev->dev,
+                               "%s: invalid cfg size:%d, should be < %d.\n",
+                               __func__, ctrl->ctrl12_size,
+                               query->max_electrodes);
+                       return -EINVAL;
+               }
+               error = rmi_write_block(rmi_dev, write_address,
+                                               &ctrl->ctrl12->reg,
+                                               ctrl->ctrl12_size);
+               if (error < 0)
+                       return error;
+               write_address += ctrl->ctrl12_size;
+       }
+
+       if (ctrl->ctrl14) {
+               error = rmi_write_block(rmi_dev,
+                                       write_address,
+                                       &ctrl->ctrl0->reg,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl15) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       ctrl->ctrl15,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl16) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       ctrl->ctrl16,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl17) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       ctrl->ctrl17,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl18) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       ctrl->ctrl18,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       if (ctrl->ctrl19) {
+               error = rmi_write_block(rmi_dev, write_address,
+                                       ctrl->ctrl19,
+                                       1);
+               if (error < 0)
+                       return error;
+               write_address++;
+       }
+
+       return 0;
+}
+
+static inline int rmi_f11_get_query_parameters(struct rmi_device *rmi_dev,
+                       struct f11_2d_sensor_query *query, u8 query_base_addr)
+{
+       int query_size;
+       int rc;
+
+       rc = rmi_read_block(rmi_dev, query_base_addr, query->f11_2d_query1__4,
+                                       sizeof(query->f11_2d_query1__4));
+       if (rc < 0)
+               return rc;
+       query_size = rc;
+
+       if (query->has_abs) {
+               rc = rmi_read(rmi_dev, query_base_addr + query_size,
+                                       &query->f11_2d_query5);
+               if (rc < 0)
+                       return rc;
+               query_size++;
+       }
+
+       if (query->has_rel) {
+               rc = rmi_read(rmi_dev, query_base_addr + query_size,
+                                       &query->f11_2d_query6);
+               if (rc < 0)
+                       return rc;
+               query_size++;
+       }
+
+       if (query->has_gestures) {
+               rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
+                                       query->f11_2d_query7__8,
+                                       sizeof(query->f11_2d_query7__8));
+               if (rc < 0)
+                       return rc;
+               query_size += sizeof(query->f11_2d_query7__8);
+       }
+
+       if (query->has_touch_shapes) {
+               rc = rmi_read(rmi_dev, query_base_addr + query_size,
+                                       &query->f11_2d_query10);
+               if (rc < 0)
+                       return rc;
+               query_size++;
+       }
+
+       return query_size;
+}
+
+/* This operation is done in a number of places, so we have a handy routine
+ * for it.
+ */
+static void f11_set_abs_params(struct rmi_function_container *fc, int index)
+{
+       struct f11_data *instance_data =  fc->data;
+       struct input_dev *input = instance_data->sensors[index].input;
+       int device_x_max =
+               instance_data->dev_controls.ctrl6__7->sensor_max_x_pos;
+       int device_y_max =
+               instance_data->dev_controls.ctrl8__9->sensor_max_y_pos;
+       int x_min, x_max, y_min, y_max;
+
+       if (instance_data->sensors[index].axis_align.swap_axes) {
+               int temp = device_x_max;
+               device_x_max = device_y_max;
+               device_y_max = temp;
+       }
+
+       /* Use the max X and max Y read from the device, or the clip values,
+        * whichever is stricter.
+        */
+       x_min = instance_data->sensors[index].axis_align.clip_X_low;
+       if (instance_data->sensors[index].axis_align.clip_X_high)
+               x_max = min((int) device_x_max,
+                       instance_data->sensors[index].axis_align.clip_X_high);
+       else
+               x_max = device_x_max;
+
+       y_min = instance_data->sensors[index].axis_align.clip_Y_low;
+       if (instance_data->sensors[index].axis_align.clip_Y_high)
+               y_max = min((int) device_y_max,
+                       instance_data->sensors[index].axis_align.clip_Y_high);
+       else
+               y_max = device_y_max;
+
+       dev_dbg(&fc->dev, "Set ranges X=[%d..%d] Y=[%d..%d].",
+                       x_min, x_max, y_min, y_max);
+
+#ifdef ABS_MT_PRESSURE
+               input_set_abs_params(input, ABS_MT_PRESSURE, 0,
+                               DEFAULT_MAX_ABS_MT_PRESSURE, 0, 0);
+#endif
+               input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
+                               0, DEFAULT_MAX_ABS_MT_TOUCH, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
+                               0, DEFAULT_MAX_ABS_MT_TOUCH, 0, 0);
+               input_set_abs_params(input, ABS_MT_ORIENTATION,
+                               0, DEFAULT_MAX_ABS_MT_ORIENTATION, 0, 0);
+               input_set_abs_params(input, ABS_MT_TRACKING_ID,
+                               DEFAULT_MIN_ABS_MT_TRACKING_ID,
+                               DEFAULT_MAX_ABS_MT_TRACKING_ID, 0, 0);
+               /* TODO get max_x_pos (and y) from control registers. */
+               input_set_abs_params(input, ABS_MT_POSITION_X,
+                               x_min, x_max, 0, 0);
+               input_set_abs_params(input, ABS_MT_POSITION_Y,
+                               y_min, y_max, 0, 0);
+}
+
+static int rmi_f11_init(struct rmi_function_container *fc)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct rmi_device_platform_data *pdata;
+       struct f11_data *f11;
+       struct input_dev *input_dev;
+       struct input_dev *input_dev_mouse;
+       u8 query_offset;
+       u8 query_base_addr;
+       u8 control_base_addr;
+       u16 max_x_pos, max_y_pos, temp;
+       int rc;
+       int i;
+       int retval = 0;
+       int attr_count = 0;
+
+       dev_info(&fc->dev, "Intializing F11 values.");
+
+       /*
+       ** init instance data, fill in values and create any sysfs files
+       */
+       f11 = kzalloc(sizeof(struct f11_data), GFP_KERNEL);
+       if (!f11)
+               return -ENOMEM;
+       fc->data = f11;
+
+       query_base_addr = fc->fd.query_base_addr;
+       control_base_addr = fc->fd.control_base_addr;
+
+       rc = rmi_read(rmi_dev, query_base_addr, &f11->dev_query.f11_2d_query0);
+       if (rc < 0)
+               goto err_free_data;
+
+       rc = rmi_f11_initialize_control_parameters(rmi_dev, &f11->dev_query,
+                                       &f11->dev_controls, control_base_addr);
+       if (rc < 0) {
+               dev_err(&fc->dev,
+                       "Failed to initialize F11 control params.\n");
+               goto err_free_data;
+       }
+
+       query_offset = (query_base_addr + 1);
+       /* Increase with one since number of sensors is zero based */
+       for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) {
+               f11->sensors[i].sensor_index = i;
+
+               rc = rmi_f11_get_query_parameters(rmi_dev,
+                                       &f11->sensors[i].sens_query,
+                                       query_offset);
+               if (rc < 0)
+                       goto err_free_data;
+
+               query_offset += rc;
+
+               pdata = to_rmi_platform_data(rmi_dev);
+               if (pdata)
+                       f11->sensors[i].axis_align = pdata->axis_align;
+
+               if (pdata && pdata->f11_ctrl) {
+                       rc = rmi_f11_set_control_parameters(rmi_dev,
+                                               &f11->sensors[i].sens_query,
+                                               pdata->f11_ctrl,
+                                               control_base_addr);
+                       if (rc < 0)
+                               goto err_free_data;
+               }
+
+               if (pdata && pdata->f11_ctrl &&
+                               pdata->f11_ctrl->ctrl6__7 &&
+                               pdata->f11_ctrl->ctrl8__9) {
+                       max_x_pos = pdata->f11_ctrl->ctrl6__7->sensor_max_x_pos;
+                       max_y_pos = pdata->f11_ctrl->ctrl8__9->sensor_max_y_pos;
+
+               } else {
+                       rc = rmi_read_block(rmi_dev,
+                         control_base_addr + F11_CTRL_SENSOR_MAX_X_POS_OFFSET,
+                         (u8 *)&max_x_pos, sizeof(max_x_pos));
+                       if (rc < 0)
+                               goto err_free_data;
+
+                       rc = rmi_read_block(rmi_dev,
+                         control_base_addr + F11_CTRL_SENSOR_MAX_Y_POS_OFFSET,
+                         (u8 *)&max_y_pos, sizeof(max_y_pos));
+                       if (rc < 0)
+                               goto err_free_data;
+               }
+
+               if (pdata->axis_align.swap_axes) {
+                       temp = max_x_pos;
+                       max_x_pos = max_y_pos;
+                       max_y_pos = temp;
+               }
+               f11->sensors[i].max_x = max_x_pos;
+               f11->sensors[i].max_y = max_y_pos;
+
+               rc = rmi_f11_2d_construct_data(&f11->sensors[i]);
+               if (rc < 0)
+                       goto err_free_data;
+
+               input_dev = input_allocate_device();
+               if (!input_dev) {
+                       rc = -ENOMEM;
+                       goto err_free_data;
+               }
+
+               f11->sensors[i].input = input_dev;
+               /* TODO how to modify the dev name and
+               * phys name for input device */
+               sprintf(f11->sensors[i].input_name, "%sfn%02x",
+                       dev_name(&rmi_dev->dev), fc->fd.function_number);
+               input_dev->name = f11->sensors[i].input_name;
+               sprintf(f11->sensors[i].input_phys, "%s/input0",
+                       input_dev->name);
+               input_dev->phys = f11->sensors[i].input_phys;
+               input_dev->dev.parent = &rmi_dev->dev;
+               input_set_drvdata(input_dev, f11);
+
+               set_bit(EV_SYN, input_dev->evbit);
+               set_bit(EV_KEY, input_dev->evbit);
+               set_bit(EV_ABS, input_dev->evbit);
+
+               f11_set_abs_params(fc, i);
+
+               dev_dbg(&fc->dev, "%s: Sensor %d hasRel %d.\n",
+                       __func__, i, f11->sensors[i].sens_query.has_rel);
+               if (f11->sensors[i].sens_query.has_rel) {
+                       set_bit(EV_REL, input_dev->evbit);
+                       set_bit(REL_X, input_dev->relbit);
+                       set_bit(REL_Y, input_dev->relbit);
+               }
+               rc = input_register_device(input_dev);
+               if (rc < 0)
+                       goto err_free_input;
+
+               if (f11->sensors[i].sens_query.has_rel) {
+                       /*create input device for mouse events  */
+                       input_dev_mouse = input_allocate_device();
+                       if (!input_dev_mouse) {
+                               rc = -ENOMEM;
+                               goto err_free_data;
+                       }
+
+                       f11->sensors[i].mouse_input = input_dev_mouse;
+                       input_dev_mouse->name = "rmi_mouse";
+                       input_dev_mouse->phys = "rmi_f11/input0";
+
+                       input_dev_mouse->id.vendor  = 0x18d1;
+                       input_dev_mouse->id.product = 0x0210;
+                       input_dev_mouse->id.version = 0x0100;
+
+                       set_bit(EV_REL, input_dev_mouse->evbit);
+                       set_bit(REL_X, input_dev_mouse->relbit);
+                       set_bit(REL_Y, input_dev_mouse->relbit);
+
+                       set_bit(BTN_MOUSE, input_dev_mouse->evbit);
+                       /* Register device's buttons and keys */
+                       set_bit(EV_KEY, input_dev_mouse->evbit);
+                       set_bit(BTN_LEFT, input_dev_mouse->keybit);
+                       set_bit(BTN_MIDDLE, input_dev_mouse->keybit);
+                       set_bit(BTN_RIGHT, input_dev_mouse->keybit);
+
+                       rc = input_register_device(input_dev_mouse);
+                       if (rc < 0)
+                               goto err_free_input;
+                               set_bit(BTN_RIGHT, input_dev_mouse->keybit);
+               }
+
+       }
+
+       dev_info(&fc->dev, "Creating sysfs files.");
+       dev_dbg(&fc->dev, "Creating fn11 sysfs files.");
+
+       /* Set up sysfs device attributes. */
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               if (sysfs_create_file
+                   (&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
+                       dev_err(&fc->dev, "Failed to create sysfs file for %s.",
+                                attrs[attr_count].attr.name);
+                       retval = -ENODEV;
+                       goto err_free_input;
+               }
+       }
+
+       dev_info(&fc->dev, "Done Creating fn11 sysfs files.");
+       return 0;
+
+err_free_input:
+       for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) {
+               if (f11->sensors[i].input)
+                       input_free_device(f11->sensors[i].input);
+               if (f11->sensors[i].sens_query.has_rel &&
+                               f11->sensors[i].mouse_input)
+                       input_free_device(f11->sensors[i].mouse_input);
+       }
+err_free_data:
+       for (attr_count--; attr_count >= 0; attr_count--)
+               device_remove_file(&fc->rmi_dev->dev, &attrs[attr_count]);
+
+       kfree(f11);
+       return rc;
+}
+
+int rmi_f11_attention(struct rmi_function_container *fc, u8 *irq_bits)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct f11_data *f11 = fc->data;
+       u8 data_base_addr = fc->fd.data_base_addr;
+       int data_base_addr_offset = 0;
+       int error;
+       int i;
+
+       for (i = 0; i < f11->dev_query.nbr_of_sensors + 1; i++) {
+               error = rmi_read_block(rmi_dev,
+                               data_base_addr + data_base_addr_offset,
+                               f11->sensors[i].data_pkt,
+                               f11->sensors[i].pkt_size);
+               if (error < 0)
+                       return error;
+
+               rmi_f11_finger_handler(&f11->sensors[i]);
+               data_base_addr_offset += f11->sensors[i].pkt_size;
+       }
+       return 0;
+}
+
+static void rmi_f11_remove(struct rmi_function_container *fc)
+{
+       struct f11_data *data = fc->data;
+       int i;
+
+       for (i = 0; i < (data->dev_query.nbr_of_sensors + 1); i++) {
+               input_unregister_device(data->sensors[i].input);
+               if (data->sensors[i].sens_query.has_rel)
+                       input_unregister_device(data->sensors[i].mouse_input);
+       }
+       kfree(fc->data);
+}
+
+static struct rmi_function_handler function_handler = {
+       .func = 0x11,
+       .init = rmi_f11_init,
+       .attention = rmi_f11_attention,
+       .remove = rmi_f11_remove
+};
+
+static int __init rmi_f11_module_init(void)
+{
+       int error;
+
+       error = rmi_register_function_driver(&function_handler);
+       if (error < 0) {
+               pr_err("%s: register failed!\n", __func__);
+               return error;
+       }
+
+       return 0;
+}
+
+static void __exit rmi_f11_module_exit(void)
+{
+       rmi_unregister_function_driver(&function_handler);
+}
+
+static ssize_t rmi_fn_11_maxPos_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u %u\n",
+                       data->sensors[0].max_x, data->sensors[0].max_y);
+}
+
+static ssize_t rmi_fn_11_flip_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u %u\n",
+                       data->sensors[0].axis_align.flip_x,
+                       data->sensors[0].axis_align.flip_y);
+}
+
+static ssize_t rmi_fn_11_flip_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf,
+                                   size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+       unsigned int new_X, new_Y;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+
+       if (sscanf(buf, "%u %u", &new_X, &new_Y) != 2)
+               return -EINVAL;
+       if (new_X < 0 || new_X > 1 || new_Y < 0 || new_Y > 1)
+               return -EINVAL;
+       instance_data->sensors[0].axis_align.flip_x = new_X;
+       instance_data->sensors[0].axis_align.flip_y = new_Y;
+
+       return count;
+}
+
+static ssize_t rmi_fn_11_swap_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       instance_data->sensors[0].axis_align.swap_axes);
+}
+
+static ssize_t rmi_fn_11_swap_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+       unsigned int newSwap;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+
+       if (sscanf(buf, "%u", &newSwap) != 1)
+               return -EINVAL;
+       if (newSwap < 0 || newSwap > 1)
+               return -EINVAL;
+       instance_data->sensors[0].axis_align.swap_axes = newSwap;
+
+       f11_set_abs_params(fc, 0);
+
+       return count;
+}
+
+static ssize_t rmi_fn_11_relreport_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       instance_data->
+                       sensors[0].axis_align.rel_report_enabled);
+}
+
+static ssize_t rmi_fn_11_relreport_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf,
+                                        size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+       unsigned int new_value;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+
+       if (sscanf(buf, "%u", &new_value) != 1)
+               return -EINVAL;
+       if (new_value < 0 || new_value > 1)
+               return -EINVAL;
+       instance_data->sensors[0].axis_align.rel_report_enabled = new_value;
+
+       return count;
+}
+
+static ssize_t rmi_fn_11_offset_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d %d\n",
+                       instance_data->sensors[0].axis_align.offset_X,
+                       instance_data->sensors[0].axis_align.offset_Y);
+}
+
+static ssize_t rmi_fn_11_offset_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf,
+                                     size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+       int new_X, new_Y;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+
+       if (sscanf(buf, "%d %d", &new_X, &new_Y) != 2)
+               return -EINVAL;
+       instance_data->sensors[0].axis_align.offset_X = new_X;
+       instance_data->sensors[0].axis_align.offset_Y = new_Y;
+
+       return count;
+}
+
+static ssize_t rmi_fn_11_clip_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u %u %u %u\n",
+                       instance_data->sensors[0].axis_align.clip_X_low,
+                       instance_data->sensors[0].axis_align.clip_X_high,
+                       instance_data->sensors[0].axis_align.clip_Y_low,
+                       instance_data->sensors[0].axis_align.clip_Y_high);
+}
+
+static ssize_t rmi_fn_11_clip_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf,
+                                   size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f11_data *instance_data;
+       unsigned int new_X_low, new_X_high, new_Y_low, new_Y_high;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       if (sscanf(buf, "%u %u %u %u",
+                  &new_X_low, &new_X_high, &new_Y_low, &new_Y_high) != 4)
+               return -EINVAL;
+       if (new_X_low < 0 || new_X_low >= new_X_high || new_Y_low < 0
+           || new_Y_low >= new_Y_high)
+               return -EINVAL;
+       instance_data->sensors[0].axis_align.clip_X_low = new_X_low;
+       instance_data->sensors[0].axis_align.clip_X_high = new_X_high;
+       instance_data->sensors[0].axis_align.clip_Y_low = new_Y_low;
+       instance_data->sensors[0].axis_align.clip_Y_high = new_Y_high;
+
+       /*
+       ** for now, we assume this is sensor index 0
+       */
+       f11_set_abs_params(fc, 0);
+
+       return count;
+}
+
+static ssize_t rmi_f11_rezero_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct rmi_function_container *fc = NULL;
+       unsigned int rezero;
+       int retval = 0;
+       /* Command register always reads as 0, so we can just use a local. */
+       union f11_2d_commands commands = {};
+
+       fc = to_rmi_function_container(dev);
+
+       if (sscanf(buf, "%u", &rezero) != 1)
+               return -EINVAL;
+       if (rezero < 0 || rezero > 1)
+               return -EINVAL;
+
+       /* Per spec, 0 has no effect, so we skip it entirely. */
+       if (rezero) {
+               commands.rezero = 1;
+               retval = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr,
+                               &commands.reg, sizeof(commands.reg));
+               if (retval < 0) {
+                       dev_err(dev, "%s: failed to issue rezero command, "
+                               "error = %d.", __func__, retval);
+                       return retval;
+               }
+       }
+
+       return count;
+}
+
+
+module_init(rmi_f11_module_init);
+module_exit(rmi_f11_module_exit);
+
+MODULE_AUTHOR("Stefan Nilsson <stefan.nilsson@unixphere.com>");
+MODULE_DESCRIPTION("RMI F11 module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi4/rmi_f19.c b/drivers/input/touchscreen/rmi4/rmi_f19.c
new file mode 100644 (file)
index 0000000..9ff9ff9
--- /dev/null
@@ -0,0 +1,1419 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#define QUERY_BASE_INDEX 1
+#define MAX_LEN 256
+
+struct f19_0d_query {
+       union {
+               struct {
+                       u8 configurable:1;
+                       u8 has_sensitivity_adjust:1;
+                       u8 has_hysteresis_threshold:1;
+               };
+               u8 f19_0d_query0;
+       };
+       u8 f19_0d_query1:5;
+};
+
+struct f19_0d_control_0 {
+       union {
+               struct {
+                       u8 button_usage:2;
+                       u8 filter_mode:2;
+               };
+               u8 f19_0d_control0;
+       };
+};
+
+struct f19_0d_control_1 {
+       u8 int_enabled_button;
+};
+
+struct f19_0d_control_2 {
+       u8 single_button;
+};
+
+struct f19_0d_control_3_4 {
+       u8 sensor_map_button:7;
+       /*u8 sensitivity_button;*/
+};
+
+struct f19_0d_control_5 {
+       u8 sensitivity_adj;
+};
+struct f19_0d_control_6 {
+       u8 hysteresis_threshold;
+};
+
+struct f19_0d_control {
+       struct f19_0d_control_0 *general_control;
+       struct f19_0d_control_1 *button_int_enable;
+       struct f19_0d_control_2 *single_button_participation;
+       struct f19_0d_control_3_4 *sensor_map;
+       struct f19_0d_control_5 *all_button_sensitivity_adj;
+       struct f19_0d_control_6 *all_button_hysteresis_threshold;
+};
+/* data specific to fn $19 that needs to be kept around */
+struct f19_data {
+       struct f19_0d_control *button_control;
+       struct f19_0d_query button_query;
+       u8 button_rezero;
+       bool *button_down;
+       unsigned char button_count;
+       unsigned char button_data_buffer_size;
+       unsigned char *button_data_buffer;
+       unsigned char *button_map;
+       char input_name[MAX_LEN];
+       char input_phys[MAX_LEN];
+       struct input_dev *input;
+};
+
+static ssize_t rmi_f19_button_count_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+
+static ssize_t rmi_f19_button_map_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f19_button_map_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count);
+static ssize_t rmi_f19_rezero_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_rezero_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t rmi_f19_has_hysteresis_threshold_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+static ssize_t rmi_f19_has_sensitivity_adjust_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+static ssize_t rmi_f19_configurable_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf);
+static ssize_t rmi_f19_filter_mode_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_filter_mode_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t rmi_f19_button_usage_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_button_usage_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t rmi_f19_interrupt_enable_button_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_interrupt_enable_button_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t rmi_f19_single_button_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_single_button_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t rmi_f19_sensor_map_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_sensor_map_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t rmi_f19_sensitivity_adjust_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_sensitivity_adjust_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+static ssize_t rmi_f19_hysteresis_threshold_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf);
+static ssize_t rmi_f19_hysteresis_threshold_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count);
+
+
+static struct device_attribute attrs[] = {
+       __ATTR(button_count, RMI_RO_ATTR,
+               rmi_f19_button_count_show, rmi_store_error),
+       __ATTR(button_map, RMI_RW_ATTR,
+               rmi_f19_button_map_show, rmi_f19_button_map_store),
+       __ATTR(rezero, RMI_RW_ATTR,
+               rmi_f19_rezero_show, rmi_f19_rezero_store),
+       __ATTR(has_hysteresis_threshold, RMI_RO_ATTR,
+               rmi_f19_has_hysteresis_threshold_show, rmi_store_error),
+       __ATTR(has_sensitivity_adjust, RMI_RO_ATTR,
+               rmi_f19_has_sensitivity_adjust_show, rmi_store_error),
+       __ATTR(configurable, RMI_RO_ATTR,
+               rmi_f19_configurable_show, rmi_store_error),
+       __ATTR(filter_mode, RMI_RW_ATTR,
+               rmi_f19_filter_mode_show, rmi_f19_filter_mode_store),
+       __ATTR(button_usage, RMI_RW_ATTR,
+               rmi_f19_button_usage_show, rmi_f19_button_usage_store),
+       __ATTR(interrupt_enable_button, RMI_RW_ATTR,
+               rmi_f19_interrupt_enable_button_show,
+               rmi_f19_interrupt_enable_button_store),
+       __ATTR(single_button, RMI_RW_ATTR,
+               rmi_f19_single_button_show, rmi_f19_single_button_store),
+       __ATTR(sensor_map, RMI_RW_ATTR,
+               rmi_f19_sensor_map_show, rmi_f19_sensor_map_store),
+       __ATTR(sensitivity_adjust, RMI_RW_ATTR,
+               rmi_f19_sensitivity_adjust_show,
+               rmi_f19_sensitivity_adjust_store),
+       __ATTR(hysteresis_threshold, RMI_RW_ATTR,
+               rmi_f19_hysteresis_threshold_show,
+               rmi_f19_hysteresis_threshold_store)
+};
+
+
+int rmi_f19_read_control_parameters(struct rmi_device *rmi_dev,
+       struct f19_0d_control *button_control,
+       unsigned char button_count,
+       unsigned char int_button_enabled_count,
+       u8 ctrl_base_addr)
+{
+       int error = 0;
+       int i;
+
+       if (button_control->general_control) {
+               error = rmi_read_block(rmi_dev, ctrl_base_addr,
+                               (u8 *)button_control->general_control,
+                               sizeof(struct f19_0d_control_0));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read f19_0d_control_0, code:"
+                               " %d.\n", error);
+                       return error;
+               }
+               ctrl_base_addr = ctrl_base_addr +
+                               sizeof(struct f19_0d_control_0);
+       }
+
+       if (button_control->button_int_enable) {
+               for (i = 0; i < int_button_enabled_count; i++) {
+                       error = rmi_read_block(rmi_dev, ctrl_base_addr,
+                               (u8 *)&button_control->button_int_enable[i],
+                               sizeof(struct f19_0d_control_1));
+                       if (error < 0) {
+                               dev_err(&rmi_dev->dev,
+                                       "Failed to read f19_0d_control_2,"
+                                       " code: %d.\n", error);
+                               return error;
+                       }
+                       ctrl_base_addr = ctrl_base_addr +
+                               sizeof(struct f19_0d_control_1);
+               }
+       }
+
+       if (button_control->single_button_participation) {
+               for (i = 0; i < int_button_enabled_count; i++) {
+                       error = rmi_read_block(rmi_dev, ctrl_base_addr,
+                                       (u8 *)&button_control->
+                                               single_button_participation[i],
+                                       sizeof(struct f19_0d_control_2));
+                       if (error < 0) {
+                               dev_err(&rmi_dev->dev,
+                                       "Failed to read f19_0d_control_2,"
+                                       " code: %d.\n", error);
+                               return error;
+                       }
+                       ctrl_base_addr = ctrl_base_addr +
+                               sizeof(struct f19_0d_control_2);
+               }
+       }
+
+       if (button_control->sensor_map) {
+               for (i = 0; i < button_count; i++) {
+                       error = rmi_read_block(rmi_dev, ctrl_base_addr,
+                                       (u8 *)&button_control->sensor_map[i],
+                                       sizeof(struct f19_0d_control_3_4));
+                       if (error < 0) {
+                               dev_err(&rmi_dev->dev,
+                               "Failed to read f19_0d_control_3_4,"
+                               " code: %d.\n", error);
+                               return error;
+                       }
+                       ctrl_base_addr = ctrl_base_addr +
+                               sizeof(struct f19_0d_control_3_4);
+               }
+       }
+
+       if (button_control->all_button_sensitivity_adj) {
+               error = rmi_read_block(rmi_dev, ctrl_base_addr,
+                               (u8 *)button_control->
+                                       all_button_sensitivity_adj,
+                               sizeof(struct f19_0d_control_5));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read f19_0d_control_5,"
+                               " code: %d.\n", error);
+                       return error;
+               }
+               ctrl_base_addr = ctrl_base_addr +
+                       sizeof(struct f19_0d_control_5);
+       }
+
+       if (button_control->all_button_hysteresis_threshold) {
+               error = rmi_read_block(rmi_dev, ctrl_base_addr,
+                               (u8 *)button_control->
+                                       all_button_hysteresis_threshold,
+                               sizeof(struct f19_0d_control_6));
+               if (error < 0) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read f19_0d_control_6,"
+                               " code: %d.\n", error);
+                       return error;
+               }
+               ctrl_base_addr = ctrl_base_addr +
+                       sizeof(struct f19_0d_control_6);
+       }
+       return 0;
+}
+
+
+int rmi_f19_initialize_control_parameters(struct rmi_device *rmi_dev,
+       struct f19_0d_control *button_control,
+       unsigned char button_count,
+       unsigned char int_button_enabled_count,
+       int control_base_addr)
+{
+       int error = 0;
+
+       button_control->general_control =
+               kzalloc(sizeof(struct f19_0d_control_0), GFP_KERNEL);
+       if (!button_control->general_control) {
+               dev_err(&rmi_dev->dev, "Failed to allocate"
+                       " f19_0d_control_0.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       button_control->button_int_enable =
+               kzalloc(int_button_enabled_count *
+                       sizeof(struct f19_0d_control_2), GFP_KERNEL);
+       if (!button_control->button_int_enable) {
+               dev_err(&rmi_dev->dev, "Failed to allocate f19_0d_control_1.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       button_control->single_button_participation =
+               kzalloc(int_button_enabled_count *
+                       sizeof(struct f19_0d_control_2), GFP_KERNEL);
+       if (!button_control->single_button_participation) {
+               dev_err(&rmi_dev->dev, "Failed to allocate"
+                       " f19_0d_control_2.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       button_control->sensor_map =
+               kzalloc(button_count *
+                       sizeof(struct f19_0d_control_3_4), GFP_KERNEL);
+       if (!button_control->sensor_map) {
+               dev_err(&rmi_dev->dev, "Failed to allocate"
+                       " f19_0d_control_3_4.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       button_control->all_button_sensitivity_adj =
+               kzalloc(sizeof(struct f19_0d_control_5), GFP_KERNEL);
+       if (!button_control->all_button_sensitivity_adj) {
+               dev_err(&rmi_dev->dev, "Failed to allocate"
+                       " f19_0d_control_5.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+
+       button_control->all_button_hysteresis_threshold =
+               kzalloc(sizeof(struct f19_0d_control_6), GFP_KERNEL);
+       if (!button_control->all_button_hysteresis_threshold) {
+               dev_err(&rmi_dev->dev, "Failed to allocate"
+                       " f19_0d_control_6.\n");
+               error = -ENOMEM;
+               goto error_exit;
+       }
+       return rmi_f19_read_control_parameters(rmi_dev, button_control,
+               button_count, int_button_enabled_count, control_base_addr);
+
+error_exit:
+       kfree(button_control->general_control);
+       kfree(button_control->button_int_enable);
+       kfree(button_control->single_button_participation);
+       kfree(button_control->sensor_map);
+       kfree(button_control->all_button_sensitivity_adj);
+       kfree(button_control->all_button_hysteresis_threshold);
+       return error;
+}
+
+static int rmi_f19_init(struct rmi_function_container *fc)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct rmi_device_platform_data *pdata;
+       struct f19_data *f19;
+       struct input_dev *input_dev;
+       u8 query_base_addr;
+       int rc;
+       int i;
+       int attr_count = 0;
+
+       dev_info(&fc->dev, "Intializing F19 values.");
+
+       f19 = kzalloc(sizeof(struct f19_data), GFP_KERNEL);
+       if (!f19) {
+               dev_err(&fc->dev, "Failed to allocate function data.\n");
+               return -ENOMEM;
+       }
+       pdata = to_rmi_platform_data(rmi_dev);
+       query_base_addr = fc->fd.query_base_addr;
+
+       /* initial all default values for f19 data here */
+       rc = rmi_read(rmi_dev, fc->fd.command_base_addr,
+               (u8 *)&f19->button_rezero);
+       if (rc < 0) {
+               dev_err(&fc->dev, "Failed to read command register.\n");
+               goto err_free_data;
+       }
+
+       f19->button_rezero = f19->button_rezero & 1;
+
+       rc = rmi_read_block(rmi_dev, query_base_addr, (u8 *)&f19->button_query,
+                       sizeof(struct f19_0d_query));
+       f19->button_count = f19->button_query.f19_0d_query1;
+
+       if (rc < 0) {
+               dev_err(&fc->dev, "Failed to read query register.\n");
+               goto err_free_data;
+       }
+
+
+       /* Figure out just how much data we'll need to read. */
+       f19->button_down = kcalloc(f19->button_count,
+                       sizeof(bool), GFP_KERNEL);
+       if (!f19->button_down) {
+               dev_err(&fc->dev, "Failed to allocate button state buffer.\n");
+               rc = -ENOMEM;
+               goto err_free_data;
+       }
+
+       f19->button_data_buffer_size = (f19->button_count + 7) / 8;
+       f19->button_data_buffer =
+           kcalloc(f19->button_data_buffer_size,
+                   sizeof(unsigned char), GFP_KERNEL);
+       if (!f19->button_data_buffer) {
+               dev_err(&fc->dev, "Failed to allocate button data buffer.\n");
+               rc = -ENOMEM;
+               goto err_free_data;
+       }
+
+       f19->button_map = kcalloc(f19->button_count,
+                               sizeof(unsigned char), GFP_KERNEL);
+       if (!f19->button_map) {
+               dev_err(&fc->dev, "Failed to allocate button map.\n");
+               rc = -ENOMEM;
+               goto err_free_data;
+       }
+
+       if (pdata) {
+               if (pdata->button_map->nbuttons != f19->button_count) {
+                       dev_warn(&fc->dev,
+                               "Platformdata button map size (%d) != number "
+                               "of buttons on device (%d) - ignored.\n",
+                               pdata->button_map->nbuttons,
+                               f19->button_count);
+               } else if (!pdata->button_map->map) {
+                       dev_warn(&fc->dev,
+                                "Platformdata button map is missing!\n");
+               } else {
+                       for (i = 0; i < pdata->button_map->nbuttons; i++)
+                               f19->button_map[i] = pdata->button_map->map[i];
+               }
+       }
+
+       f19->button_control = kzalloc(sizeof(struct f19_0d_control),
+                               GFP_KERNEL);
+
+       rc = rmi_f19_initialize_control_parameters(fc->rmi_dev,
+               f19->button_control, f19->button_count,
+               f19->button_data_buffer_size, fc->fd.control_base_addr);
+       if (rc < 0) {
+               dev_err(&fc->dev,
+                       "Failed to initialize F19 control params.\n");
+               goto err_free_data;
+       }
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(&fc->dev, "Failed to allocate input device.\n");
+               rc = -ENOMEM;
+               goto err_free_data;
+       }
+
+       f19->input = input_dev;
+       snprintf(f19->input_name, MAX_LEN, "%sfn%02x", dev_name(&rmi_dev->dev),
+               fc->fd.function_number);
+       input_dev->name = f19->input_name;
+       snprintf(f19->input_phys, MAX_LEN, "%s/input0", input_dev->name);
+       input_dev->phys = f19->input_phys;
+       input_dev->dev.parent = &rmi_dev->dev;
+       input_set_drvdata(input_dev, f19);
+
+       /* Set up any input events. */
+       set_bit(EV_SYN, input_dev->evbit);
+       set_bit(EV_KEY, input_dev->evbit);
+       /* set bits for each button... */
+       for (i = 0; i < f19->button_count; i++)
+               set_bit(f19->button_map[i], input_dev->keybit);
+       rc = input_register_device(input_dev);
+       if (rc < 0) {
+               dev_err(&fc->dev, "Failed to register input device.\n");
+               goto err_free_input;
+       }
+
+       dev_dbg(&fc->dev, "Creating sysfs files.\n");
+       /* Set up sysfs device attributes. */
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               if (sysfs_create_file
+                   (&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
+                       dev_err(&fc->dev,
+                               "Failed to create sysfs file for %s.",
+                               attrs[attr_count].attr.name);
+                       rc = -ENODEV;
+                       goto err_free_data;
+               }
+       }
+       fc->data = f19;
+       return 0;
+
+err_free_input:
+       input_free_device(f19->input);
+
+err_free_data:
+       if (f19) {
+               kfree(f19->button_down);
+               kfree(f19->button_data_buffer);
+               kfree(f19->button_map);
+       }
+       kfree(f19);
+       for (attr_count--; attr_count >= 0; attr_count--)
+               sysfs_remove_file(&fc->dev.kobj,
+                                 &attrs[attr_count].attr);
+       return rc;
+}
+
+int rmi_f19_attention(struct rmi_function_container *fc, u8 *irq_bits)
+{
+       struct rmi_device *rmi_dev = fc->rmi_dev;
+       struct f19_data *f19 = fc->data;
+       u8 data_base_addr = fc->fd.data_base_addr;
+       int error;
+       int button;
+
+       /* Read the button data. */
+
+       error = rmi_read_block(rmi_dev, data_base_addr, f19->button_data_buffer,
+                       f19->button_data_buffer_size);
+       if (error < 0) {
+               dev_err(&fc->dev, "%s: Failed to read button data registers.\n",
+                       __func__);
+               return error;
+       }
+
+       /* Generate events for buttons that change state. */
+       for (button = 0; button < f19->button_count;
+            button++) {
+               int button_reg;
+               int button_shift;
+               bool button_status;
+
+               /* determine which data byte the button status is in */
+               button_reg = button / 7;
+               /* bit shift to get button's status */
+               button_shift = button % 8;
+               button_status =
+                   ((f19->button_data_buffer[button_reg] >> button_shift)
+                       & 0x01) != 0;
+
+               /* if the button state changed from the last time report it
+                * and store the new state */
+               if (button_status != f19->button_down[button]) {
+                       dev_dbg(&fc->dev, "%s: Button %d (code %d) -> %d.\n",
+                               __func__, button, f19->button_map[button],
+                                button_status);
+                       /* Generate an event here. */
+                       input_report_key(f19->input, f19->button_map[button],
+                                        button_status);
+                       f19->button_down[button] = button_status;
+               }
+       }
+
+       input_sync(f19->input); /* sync after groups of events */
+       return 0;
+}
+
+static void rmi_f19_remove(struct rmi_function_container *fc)
+{
+       struct f19_data *data = fc->data;
+       if (data) {
+               kfree(data->button_down);
+               kfree(data->button_data_buffer);
+               kfree(data->button_map);
+               input_unregister_device(data->input);
+               if (data->button_control) {
+                       kfree(data->button_control->general_control);
+                       kfree(data->button_control->button_int_enable);
+                       kfree(data->button_control->
+                               single_button_participation);
+                       kfree(data->button_control->sensor_map);
+                       kfree(data->button_control->
+                               all_button_sensitivity_adj);
+                       kfree(data->button_control->
+                               all_button_hysteresis_threshold);
+               }
+               kfree(data->button_control);
+       }
+       kfree(fc->data);
+}
+
+static struct rmi_function_handler function_handler = {
+       .func = 0x19,
+       .init = rmi_f19_init,
+       .attention = rmi_f19_attention,
+       .remove = rmi_f19_remove
+};
+
+static int __init rmi_f19_module_init(void)
+{
+       int error;
+
+       error = rmi_register_function_driver(&function_handler);
+       if (error < 0) {
+               pr_err("%s: register failed!\n", __func__);
+               return error;
+       }
+
+       return 0;
+}
+
+static void rmi_f19_module_exit(void)
+{
+       rmi_unregister_function_driver(&function_handler);
+}
+
+static ssize_t rmi_f19_filter_mode_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->button_control->general_control->filter_mode);
+
+}
+
+static ssize_t rmi_f19_filter_mode_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       unsigned int new_value;
+       int result;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       if (sscanf(buf, "%u", &new_value) != 1) {
+               dev_err(dev,
+               "%s: Error - filter_mode_store has an "
+               "invalid len.\n",
+               __func__);
+               return -EINVAL;
+       }
+
+       if (new_value < 0 || new_value > 4) {
+               dev_err(dev, "%s: Error - filter_mode_store has an "
+               "invalid value %d.\n",
+               __func__, new_value);
+               return -EINVAL;
+       }
+       data->button_control->general_control->filter_mode = new_value;
+       result = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr,
+               (u8 *)data->button_control->general_control,
+                       sizeof(struct f19_0d_control_0));
+       if (result < 0) {
+               dev_err(dev, "%s : Could not write filter_mode_store to 0x%x\n",
+                               __func__, fc->fd.control_base_addr);
+               return result;
+       }
+
+       return count;
+}
+
+static ssize_t rmi_f19_button_usage_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->button_control->general_control->button_usage);
+
+}
+
+static ssize_t rmi_f19_button_usage_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       unsigned int new_value;
+       int result;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       if (sscanf(buf, "%u", &new_value) != 1) {
+               dev_err(dev,
+               "%s: Error - button_usage_store has an "
+               "invalid len.\n",
+               __func__);
+               return -EINVAL;
+       }
+
+       if (new_value < 0 || new_value > 4) {
+               dev_err(dev, "%s: Error - button_usage_store has an "
+               "invalid value %d.\n",
+               __func__, new_value);
+               return -EINVAL;
+       }
+       data->button_control->general_control->button_usage = new_value;
+       result = rmi_write_block(fc->rmi_dev, fc->fd.control_base_addr,
+               (u8 *)data->button_control->general_control,
+                       sizeof(struct f19_0d_control_0));
+       if (result < 0) {
+               dev_err(dev, "%s : Could not write button_usage_store to 0x%x\n",
+                               __func__, fc->fd.control_base_addr);
+               return result;
+       }
+
+       return count;
+
+}
+
+static ssize_t rmi_f19_interrupt_enable_button_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       int i, len, total_len = 0;
+       char *current_buf = buf;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       /* loop through each button map value and copy its
+        * string representation into buf */
+       for (i = 0; i < data->button_count; i++) {
+               int button_reg;
+               int button_shift;
+               int interrupt_button;
+
+               button_reg = i / 7;
+               button_shift = i % 8;
+               interrupt_button =
+                   ((data->button_control->
+                       button_int_enable[button_reg].int_enabled_button >>
+                               button_shift) & 0x01);
+
+               /* get next button mapping value and write it to buf */
+               len = snprintf(current_buf, PAGE_SIZE - total_len,
+                       "%u ", interrupt_button);
+               /* bump up ptr to next location in buf if the
+                * snprintf was valid.  Otherwise issue an error
+                * and return. */
+               if (len > 0) {
+                       current_buf += len;
+                       total_len += len;
+               } else {
+                       dev_err(dev, "%s: Failed to build interrupt button"
+                               " buffer, code = %d.\n", __func__, len);
+                       return snprintf(buf, PAGE_SIZE, "unknown\n");
+               }
+       }
+       len = snprintf(current_buf, PAGE_SIZE - total_len, "\n");
+       if (len > 0)
+               total_len += len;
+       else
+               dev_warn(dev, "%s: Failed to append carriage return.\n",
+                        __func__);
+       return total_len;
+
+}
+
+static ssize_t rmi_f19_interrupt_enable_button_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       int i;
+       int button_count = 0;
+       int retval = count;
+       int button_reg = 0;
+       int ctrl_bass_addr;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       for (i = 0; i < data->button_count && *buf != 0;
+            i++) {
+               int button_shift;
+               int button;
+
+               button_reg = i / 7;
+               button_shift = i % 8;
+               /* get next button mapping value and store and bump up to
+                * point to next item in buf */
+               sscanf(buf, "%u", &button);
+
+               if (button != 0 && button != 1) {
+                       dev_err(dev,
+                               "%s: Error - interrupt enable button for"
+                               " button %d is not a valid value 0x%x.\n",
+                               __func__, i, button);
+                       return -EINVAL;
+               }
+
+               if (button_shift == 0)
+                       data->button_control->button_int_enable[button_reg].
+                               int_enabled_button = 0;
+               data->button_control->button_int_enable[button_reg].
+                       int_enabled_button |= (button << button_shift);
+               button_count++;
+               /* bump up buf to point to next item to read */
+               while (*buf != 0) {
+                       buf++;
+                       if (*(buf - 1) == ' ')
+                               break;
+               }
+       }
+
+       /* Make sure the button count matches */
+       if (button_count != data->button_count) {
+               dev_err(dev,
+                       "%s: Error - interrupt enable button count of %d"
+                       " doesn't match device button count of %d.\n",
+                        __func__, button_count, data->button_count);
+               return -EINVAL;
+       }
+
+       /* write back to the control register */
+       ctrl_bass_addr = fc->fd.control_base_addr +
+                       sizeof(struct f19_0d_control_0);
+       retval = rmi_write_block(fc->rmi_dev, ctrl_bass_addr,
+               (u8 *)data->button_control->button_int_enable,
+                       sizeof(struct f19_0d_control_1)*(button_reg + 1));
+       if (retval < 0) {
+               dev_err(dev, "%s : Could not write interrupt_enable_store"
+                       " to 0x%x\n", __func__, ctrl_bass_addr);
+               return retval;
+       }
+
+       return count;
+}
+
+static ssize_t rmi_f19_single_button_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       int i, len, total_len = 0;
+       char *current_buf = buf;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       /* loop through each button map value and copy its
+        * string representation into buf */
+       for (i = 0; i < data->button_count; i++) {
+               int button_reg;
+               int button_shift;
+               int single_button;
+
+               button_reg = i / 7;
+               button_shift = i % 8;
+               single_button = ((data->button_control->
+                       single_button_participation[button_reg].single_button
+                       >> button_shift) & 0x01);
+
+               /* get next button mapping value and write it to buf */
+               len = snprintf(current_buf, PAGE_SIZE - total_len,
+                       "%u ", single_button);
+               /* bump up ptr to next location in buf if the
+                * snprintf was valid.  Otherwise issue an error
+                * and return. */
+               if (len > 0) {
+                       current_buf += len;
+                       total_len += len;
+               } else {
+                       dev_err(dev, "%s: Failed to build signle button buffer"
+                               ", code = %d.\n", __func__, len);
+                       return snprintf(buf, PAGE_SIZE, "unknown\n");
+               }
+       }
+       len = snprintf(current_buf, PAGE_SIZE - total_len, "\n");
+       if (len > 0)
+               total_len += len;
+       else
+               dev_warn(dev, "%s: Failed to append carriage return.\n",
+                        __func__);
+
+       return total_len;
+
+}
+
+static ssize_t rmi_f19_single_button_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       int i;
+       int button_count = 0;
+       int retval = count;
+       int ctrl_bass_addr;
+       int button_reg = 0;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       for (i = 0; i < data->button_count && *buf != 0;
+            i++) {
+               int button_shift;
+               int button;
+
+               button_reg = i / 7;
+               button_shift = i % 8;
+               /* get next button mapping value and store and bump up to
+                * point to next item in buf */
+               sscanf(buf, "%u", &button);
+
+               if (button != 0 && button != 1) {
+                       dev_err(dev,
+                               "%s: Error - single button for button %d"
+                               " is not a valid value 0x%x.\n",
+                               __func__, i, button);
+                       return -EINVAL;
+               }
+               if (button_shift == 0)
+                       data->button_control->
+                               single_button_participation[button_reg].
+                               single_button = 0;
+               data->button_control->single_button_participation[button_reg].
+                       single_button |=  (button << button_shift);
+               button_count++;
+               /* bump up buf to point to next item to read */
+               while (*buf != 0) {
+                       buf++;
+                       if (*(buf - 1) == ' ')
+                               break;
+               }
+       }
+
+       /* Make sure the button count matches */
+       if (button_count != data->button_count) {
+               dev_err(dev,
+                   "%s: Error - single button count of %d doesn't match"
+                    " device button count of %d.\n", __func__, button_count,
+                    data->button_count);
+               return -EINVAL;
+       }
+       /* write back to the control register */
+       ctrl_bass_addr = fc->fd.control_base_addr +
+               sizeof(struct f19_0d_control_0) +
+               sizeof(struct f19_0d_control_2)*(button_reg + 1);
+       retval = rmi_write_block(fc->rmi_dev, ctrl_bass_addr,
+               (u8 *)data->button_control->single_button_participation,
+                       sizeof(struct f19_0d_control_2)*(button_reg + 1));
+       if (retval < 0) {
+               dev_err(dev, "%s : Could not write interrupt_enable_store to"
+                       " 0x%x\n", __func__, ctrl_bass_addr);
+               return -EINVAL;
+       }
+       return count;
+}
+
+static ssize_t rmi_f19_sensor_map_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       int i, len, total_len = 0;
+       char *current_buf = buf;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       for (i = 0; i < data->button_count; i++) {
+               len = snprintf(current_buf, PAGE_SIZE - total_len,
+                       "%u ", data->button_control->sensor_map[i].
+                       sensor_map_button);
+               /* bump up ptr to next location in buf if the
+                * snprintf was valid.  Otherwise issue an error
+                * and return. */
+               if (len > 0) {
+                       current_buf += len;
+                       total_len += len;
+               } else {
+                       dev_err(dev, "%s: Failed to build sensor map buffer, "
+                               "code = %d.\n", __func__, len);
+                       return snprintf(buf, PAGE_SIZE, "unknown\n");
+               }
+       }
+       len = snprintf(current_buf, PAGE_SIZE - total_len, "\n");
+       if (len > 0)
+               total_len += len;
+       else
+               dev_warn(dev, "%s: Failed to append carriage return.\n",
+                        __func__);
+       return total_len;
+
+
+}
+
+static ssize_t rmi_f19_sensor_map_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       int sensor_map;
+       int i;
+       int retval = count;
+       int button_count = 0;
+       int ctrl_bass_addr;
+       int button_reg;
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       if (data->button_query.configurable == 0) {
+               dev_err(dev,
+                       "%s: Error - sensor map is not configuralbe at"
+                       " run-time", __func__);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < data->button_count && *buf != 0; i++) {
+               /* get next button mapping value and store and bump up to
+                * point to next item in buf */
+               sscanf(buf, "%u", &sensor_map);
+
+               /* Make sure the key is a valid key */
+               if (sensor_map < 0 || sensor_map > 127) {
+                       dev_err(dev,
+                               "%s: Error - sensor map for button %d is"
+                               " not a valid value 0x%x.\n",
+                               __func__, i, sensor_map);
+                       return -EINVAL;
+               }
+
+               data->button_control->sensor_map[i].sensor_map_button =
+                       sensor_map;
+               button_count++;
+
+               /* bump up buf to point to next item to read */
+               while (*buf != 0) {
+                       buf++;
+                       if (*(buf - 1) == ' ')
+                               break;
+               }
+       }
+
+       if (button_count != data->button_count) {
+               dev_err(dev,
+                   "%s: Error - button map count of %d doesn't match device "
+                    "button count of %d.\n", __func__, button_count,
+                    data->button_count);
+               return -EINVAL;
+       }
+
+       /* write back to the control register */
+       button_reg = (button_count / 7) + 1;
+       ctrl_bass_addr = fc->fd.control_base_addr +
+               sizeof(struct f19_0d_control_0) +
+               sizeof(struct f19_0d_control_1)*button_reg +
+               sizeof(struct f19_0d_control_2)*button_reg;
+       retval = rmi_write_block(fc->rmi_dev, ctrl_bass_addr,
+               (u8 *)data->button_control->sensor_map,
+                       sizeof(struct f19_0d_control_3_4)*button_count);
+       if (retval < 0) {
+               dev_err(dev, "%s : Could not sensor_map_store to 0x%x\n",
+                               __func__, ctrl_bass_addr);
+               return -EINVAL;
+       }
+       return count;
+}
+
+static ssize_t rmi_f19_sensitivity_adjust_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", data->button_control->
+               all_button_sensitivity_adj->sensitivity_adj);
+
+}
+
+static ssize_t rmi_f19_sensitivity_adjust_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       unsigned int new_value;
+       int len;
+       int ctrl_bass_addr;
+       int button_reg;
+
+       fc = to_rmi_function_container(dev);
+
+       data = fc->data;
+
+       if (data->button_query.configurable == 0) {
+               dev_err(dev,
+                       "%s: Error - sensitivity_adjust is not"
+                       " configuralbe at run-time", __func__);
+               return -EINVAL;
+       }
+
+       len = sscanf(buf, "%u", &new_value);
+       if (new_value < 0 || new_value > 31)
+               return -EINVAL;
+
+       data->button_control->all_button_sensitivity_adj->sensitivity_adj =
+                new_value;
+       /* write back to the control register */
+       button_reg = (data->button_count / 7) + 1;
+       ctrl_bass_addr = fc->fd.control_base_addr +
+               sizeof(struct f19_0d_control_0) +
+               sizeof(struct f19_0d_control_1)*button_reg +
+               sizeof(struct f19_0d_control_2)*button_reg +
+               sizeof(struct f19_0d_control_3_4)*data->button_count;
+       len = rmi_write_block(fc->rmi_dev, ctrl_bass_addr,
+               (u8 *)data->button_control->all_button_sensitivity_adj,
+                       sizeof(struct f19_0d_control_5));
+       if (len < 0) {
+               dev_err(dev, "%s : Could not sensitivity_adjust_store to"
+                       " 0x%x\n", __func__, ctrl_bass_addr);
+               return len;
+       }
+
+       return len;
+}
+
+static ssize_t rmi_f19_hysteresis_threshold_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", data->button_control->
+               all_button_hysteresis_threshold->hysteresis_threshold);
+
+}
+static ssize_t rmi_f19_hysteresis_threshold_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       unsigned int new_value;
+       int len;
+       int ctrl_bass_addr;
+       int button_reg;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       len = sscanf(buf, "%u", &new_value);
+       if (new_value < 0 || new_value > 15) {
+               dev_err(dev, "%s: Error - hysteresis_threshold_store has an "
+               "invalid value %d.\n",
+               __func__, new_value);
+               return -EINVAL;
+       }
+       data->button_control->all_button_hysteresis_threshold->
+               hysteresis_threshold = new_value;
+       /* write back to the control register */
+       button_reg = (data->button_count / 7) + 1;
+       ctrl_bass_addr = fc->fd.control_base_addr +
+               sizeof(struct f19_0d_control_0) +
+               sizeof(struct f19_0d_control_1)*button_reg +
+               sizeof(struct f19_0d_control_2)*button_reg +
+               sizeof(struct f19_0d_control_3_4)*data->button_count+
+               sizeof(struct f19_0d_control_5);
+       len = rmi_write_block(fc->rmi_dev, ctrl_bass_addr,
+               (u8 *)data->button_control->all_button_sensitivity_adj,
+                       sizeof(struct f19_0d_control_6));
+       if (len < 0) {
+               dev_err(dev, "%s : Could not write all_button hysteresis "
+                       "threshold to 0x%x\n", __func__, ctrl_bass_addr);
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static ssize_t rmi_f19_has_hysteresis_threshold_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->button_query.has_hysteresis_threshold);
+}
+
+static ssize_t rmi_f19_has_sensitivity_adjust_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->button_query.has_sensitivity_adjust);
+}
+
+static ssize_t rmi_f19_configurable_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->button_query.configurable);
+}
+
+static ssize_t rmi_f19_rezero_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->button_rezero);
+
+}
+
+static ssize_t rmi_f19_rezero_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf,
+                                        size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       unsigned int new_value;
+       int len;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       len = sscanf(buf, "%u", &new_value);
+       if (new_value != 0 && new_value != 1) {
+               dev_err(dev,
+                       "%s: Error - rezero is not a "
+                       "valid value 0x%x.\n",
+                       __func__, new_value);
+               return -EINVAL;
+       }
+       data->button_rezero = new_value & 1;
+       len = rmi_write(fc->rmi_dev, fc->fd.command_base_addr,
+               data->button_rezero);
+
+       if (len < 0) {
+               dev_err(dev, "%s : Could not write rezero to 0x%x\n",
+                               __func__, fc->fd.command_base_addr);
+               return -EINVAL;
+       }
+       return count;
+}
+
+static ssize_t rmi_f19_button_count_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->button_count);
+}
+
+static ssize_t rmi_f19_button_map_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       int i, len, total_len = 0;
+       char *current_buf = buf;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+       /* loop through each button map value and copy its
+        * string representation into buf */
+       for (i = 0; i < data->button_count; i++) {
+               /* get next button mapping value and write it to buf */
+               len = snprintf(current_buf, PAGE_SIZE - total_len,
+                       "%u ", data->button_map[i]);
+               /* bump up ptr to next location in buf if the
+                * snprintf was valid.  Otherwise issue an error
+                * and return. */
+               if (len > 0) {
+                       current_buf += len;
+                       total_len += len;
+               } else {
+                       dev_err(dev, "%s: Failed to build button map buffer, "
+                               "code = %d.\n", __func__, len);
+                       return snprintf(buf, PAGE_SIZE, "unknown\n");
+               }
+       }
+       len = snprintf(current_buf, PAGE_SIZE - total_len, "\n");
+       if (len > 0)
+               total_len += len;
+       else
+               dev_warn(dev, "%s: Failed to append carriage return.\n",
+                        __func__);
+       return total_len;
+}
+
+static ssize_t rmi_f19_button_map_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf,
+                               size_t count)
+{
+       struct rmi_function_container *fc;
+       struct f19_data *data;
+       unsigned int button;
+       int i;
+       int retval = count;
+       int button_count = 0;
+       unsigned char temp_button_map[KEY_MAX];
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       /* Do validation on the button map data passed in.  Store button
+        * mappings into a temp buffer and then verify button count and
+        * data prior to clearing out old button mappings and storing the
+        * new ones. */
+       for (i = 0; i < data->button_count && *buf != 0;
+            i++) {
+               /* get next button mapping value and store and bump up to
+                * point to next item in buf */
+               sscanf(buf, "%u", &button);
+
+               /* Make sure the key is a valid key */
+               if (button > KEY_MAX) {
+                       dev_err(dev,
+                               "%s: Error - button map for button %d is not a"
+                               " valid value 0x%x.\n", __func__, i, button);
+                       retval = -EINVAL;
+                       goto err_ret;
+               }
+
+               temp_button_map[i] = button;
+               button_count++;
+
+               /* bump up buf to point to next item to read */
+               while (*buf != 0) {
+                       buf++;
+                       if (*(buf - 1) == ' ')
+                               break;
+               }
+       }
+
+       /* Make sure the button count matches */
+       if (button_count != data->button_count) {
+               dev_err(dev,
+                   "%s: Error - button map count of %d doesn't match device "
+                    "button count of %d.\n", __func__, button_count,
+                    data->button_count);
+               retval = -EINVAL;
+               goto err_ret;
+       }
+
+       /* Clear the key bits for the old button map. */
+       for (i = 0; i < button_count; i++)
+               clear_bit(data->button_map[i], data->input->keybit);
+
+       /* Switch to the new map. */
+       memcpy(data->button_map, temp_button_map,
+              data->button_count);
+
+       /* Loop through the key map and set the key bit for the new mapping. */
+       for (i = 0; i < button_count; i++)
+               set_bit(data->button_map[i], data->input->keybit);
+
+err_ret:
+       return retval;
+}
+
+module_init(rmi_f19_module_init);
+module_exit(rmi_f19_module_exit);
+
+MODULE_AUTHOR("Vivian Ly <vly@synaptics.com>");
+MODULE_DESCRIPTION("RMI F19 module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi4/rmi_f34.c b/drivers/input/touchscreen/rmi4/rmi_f34.c
new file mode 100644 (file)
index 0000000..33e84d2
--- /dev/null
@@ -0,0 +1,821 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include "rmi_driver.h"
+
+/* define fn $34 commands */
+#define WRITE_FW_BLOCK            0x2
+#define ERASE_ALL                 0x3
+#define READ_CONFIG_BLOCK         0x5
+#define WRITE_CONFIG_BLOCK        0x6
+#define ERASE_CONFIG              0x7
+#define ENABLE_FLASH_PROG         0xf
+
+#define STATUS_IN_PROGRESS        0xff
+#define STATUS_IDLE              0x80
+
+#define PDT_START_SCAN_LOCATION        0x00e9
+#define PDT_END_SCAN_LOCATION  0x0005
+
+#define BLK_SZ_OFF     3
+#define IMG_BLK_CNT_OFF        5
+#define CFG_BLK_CNT_OFF        7
+
+#define BLK_NUM_OFF 2
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+#define KERNEL_VERSION_ABOVE_2_6_32 1
+#endif
+
+/* data specific to fn $34 that needs to be kept around */
+struct rmi_fn_34_data {
+       unsigned char status;
+       unsigned char cmd;
+       unsigned short bootloaderid;
+       unsigned short blocksize;
+       unsigned short imageblockcount;
+       unsigned short configblockcount;
+       unsigned short blocknum;
+       bool inflashprogmode;
+};
+
+static ssize_t rmi_fn_34_status_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_34_cmd_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_34_cmd_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count);
+
+#ifdef KERNEL_VERSION_ABOVE_2_6_32
+static ssize_t rmi_fn_34_data_read(struct file *data_file, struct kobject *kobj,
+                                  struct bin_attribute *attributes,
+                                  char *buf, loff_t pos, size_t count);
+
+static ssize_t rmi_fn_34_data_write(struct file *data_file,
+                                   struct kobject *kobj,
+                                   struct bin_attribute *attributes, char *buf,
+                                   loff_t pos, size_t count);
+#else
+static ssize_t rmi_fn_34_data_read(struct kobject *kobj,
+                                  struct bin_attribute *attributes,
+                                  char *buf, loff_t pos, size_t count);
+
+static ssize_t rmi_fn_34_data_write(struct kobject *kobj,
+                                   struct bin_attribute *attributes, char *buf,
+                                   loff_t pos, size_t count);
+#endif
+
+static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf);
+
+static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t count);
+
+static ssize_t rmi_fn_34_blocksize_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf);
+
+static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev,
+                                             struct device_attribute *attr,
+                                             char *buf);
+
+static ssize_t rmi_fn_34_configblockcount_show(struct device *dev,
+                                              struct device_attribute *attr,
+                                              char *buf);
+
+static ssize_t rmi_fn_34_blocknum_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf);
+
+static ssize_t rmi_fn_34_blocknum_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count);
+
+static ssize_t rmi_fn_34_rescanPDT_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count);
+
+static struct device_attribute attrs[] = {
+       __ATTR(status, RMI_RO_ATTR,
+              rmi_fn_34_status_show, rmi_store_error),
+       /* Also, sysfs will need to have a file set up to distinguish
+        * between commands - like Config write/read, Image write/verify. */
+       __ATTR(cmd, RMI_RW_ATTR,
+              rmi_fn_34_cmd_show, rmi_fn_34_cmd_store),
+       __ATTR(bootloaderid, RMI_RW_ATTR,
+              rmi_fn_34_bootloaderid_show, rmi_fn_34_bootloaderid_store),
+       __ATTR(blocksize, RMI_RO_ATTR,
+              rmi_fn_34_blocksize_show, rmi_store_error),
+       __ATTR(imageblockcount, RMI_RO_ATTR,
+              rmi_fn_34_imageblockcount_show, rmi_store_error),
+       __ATTR(configblockcount, RMI_RO_ATTR,
+              rmi_fn_34_configblockcount_show, rmi_store_error),
+       __ATTR(blocknum, RMI_RW_ATTR,
+              rmi_fn_34_blocknum_show, rmi_fn_34_blocknum_store),
+       __ATTR(rescanPDT, RMI_WO_ATTR,
+              rmi_show_error, rmi_fn_34_rescanPDT_store)
+};
+
+struct bin_attribute dev_attr_data = {
+       .attr = {
+                .name = "data",
+                .mode = 0666},
+       .size = 0,
+       .read = rmi_fn_34_data_read,
+       .write = rmi_fn_34_data_write,
+};
+
+static int rmi_f34_init(struct rmi_function_container *fc)
+{
+       int retval = 0;
+       int attr_count = 0;
+       struct rmi_fn_34_data *f34;
+       u16 query_base_addr;
+       u16 control_base_addr;
+       unsigned char buf[2];
+
+       dev_info(&fc->dev, "Intializing f34 values.");
+
+       /* init instance data, fill in values and create any sysfs files */
+       f34 = kzalloc(sizeof(struct rmi_fn_34_data), GFP_KERNEL);
+       if (!f34) {
+               dev_err(&fc->dev, "Failed to allocate rmi_fn_34_data.\n");
+               return -ENOMEM;
+       }
+
+       fc->data = f34;
+
+       /* get the Bootloader ID and Block Size. */
+       query_base_addr = fc->fd.query_base_addr;
+       control_base_addr = fc->fd.control_base_addr;
+
+       retval = rmi_read_block(fc->rmi_dev, query_base_addr, buf,
+                       ARRAY_SIZE(buf));
+
+       if (retval < 0) {
+               dev_err(&fc->dev, "Could not read bootloaderid from 0x%04x.\n",
+                       query_base_addr);
+               goto exit_free_data;
+       }
+       batohs(&f34->bootloaderid, buf);
+
+       retval = rmi_read_block(fc->rmi_dev, query_base_addr + BLK_SZ_OFF, buf,
+                       ARRAY_SIZE(buf));
+
+       if (retval < 0) {
+               dev_err(&fc->dev, "Could not read block size from 0x%04x, "
+                       "error=%d.\n", query_base_addr + BLK_SZ_OFF, retval);
+               goto exit_free_data;
+       }
+       batohs(&f34->blocksize, buf);
+
+       /* Get firmware image block count and store it in the instance data */
+       retval = rmi_read_block(fc->rmi_dev, query_base_addr + IMG_BLK_CNT_OFF,
+                       buf, ARRAY_SIZE(buf));
+
+       if (retval < 0) {
+               dev_err(&fc->dev, "Couldn't read image block count from 0x%x, "
+                       "error=%d.\n", query_base_addr + IMG_BLK_CNT_OFF,
+                       retval);
+               goto exit_free_data;
+       }
+       batohs(&f34->imageblockcount, buf);
+
+       /* Get config block count and store it in the instance data */
+       retval = rmi_read_block(fc->rmi_dev, query_base_addr + 7, buf,
+                       ARRAY_SIZE(buf));
+
+       if (retval < 0) {
+               dev_err(&fc->dev, "Couldn't read config block count from 0x%x, "
+                       "error=%d.\n", query_base_addr + CFG_BLK_CNT_OFF,
+                       retval);
+               goto exit_free_data;
+       }
+       batohs(&f34->configblockcount, buf);
+
+       /* We need a sysfs file for the image/config block to write or read.
+        * Set up sysfs bin file for binary data block. Since the image is
+        * already in our format there is no need to convert the data for
+        * endianess. */
+       retval = sysfs_create_bin_file(&fc->dev.kobj,
+                               &dev_attr_data);
+       if (retval < 0) {
+               dev_err(&fc->dev, "Failed to create sysfs file for F34 data "
+                    "(error = %d).\n", retval);
+               retval = -ENODEV;
+               goto exit_free_data;
+       }
+
+       dev_dbg(&fc->dev, "Creating sysfs files.\n");
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               if (sysfs_create_file
+                   (&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
+                       dev_err(&fc->dev, "Failed to create sysfs file for %s.",
+                               attrs[attr_count].attr.name);
+                       retval = -ENODEV;
+                       goto exit_free_attrs;
+               }
+       }
+
+       return retval;
+
+exit_free_attrs:
+       for (attr_count--; attr_count >= 0; attr_count--)
+               sysfs_remove_file(&fc->dev.kobj,
+                                 &attrs[attr_count].attr);
+exit_free_data:
+       kfree(f34);
+       return retval;
+}
+
+static int f34_read_status(struct rmi_function_container *fc)
+{
+       struct rmi_fn_34_data *instance_data = fc->data;
+       u16 data_base_addr = fc->fd.data_base_addr;
+       u8 status;
+       int retval;
+
+       /* Read the Fn $34 status from F34_Flash_Data3 to see the previous
+        * commands status. F34_Flash_Data3 will be the address after the
+        * 2 block number registers plus blocksize Data registers.
+        *  inform user space - through a sysfs param. */
+       retval = rmi_read(fc->rmi_dev,
+                         data_base_addr + instance_data->blocksize +
+                         BLK_NUM_OFF, &status);
+
+       if (retval < 0) {
+               dev_err(&fc->dev, "Could not read status from 0x%x\n",
+                      data_base_addr + instance_data->blocksize + BLK_NUM_OFF);
+               status = 0xff;  /* failure */
+       }
+
+       /* set a sysfs value that the user mode can read - only
+        * upper 4 bits are the status. successful is $80, anything
+        * else is failure */
+       instance_data->status = status & 0xf0;
+
+       /* put mode into Flash Prog Mode when we successfully do
+        * an Enable Flash Prog cmd. */
+       if ((instance_data->status == STATUS_IDLE) &&
+               (instance_data->cmd == ENABLE_FLASH_PROG))
+               instance_data->inflashprogmode = true;
+
+       return retval;
+}
+
+int rmi_f34_attention(struct rmi_function_container *fc, u8 *irq_bits)
+{
+       return f34_read_status(fc);
+}
+
+static struct rmi_function_handler function_handler = {
+       .func = 0x34,
+       .init = rmi_f34_init,
+       .attention = rmi_f34_attention
+};
+
+static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->bootloaderid);
+}
+
+static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t count)
+{
+       int error;
+       unsigned long val;
+       unsigned char data[2];
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+       u16 data_base_addr;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       /* need to convert the string data to an actual value */
+       error = strict_strtoul(buf, 10, &val);
+
+       if (error)
+               return error;
+
+       instance_data->bootloaderid = val;
+
+       /* Write the Bootloader ID key data back to the first two Block
+        * Data registers (F34_Flash_Data2.0 and F34_Flash_Data2.1). */
+       hstoba(data, (unsigned short)val);
+       data_base_addr = fc->fd.data_base_addr;
+
+       error = rmi_write_block(fc->rmi_dev,
+                               data_base_addr + BLK_NUM_OFF,
+                               data,
+                               ARRAY_SIZE(data));
+
+       if (error < 0) {
+               dev_err(dev, "%s : Could not write bootloader id to 0x%x\n",
+                      __func__, data_base_addr + BLK_NUM_OFF);
+               return error;
+       }
+
+       return count;
+}
+
+static ssize_t rmi_fn_34_blocksize_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->blocksize);
+}
+
+static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       instance_data->imageblockcount);
+}
+
+static ssize_t rmi_fn_34_configblockcount_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       instance_data->configblockcount);
+}
+
+static ssize_t rmi_fn_34_status_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+       int retval;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       retval = f34_read_status(fc);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->status);
+}
+
+static ssize_t rmi_fn_34_cmd_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->cmd);
+}
+
+static ssize_t rmi_fn_34_cmd_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf,
+                               size_t count)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+       unsigned long val;
+       u16 data_base_addr;
+       int error;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+       data_base_addr = fc->fd.data_base_addr;
+
+       /* need to convert the string data to an actual value */
+       error = strict_strtoul(buf, 10, &val);
+       if (error)
+               return error;
+
+       /* make sure we are in Flash Prog mode for all cmds except the
+        * Enable Flash Programming cmd - otherwise we are in error */
+       if ((val != ENABLE_FLASH_PROG) && !instance_data->inflashprogmode) {
+               dev_err(dev, "%s: CANNOT SEND CMD %d TO SENSOR - "
+                       "NOT IN FLASH PROG MODE\n"
+                       , __func__, data_base_addr);
+               return -EINVAL;
+       }
+
+       instance_data->cmd = val;
+
+       /* Validate command value and (if necessary) write it to the command
+        * register.
+        */
+       switch (instance_data->cmd) {
+       case ENABLE_FLASH_PROG:
+       case ERASE_ALL:
+       case ERASE_CONFIG:
+       case WRITE_FW_BLOCK:
+       case READ_CONFIG_BLOCK:
+       case WRITE_CONFIG_BLOCK:
+               /* Reset the status to indicate we are in progress on a cmd. */
+               /* The status will change when the ATTN interrupt happens
+                  and the status of the cmd that was issued is read from
+                  the F34_Flash_Data3 register - result should be 0x80 for
+                  success - any other value indicates an error */
+
+               /* Issue the command to the device. */
+               error = rmi_write(fc->rmi_dev,
+                               data_base_addr + instance_data->blocksize +
+                               BLK_NUM_OFF, instance_data->cmd);
+
+               if (error < 0) {
+                       dev_err(dev, "%s: Could not write command 0x%02x "
+                               "to 0x%04x\n", __func__, instance_data->cmd,
+                               data_base_addr + instance_data->blocksize +
+                               BLK_NUM_OFF);
+                       return error;
+               }
+
+               if (instance_data->cmd == ENABLE_FLASH_PROG)
+                       instance_data->inflashprogmode = true;
+
+               /* set status to indicate we are in progress */
+               instance_data->status = STATUS_IN_PROGRESS;
+               break;
+       default:
+               dev_dbg(dev, "%s: RMI4 function $34 - "
+                               "unknown command 0x%02lx.\n", __func__, val);
+               count = -EINVAL;
+               break;
+       }
+
+       return count;
+}
+
+static ssize_t rmi_fn_34_blocknum_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->blocknum);
+}
+
+static ssize_t rmi_fn_34_blocknum_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t count)
+{
+       int error;
+       unsigned long val;
+       unsigned char data[2];
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+       u16 data_base_addr;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+       data_base_addr = fc->fd.data_base_addr;
+
+       /* need to convert the string data to an actual value */
+       error = strict_strtoul(buf, 10, &val);
+
+       if (error)
+               return error;
+
+       instance_data->blocknum = val;
+
+       /* Write the Block Number data back to the first two Block
+        * Data registers (F34_Flash_Data_0 and F34_Flash_Data_1). */
+       hstoba(data, (unsigned short)val);
+
+       error = rmi_write_block(fc->rmi_dev,
+                               data_base_addr,
+                               data,
+                               ARRAY_SIZE(data));
+
+       if (error < 0) {
+               dev_err(dev, "%s : Could not write block number %u to 0x%x\n",
+                      __func__, instance_data->blocknum, data_base_addr);
+               return error;
+       }
+
+       return count;
+}
+
+static ssize_t rmi_fn_34_rescanPDT_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *driver_data;
+       struct pdt_entry pdt_entry;
+       bool fn01found = false;
+       bool fn34found = false;
+       unsigned int rescan;
+       int irq_count = 0;
+       int retval = 0;
+       int i;
+
+       /* Rescan of the PDT is needed since issuing the Flash Enable cmd
+        * the device registers for Fn$01 and Fn$34 moving around because
+        * of the change from Bootloader mode to Flash Programming mode
+        * may change to a different PDT with only Fn$01 and Fn$34 that
+        * could have addresses for query, control, data, command registers
+        * that differ from the PDT scan done at device initialization. */
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+       rmi_dev = fc->rmi_dev;
+       driver_data = rmi_get_driverdata(rmi_dev);
+
+       /* Make sure we are only in Flash Programming mode  - DON'T
+        * ALLOW THIS IN UI MODE. */
+       if (instance_data->cmd != ENABLE_FLASH_PROG) {
+               dev_err(dev, "%s: NOT IN FLASH PROG MODE - CAN'T RESCAN PDT.\n"
+                               , __func__);
+               return -EINVAL;
+       }
+
+       /* The only good value to write to this is 1, we allow 0, but with
+        * no effect (this is consistent with the way the command bit works. */
+       if (sscanf(buf, "%u", &rescan) != 1)
+               return -EINVAL;
+       if (rescan < 0 || rescan > 1)
+               return -EINVAL;
+
+       /* 0 has no effect, so we skip it entirely. */
+       if (rescan) {
+               /* rescan the PDT - filling in Fn01 and Fn34 addresses -
+                * this is only temporary - the device will need to be reset
+                * to return the PDT to the normal values. */
+
+               /* mini-parse the PDT - we only have to get Fn$01 and Fn$34 and
+                  since we are Flash Programming mode we only have page 0. */
+               for (i = PDT_START_SCAN_LOCATION; i >= PDT_END_SCAN_LOCATION;
+                       i -= sizeof(pdt_entry)) {
+                       retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry,
+                                              sizeof(pdt_entry));
+                       if (retval != sizeof(pdt_entry)) {
+                               dev_err(dev, "%s: err frm rmi_read_block pdt "
+                                       "entry data from PDT, "
+                                       "error = %d.", __func__, retval);
+                               return retval;
+                       }
+
+                       if ((pdt_entry.function_number == 0x00) ||
+                               (pdt_entry.function_number == 0xff))
+                               break;
+
+                       dev_dbg(dev, "%s: Found F%.2X\n",
+                               __func__, pdt_entry.function_number);
+
+                       /* f01 found - just fill in the new addresses in
+                        * the existing fc. */
+                       if (pdt_entry.function_number == 0x01) {
+                               struct rmi_function_container *f01_fc =
+                                       driver_data->f01_container;
+                               fn01found = true;
+                               f01_fc->fd.query_base_addr =
+                                       pdt_entry.query_base_addr;
+                               f01_fc->fd.command_base_addr =
+                                 pdt_entry.command_base_addr;
+                               f01_fc->fd.control_base_addr =
+                                 pdt_entry.control_base_addr;
+                               f01_fc->fd.data_base_addr =
+                                 pdt_entry.data_base_addr;
+                               f01_fc->fd.function_number =
+                                 pdt_entry.function_number;
+                               f01_fc->fd.interrupt_source_count =
+                                 pdt_entry.interrupt_source_count;
+                               f01_fc->num_of_irqs =
+                                 pdt_entry.interrupt_source_count;
+                               f01_fc->irq_pos = irq_count;
+
+                               irq_count += f01_fc->num_of_irqs;
+
+                               if (fn34found)
+                                       break;
+                       }
+
+                       /* f34 found - just fill in the new addresses in
+                        * the existing fc. */
+                       if (pdt_entry.function_number == 0x34) {
+                               fn34found = true;
+                               fc->fd.query_base_addr =
+                                 pdt_entry.query_base_addr;
+                               fc->fd.command_base_addr =
+                                 pdt_entry.command_base_addr;
+                               fc->fd.control_base_addr =
+                                 pdt_entry.control_base_addr;
+                               fc->fd.data_base_addr =
+                                 pdt_entry.data_base_addr;
+                               fc->fd.function_number =
+                                 pdt_entry.function_number;
+                               fc->fd.interrupt_source_count =
+                                 pdt_entry.interrupt_source_count;
+                               fc->num_of_irqs =
+                                 pdt_entry.interrupt_source_count;
+                               fc->irq_pos = irq_count;
+
+                               irq_count += fc->num_of_irqs;
+
+                               if (fn01found)
+                                       break;
+                       }
+
+               }
+
+               if (!fn01found || !fn34found) {
+                       dev_err(dev, "%s: failed to find fn$01 or fn$34 trying "
+                               "to do rescan PDT.\n"
+                               , __func__);
+                       return -EINVAL;
+               }
+       }
+
+       return count;
+}
+
+#ifdef KERNEL_VERSION_ABOVE_2_6_32
+static ssize_t rmi_fn_34_data_read(struct file *data_file,
+                               struct kobject *kobj,
+                               struct bin_attribute *attributes,
+                               char *buf,
+                               loff_t pos,
+                               size_t count)
+#else
+static ssize_t rmi_fn_34_data_read(struct kobject *kobj,
+                               struct bin_attribute *attributes,
+                               char *buf,
+                               loff_t pos,
+                               size_t count)
+#endif
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+       u16 data_base_addr;
+       int error;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       data_base_addr = fc->fd.data_base_addr;
+
+       if (count != instance_data->blocksize) {
+               dev_err(dev,
+                       "%s : Incorrect F34 block size %d. "
+                       "Expected size %d.\n",
+                       __func__, count, instance_data->blocksize);
+               return -EINVAL;
+       }
+
+       /* Read the data from flash into buf.  The app layer will be blocked
+        * at reading from the sysfs file.  When we return the count (or
+        * error if we fail) the app will resume. */
+       error = rmi_read_block(fc->rmi_dev, data_base_addr + BLK_NUM_OFF,
+                       (unsigned char *)buf, count);
+
+       if (error < 0) {
+               dev_err(dev, "%s : Could not read data from 0x%04x\n",
+                      __func__, data_base_addr + BLK_NUM_OFF);
+               return error;
+       }
+
+       return count;
+}
+
+#ifdef KERNEL_VERSION_ABOVE_2_6_32
+static ssize_t rmi_fn_34_data_write(struct file *data_file,
+                               struct kobject *kobj,
+                               struct bin_attribute *attributes,
+                               char *buf,
+                               loff_t pos,
+                               size_t count)
+#else
+static ssize_t rmi_fn_34_data_write(struct kobject *kobj,
+                               struct bin_attribute *attributes,
+                               char *buf,
+                               loff_t pos,
+                               size_t count)
+#endif
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct rmi_function_container *fc;
+       struct rmi_fn_34_data *instance_data;
+       u16 data_base_addr;
+       int error;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       data_base_addr = fc->fd.data_base_addr;
+
+       /* Write the data from buf to flash. The app layer will be
+        * blocked at writing to the sysfs file.  When we return the
+        * count (or error if we fail) the app will resume. */
+
+       if (count != instance_data->blocksize) {
+               dev_err(dev,
+                       "%s : Incorrect F34 block size %d. "
+                       "Expected size %d.\n",
+                       __func__, count, instance_data->blocksize);
+               return -EINVAL;
+       }
+
+       /* Write the data block - only if the count is non-zero  */
+       if (count) {
+               error = rmi_write_block(fc->rmi_dev,
+                               data_base_addr + BLK_NUM_OFF,
+                               (unsigned char *)buf,
+                               count);
+
+               if (error < 0) {
+                       dev_err(dev, "%s : Could not write block data "
+                               "to 0x%x\n", __func__,
+                               data_base_addr + BLK_NUM_OFF);
+                       return error;
+               }
+       }
+
+       return count;
+}
+
+static int __init rmi_f34_module_init(void)
+{
+       int error;
+
+       error = rmi_register_function_driver(&function_handler);
+       if (error < 0) {
+               pr_err("%s : register failed !\n", __func__);
+               return error;
+       }
+
+       return 0;
+}
+
+static void rmi_f34_module_exit(void)
+{
+       rmi_unregister_function_driver(&function_handler);
+}
+
+module_init(rmi_f34_module_init);
+module_exit(rmi_f34_module_exit);
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("RMI f34 module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi4/rmi_f54.c b/drivers/input/touchscreen/rmi4/rmi_f54.c
new file mode 100644 (file)
index 0000000..11bb0b9
--- /dev/null
@@ -0,0 +1,1347 @@
+
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include "rmi_driver.h"
+
+/* Set this to 1 for raw hex dump of returned data. */
+#define RAW_HEX 0
+/* Set this to 1 for human readable dump of returned data. */
+#define HUMAN_READABLE 0
+/* The watchdog timer can be useful when debugging certain firmware related
+ * issues.
+ */
+#define F54_WATCHDOG 1
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
+#define KERNEL_VERSION_ABOVE_2_6_32 1
+#endif
+
+/* define fn $54 commands */
+#define GET_REPORT                1
+#define FORCE_CAL                 2
+
+/* status */
+#define BUSY 1
+#define IDLE 0
+
+/* Offsets for data */
+#define RMI_F54_REPORT_DATA_OFFSET     3
+#define RMI_F54_FIFO_OFFSET            1
+#define RMI_F54_NUM_TX_OFFSET          1
+#define RMI_F54_NUM_RX_OFFSET          0
+
+/* Fixed sizes of reports */
+#define RMI_54_FULL_RAW_CAP_MIN_MAX_SIZE 4
+#define RMI_54_HIGH_RESISTANCE_SIZE 6
+
+/* definitions for F54 Query Registers in ultra-portable unionstruct form */
+struct f54_ad_query {
+       /* query 0 */
+       u8 number_of_receiver_electrodes;
+
+       /* query 1 */
+       u8 number_of_transmitter_electrodes;
+
+       union {
+               struct {
+                       /* query2 */
+                       u8 f54_ad_query2_b0__1:2;
+                       u8 has_baseline:1;
+                       u8 has_image8:1;
+                       u8 f54_ad_query2_b4__5:2;
+                       u8 has_image16:1;
+                       u8 f54_ad_query2_b7:1;
+               };
+               u8 f54_ad_query2;
+       };
+
+       /* query 3.0 and 3.1 */
+       u16 clock_rate;
+
+       /* query 4 */
+       u8 touch_controller_family;
+
+       /* query 5 */
+       union {
+               struct {
+                       u8 has_pixel_touch_threshold_adjustment:1;
+                       u8 f54_ad_query5_b1__7:7;
+               };
+               u8 f54_ad_query5;
+       };
+
+       /* query 6 */
+       union {
+               struct {
+               u8 has_sensor_assignment:1;
+               u8 has_interference_metric:1;
+               u8 has_sense_frequency_control:1;
+               u8 has_firmware_noise_mitigation:1;
+               u8 f54_ad_query6_b4:1;
+               u8 has_two_byte_report_rate:1;
+               u8 has_one_byte_report_rate:1;
+               u8 has_relaxation_control:1;
+               };
+               u8 f54_ad_query6;
+       };
+
+       /* query 7 */
+       union {
+               struct {
+                       u8 curve_compensation_mode:2;
+                       u8 f54_ad_query7_b2__7:6;
+               };
+               u8 f54_ad_query7;
+       };
+
+       /* query 8 */
+       union {
+               struct {
+               u8 f54_ad_query2_b0:1;
+               u8 has_iir_filter:1;
+               u8 has_cmn_removal:1;
+               u8 has_cmn_maximum:1;
+               u8 has_pixel_threshold_hysteresis:1;
+               u8 has_edge_compensation:1;
+               u8 has_perf_frequency_noisecontrol:1;
+               u8 f54_ad_query8_b7:1;
+               };
+               u8 f54_ad_query8;
+       };
+
+       u8 f54_ad_query9;
+       u8 f54_ad_query10;
+       u8 f54_ad_query11;
+
+       /* query 12 */
+       union {
+               struct {
+                       u8 number_of_sensing_frequencies:4;
+                       u8 f54_ad_query12_b4__7:4;
+               };
+               u8 f54_ad_query12;
+       };
+};
+
+/* define report types */
+enum f54_report_types {
+       /* The numbering should follow automatically, here for clarity */
+       F54_8BIT_IMAGE = 1,
+       F54_16BIT_IMAGE = 2,
+       F54_RAW_16BIT_IMAGE = 3,
+       F54_HIGH_RESISTANCE = 4,
+       F54_TX_TO_TX_SHORT = 5,
+       F54_RX_TO_RX1 = 7,
+       F54_TRUE_BASELINE = 9,
+       F54_FULL_RAW_CAP_MIN_MAX = 13,
+       F54_RX_OPENS1 = 14,
+       F54_TX_OPEN = 15,
+       F54_TX_TO_GROUND = 16,
+       F54_RX_TO_RX2 = 17,
+       F54_RX_OPENS2 = 18,
+       F54_FULL_RAW_CAP = 19,
+       F54_FULL_RAW_CAP_RX_COUPLING_COMP = 20
+};
+
+/* data specific to fn $54 that needs to be kept around */
+struct rmi_fn_54_data {
+       struct f54_ad_query query;
+       u8 cmd;
+       enum f54_report_types report_type;
+       u16 fifoindex;
+       signed char status;
+       bool no_auto_cal;
+       /*
+        * May need to do something to make sure this reflects what is currently
+        * in data.
+        */
+       unsigned int report_size;
+       unsigned char *report_data;
+       unsigned int bufsize;
+       struct mutex data_mutex;
+       struct lock_class_key data_key;
+       struct mutex status_mutex;
+       struct lock_class_key status_key;
+#if F54_WATCHDOG
+       struct hrtimer watchdog;
+#endif
+       struct rmi_function_container *fc;
+       struct work_struct work;
+};
+
+/* sysfs functions */
+static ssize_t rmi_fn_54_report_type_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_report_type_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_get_report_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_force_cal_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_status_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+#ifdef KERNEL_VERSION_ABOVE_2_6_32
+static ssize_t rmi_fn_54_data_read(struct file *data_file, struct kobject *kobj,
+#else
+static ssize_t rmi_fn_54_data_read(struct kobject *kobj,
+#endif
+                                       struct bin_attribute *attributes,
+                                       char *buf, loff_t pos, size_t count);
+
+static ssize_t rmi_fn_54_num_rx_electrodes_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_num_tx_electrodes_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_image16_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_image8_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_baseline_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_clock_rate_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+
+static ssize_t rmi_fn_54_touch_controller_family_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+
+static ssize_t rmi_fn_54_has_pixel_touch_threshold_adjustment_show(
+               struct device *dev, struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_sensor_assignment_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_interference_metric_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_sense_frequency_control_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_firmware_noise_mitigation_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_two_byte_report_rate_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_one_byte_report_rate_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_relaxation_control_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_curve_compensation_mode_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_iir_filter_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_cmn_removal_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_cmn_maximum_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_pixel_threshold_hysteresis_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_edge_compensation_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_has_perf_frequency_noisecontrol_show(
+               struct device *dev, struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_number_of_sensing_frequencies_show(struct device *dev,
+                       struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_no_auto_cal_show(struct device *dev,
+                               struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_no_auto_cal_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_fifoindex_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_fifoindex_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count);
+
+static struct device_attribute attrs[] = {
+       __ATTR(report_type, RMI_RW_ATTR,
+               rmi_fn_54_report_type_show, rmi_fn_54_report_type_store),
+       __ATTR(get_report, RMI_WO_ATTR,
+               rmi_show_error, rmi_fn_54_get_report_store),
+       __ATTR(force_cal, RMI_WO_ATTR,
+               rmi_show_error, rmi_fn_54_force_cal_store),
+       __ATTR(status, RMI_RO_ATTR,
+               rmi_fn_54_status_show, rmi_store_error),
+       __ATTR(num_rx_electrodes, RMI_RO_ATTR,
+               rmi_fn_54_num_rx_electrodes_show, rmi_store_error),
+       __ATTR(num_tx_electrodes, RMI_RO_ATTR,
+               rmi_fn_54_num_tx_electrodes_show, rmi_store_error),
+       __ATTR(has_image16, RMI_RO_ATTR,
+               rmi_fn_54_has_image16_show, rmi_store_error),
+       __ATTR(has_image8, RMI_RO_ATTR,
+               rmi_fn_54_has_image8_show, rmi_store_error),
+       __ATTR(has_baseline, RMI_RO_ATTR,
+               rmi_fn_54_has_baseline_show, rmi_store_error),
+       __ATTR(clock_rate, RMI_RO_ATTR,
+               rmi_fn_54_clock_rate_show, rmi_store_error),
+       __ATTR(touch_controller_family, RMI_RO_ATTR,
+               rmi_fn_54_touch_controller_family_show, rmi_store_error),
+       __ATTR(has_pixel_touch_threshold_adjustment, RMI_RO_ATTR,
+               rmi_fn_54_has_pixel_touch_threshold_adjustment_show
+                                                       , rmi_store_error),
+       __ATTR(has_sensor_assignment, RMI_RO_ATTR,
+               rmi_fn_54_has_sensor_assignment_show, rmi_store_error),
+       __ATTR(has_interference_metric, RMI_RO_ATTR,
+               rmi_fn_54_has_interference_metric_show, rmi_store_error),
+       __ATTR(has_sense_frequency_control, RMI_RO_ATTR,
+               rmi_fn_54_has_sense_frequency_control_show, rmi_store_error),
+       __ATTR(has_firmware_noise_mitigation, RMI_RO_ATTR,
+               rmi_fn_54_has_firmware_noise_mitigation_show, rmi_store_error),
+       __ATTR(has_two_byte_report_rate, RMI_RO_ATTR,
+               rmi_fn_54_has_two_byte_report_rate_show, rmi_store_error),
+       __ATTR(has_one_byte_report_rate, RMI_RO_ATTR,
+               rmi_fn_54_has_one_byte_report_rate_show, rmi_store_error),
+       __ATTR(has_relaxation_control, RMI_RO_ATTR,
+               rmi_fn_54_has_relaxation_control_show, rmi_store_error),
+       __ATTR(curve_compensation_mode, RMI_RO_ATTR,
+               rmi_fn_54_curve_compensation_mode_show, rmi_store_error),
+       __ATTR(has_iir_filter, RMI_RO_ATTR,
+               rmi_fn_54_has_iir_filter_show, rmi_store_error),
+       __ATTR(has_cmn_removal, RMI_RO_ATTR,
+               rmi_fn_54_has_cmn_removal_show, rmi_store_error),
+       __ATTR(has_cmn_maximum, RMI_RO_ATTR,
+               rmi_fn_54_has_cmn_maximum_show, rmi_store_error),
+       __ATTR(has_pixel_threshold_hysteresis, RMI_RO_ATTR,
+               rmi_fn_54_has_pixel_threshold_hysteresis_show, rmi_store_error),
+       __ATTR(has_edge_compensation, RMI_RO_ATTR,
+               rmi_fn_54_has_edge_compensation_show, rmi_store_error),
+       __ATTR(has_perf_frequency_noisecontrol, RMI_RO_ATTR,
+             rmi_fn_54_has_perf_frequency_noisecontrol_show, rmi_store_error),
+       __ATTR(number_of_sensing_frequencies, RMI_RO_ATTR,
+               rmi_fn_54_number_of_sensing_frequencies_show, rmi_store_error),
+       __ATTR(no_auto_cal, RMI_RW_ATTR,
+               rmi_fn_54_no_auto_cal_show, rmi_fn_54_no_auto_cal_store),
+       __ATTR(fifoindex, RMI_RW_ATTR,
+               rmi_fn_54_fifoindex_show, rmi_fn_54_fifoindex_store),
+};
+
+struct bin_attribute dev_rep_data = {
+       .attr = {
+                .name = "rep_data",
+                .mode = RMI_RO_ATTR},
+       .size = 0,
+       .read = rmi_fn_54_data_read,
+};
+
+#if F54_WATCHDOG
+static enum hrtimer_restart clear_status(struct hrtimer *timer);
+
+static void clear_status_worker(struct work_struct *work);
+#endif
+
+static int rmi_f54_init(struct rmi_function_container *fc)
+{
+       struct rmi_fn_54_data *instance_data;
+       int retval = 0;
+       int attr_count = 0;
+
+       dev_info(&fc->dev, "Intializing F54.");
+
+       instance_data = kzalloc(sizeof(struct rmi_fn_54_data), GFP_KERNEL);
+       if (!instance_data) {
+               dev_err(&fc->dev, "Failed to allocate rmi_fn_54_data.\n");
+               retval = -ENOMEM;
+               goto error_exit;
+       }
+       fc->data = instance_data;
+       instance_data->fc = fc;
+
+#if F54_WATCHDOG
+       /* Set up watchdog timer to catch unanswered get_report commands */
+       hrtimer_init(&instance_data->watchdog, CLOCK_MONOTONIC,
+                                                       HRTIMER_MODE_REL);
+       instance_data->watchdog.function = clear_status;
+
+       /* work function to do unlocking */
+       INIT_WORK(&instance_data->work, clear_status_worker);
+#endif
+
+       /* Read F54 Query Data */
+       retval = rmi_read_block(fc->rmi_dev, fc->fd.query_base_addr,
+               (u8 *)&instance_data->query, sizeof(instance_data->query));
+       if (retval < 0) {
+               dev_err(&fc->dev, "Could not read query registers"
+                       " from 0x%04x\n", fc->fd.query_base_addr);
+               goto error_exit;
+       }
+
+       __mutex_init(&instance_data->data_mutex, "data_mutex",
+                    &instance_data->data_key);
+
+       __mutex_init(&instance_data->status_mutex, "status_mutex",
+                    &instance_data->status_key);
+
+       dev_dbg(&fc->dev, "Creating sysfs files.");
+       /* Set up sysfs device attributes. */
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               if (sysfs_create_file
+                   (&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
+                       dev_err(&fc->dev, "Failed to create sysfs file for %s.",
+                            attrs[attr_count].attr.name);
+                       retval = -ENODEV;
+                       goto error_exit;
+               }
+       }
+       /* Binary sysfs file to report the data back */
+       retval = sysfs_create_bin_file(&fc->dev.kobj, &dev_rep_data);
+       if (retval < 0) {
+               dev_err(&fc->dev, "Failed to create sysfs file for F54 data "
+                                       "(error = %d).\n", retval);
+               retval = -ENODEV;
+               goto error_exit;
+       }
+       instance_data->status = IDLE;
+       return retval;
+
+error_exit:
+       dev_err(&fc->dev, "An error occured in F54 init!\n");
+       for (attr_count--; attr_count >= 0; attr_count--)
+               sysfs_remove_file(&fc->dev.kobj,
+                                 &attrs[attr_count].attr);
+       kfree(instance_data);
+       return retval;
+}
+
+static void set_report_size(struct rmi_fn_54_data *data)
+{
+       u8 rx = data->query.number_of_receiver_electrodes;
+       u8 tx = data->query.number_of_transmitter_electrodes;
+       switch (data->report_type) {
+       case F54_8BIT_IMAGE:
+               data->report_size = rx * tx;
+               break;
+       case F54_16BIT_IMAGE:
+       case F54_RAW_16BIT_IMAGE:
+       case F54_TRUE_BASELINE:
+       case F54_FULL_RAW_CAP:
+       case F54_FULL_RAW_CAP_RX_COUPLING_COMP:
+               data->report_size = 2 * rx * tx;
+               break;
+       case F54_HIGH_RESISTANCE:
+               data->report_size = RMI_54_HIGH_RESISTANCE_SIZE;
+               break;
+       case F54_FULL_RAW_CAP_MIN_MAX:
+               data->report_size = RMI_54_FULL_RAW_CAP_MIN_MAX_SIZE;
+               break;
+       case F54_TX_TO_TX_SHORT:
+       case F54_TX_OPEN:
+       case F54_TX_TO_GROUND:
+               data->report_size =  (tx + 7) / 8;
+               break;
+       case F54_RX_TO_RX1:
+       case F54_RX_OPENS1:
+               if (rx < tx)
+                       data->report_size = 2 * rx * rx;
+               else
+                       data->report_size = 2 * rx * tx;
+               break;
+       case F54_RX_TO_RX2:
+       case F54_RX_OPENS2:
+               if (rx <= tx)
+                       data->report_size = 0;
+               else
+                       data->report_size = 2 * rx * (rx - tx);
+               break;
+       default:
+               data->report_size = 0;
+       }
+}
+
+int rmi_f54_attention(struct rmi_function_container *fc, u8 *irq_bits)
+{
+       struct rmi_driver *driver = fc->rmi_dev->driver;
+       char fifo[2];
+       struct rmi_fn_54_data *data = fc->data;
+       int error = 0;
+
+       set_report_size(data);
+       if (data->report_size == 0) {
+               dev_err(&fc->dev, "Invalid report type set in %s. "
+                               "This should never happen.\n", __func__);
+               error = -EINVAL;
+               goto error_exit;
+       }
+       /*
+        * We need to ensure the buffer is big enough. A Buffer size of 0 means
+        * that the buffer has not been allocated.
+        */
+       if (data->bufsize < data->report_size) {
+               mutex_lock(&data->data_mutex);
+               if (data->bufsize > 0)
+                       kfree(data->report_data);
+               data->report_data = kzalloc(data->report_size, GFP_KERNEL);
+               if (!data->report_data) {
+                       dev_err(&fc->dev, "Failed to allocate report_data.\n");
+                       error = -ENOMEM;
+                       data->bufsize = 0;
+                       mutex_unlock(&data->data_mutex);
+                       goto error_exit;
+               }
+               data->bufsize = data->report_size;
+               mutex_unlock(&data->data_mutex);
+       }
+       dev_vdbg(&fc->dev, "F54 Interrupt handler is running.\nSize: %d\n",
+                data->report_size);
+       /*
+        * Read report type, fifo high, and fifo low
+        * error = rmi_read_multiple(rmifninfo->sensor,
+        *      rmifninfo->function_descriptor.data_base_addr ,
+        *      repfifo,3);
+        */
+       /* Write 0 to fifohi and fifolo. */
+       fifo[0] = 0;
+       fifo[1] = 0;
+       error = rmi_write_block(fc->rmi_dev, fc->fd.data_base_addr
+                               + RMI_F54_FIFO_OFFSET, fifo,    sizeof(fifo));
+       if (error < 0)
+               dev_err(&fc->dev, "Failed to write fifo to zero!\n");
+       else
+               error = rmi_read_block(fc->rmi_dev,
+                       fc->fd.data_base_addr + RMI_F54_REPORT_DATA_OFFSET,
+                       data->report_data, data->report_size);
+       if (error < 0)
+               dev_err(&fc->dev, "F54 data read failed. Code: %d.\n", error);
+       else if (error != data->report_size) {
+               error = -EINVAL;
+               goto error_exit;
+       }
+#if RAW_HEX
+       int l;
+       /* Debugging: Print out the file in hex. */
+       pr_info("Report data (raw hex):\n");
+       for (l = 0; l < data->report_size; l += 2) {
+               pr_info("%03d: 0x%02x%02x\n", l/2,
+                       data->report_data[l+1], data->report_data[l]);
+       }
+#endif
+#if HUMAN_READABLE
+       /* Debugging: Print out file in human understandable image */
+       switch (data->report_type) {
+       case F54_16BIT_IMAGE:
+       case F54_RAW_16BIT_IMAGE:
+       case F54_TRUE_BASELINE:
+       case F54_FULL_RAW_CAP:
+       case F54_FULL_RAW_CAP_RX_COUPLING_COMP:
+               pr_info("Report data (Image):\n");
+               int i, j, k;
+               char c[2];
+               short s;
+               k = 0;
+               for (i = 0; i < data->query.number_of_transmitter_electrodes;
+                                                                       i++) {
+                       for (j = 0; j <
+                            data->query.number_of_receiver_electrodes; j++) {
+                               c[0] = data->report_data[k];
+                               c[1] = data->report_data[k+1];
+                               memcpy(&s, &c, 2);
+                               if (s < -64)
+                                       printk(".");
+                               else if (s < 0)
+                                       printk("-");
+                               else if (s > 64)
+                                       printk("*");
+                               else if (s > 0)
+                                       printk("+");
+                               else
+                                       printk("0");
+                               k += 2;
+                       }
+                       pr_info("\n");
+               }
+               pr_info("EOF\n");
+               break;
+       default:
+               pr_info("Report type %d debug image not supported",
+                                                       data->report_type);
+       }
+#endif
+       error = IDLE;
+error_exit:
+       mutex_lock(&data->status_mutex);
+       /* Turn back on other interupts, if it
+        * appears that we turned them off. */
+       if (driver->restore_irq_mask) {
+               dev_dbg(&fc->dev, "Restoring interupts!\n");
+               driver->restore_irq_mask(fc->rmi_dev);
+       } else {
+               dev_err(&fc->dev, "No way to restore interrupts!\n");
+       }
+       data->status = error;
+       mutex_unlock(&data->status_mutex);
+       return data->status;
+}
+
+
+#if F54_WATCHDOG
+static void clear_status_worker(struct work_struct *work)
+{
+       struct rmi_fn_54_data *data = container_of(work,
+                                       struct rmi_fn_54_data, work);
+       struct rmi_function_container *fc = data->fc;
+       struct rmi_driver *driver = fc->rmi_dev->driver;
+       char command;
+       int result;
+
+       mutex_lock(&data->status_mutex);
+       if (data->status == BUSY) {
+               pr_info("F54 Timout Occured: Determining status.\n");
+               result = rmi_read_block(fc->rmi_dev, fc->fd.command_base_addr,
+                                                               &command, 1);
+               if (result < 0) {
+                       dev_err(&fc->dev, "Could not read get_report register "
+                               "from 0x%04x\n", fc->fd.command_base_addr);
+                       data->status = -ETIMEDOUT;
+               } else {
+                       if (command & GET_REPORT) {
+                               dev_warn(&fc->dev, "Report type unsupported!");
+                               data->status = -EINVAL;
+                       } else {
+                               data->status = -ETIMEDOUT;
+                       }
+               }
+               if (driver->restore_irq_mask) {
+                       dev_dbg(&fc->dev, "Restoring interupts!\n");
+                       driver->restore_irq_mask(fc->rmi_dev);
+               } else {
+                       dev_err(&fc->dev, "No way to restore interrupts!\n");
+               }
+       }
+       mutex_unlock(&data->status_mutex);
+}
+
+static enum hrtimer_restart clear_status(struct hrtimer *timer)
+{
+       struct rmi_fn_54_data *data = container_of(timer,
+                                       struct rmi_fn_54_data, watchdog);
+       schedule_work(&(data->work));
+       return HRTIMER_NORESTART;
+}
+#endif
+
+/* Check if report_type is valid */
+static bool is_report_type_valid(enum f54_report_types reptype)
+{
+       /* Basic checks on report_type to ensure we write a valid type
+        * to the sensor.
+        * TODO: Check Query3 to see if some specific reports are
+        * available. This is currently listed as a reserved register.
+        */
+       switch (reptype) {
+       case F54_8BIT_IMAGE:
+       case F54_16BIT_IMAGE:
+       case F54_RAW_16BIT_IMAGE:
+       case F54_HIGH_RESISTANCE:
+       case F54_TX_TO_TX_SHORT:
+       case F54_RX_TO_RX1:
+       case F54_TRUE_BASELINE:
+       case F54_FULL_RAW_CAP_MIN_MAX:
+       case F54_RX_OPENS1:
+       case F54_TX_OPEN:
+       case F54_TX_TO_GROUND:
+       case F54_RX_TO_RX2:
+       case F54_RX_OPENS2:
+       case F54_FULL_RAW_CAP:
+       case F54_FULL_RAW_CAP_RX_COUPLING_COMP:
+               return true;
+               break;
+       default:
+               return false;
+       }
+}
+
+/* SYSFS file show/store functions */
+static ssize_t rmi_fn_54_report_type_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->report_type);
+}
+
+static ssize_t rmi_fn_54_report_type_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count) {
+       int result;
+       unsigned long val;
+       unsigned char data;
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *instance_data;
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       /* need to convert the string data to an actual value */
+       result = strict_strtoul(buf, 10, &val);
+       if (result)
+               return result;
+       if (!is_report_type_valid(val)) {
+               dev_err(dev, "%s : Report type %d is invalid.\n",
+                                       __func__, (u8) val);
+               return -EINVAL;
+       }
+       mutex_lock(&instance_data->status_mutex);
+       if (instance_data->status != BUSY) {
+               instance_data->report_type = (enum f54_report_types)val;
+               data = (char)val;
+               /* Write the Report Type back to the first Block
+                * Data registers (F54_AD_Data0). */
+               result =
+                   rmi_write_block(fc->rmi_dev, fc->fd.data_base_addr,
+                                                               &data, 1);
+               mutex_unlock(&instance_data->status_mutex);
+               if (result < 0) {
+                       dev_err(dev, "%s : Could not write report type to"
+                               " 0x%x\n", __func__, fc->fd.data_base_addr);
+                       return result;
+               }
+               return count;
+       } else {
+               dev_err(dev, "%s : Report type cannot be changed in the middle"
+                               " of command.\n", __func__);
+               mutex_unlock(&instance_data->status_mutex);
+               return -EINVAL;
+       }
+}
+
+static ssize_t rmi_fn_54_get_report_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count) {
+       unsigned long val;
+       int error, result;
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *instance_data;
+       struct rmi_driver *driver;
+       u8 command;
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+       driver = fc->rmi_dev->driver;
+
+       /* need to convert the string data to an actual value */
+       error = strict_strtoul(buf, 10, &val);
+       if (error)
+               return error;
+       /* Do nothing if not set to 1. This prevents accidental commands. */
+       if (val != 1)
+               return count;
+       command = (unsigned char)GET_REPORT;
+       /* Basic checks on report_type to ensure we write a valid type
+        * to the sensor.
+        * TODO: Check Query3 to see if some specific reports are
+        * available. This is currently listed as a reserved register.
+        */
+       if (!is_report_type_valid(instance_data->report_type)) {
+               dev_err(dev, "%s : Report type %d is invalid.\n",
+                               __func__, instance_data->report_type);
+               return -EINVAL;
+       }
+       mutex_lock(&instance_data->status_mutex);
+       if (instance_data->status != IDLE) {
+               if (instance_data->status != BUSY) {
+                       dev_err(dev, "F54 status is in an abnormal state: 0x%x",
+                                                       instance_data->status);
+               }
+               mutex_unlock(&instance_data->status_mutex);
+               return count;
+       }
+       /* Store interrupts */
+       /* Do not exit if we fail to turn off interupts. We are likely
+        * to still get useful data. The report data can, however, be
+        * corrupted, and there may be unexpected behavior.
+        */
+       dev_dbg(dev, "Storing and overriding interupts\n");
+       if (driver->store_irq_mask)
+               driver->store_irq_mask(fc->rmi_dev,
+                                       fc->irq_mask);
+       else
+               dev_err(dev, "No way to store interupts!\n");
+       instance_data->status = BUSY;
+
+       /* small delay to avoid race condition in firmare. This value is a bit
+        * higher than absolutely necessary. Should be removed once issue is
+        * resolved in firmware. */
+
+       mdelay(2);
+
+       /* Write the command to the command register */
+       result = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr,
+                                               &command, 1);
+       mutex_unlock(&instance_data->status_mutex);
+       if (result < 0) {
+               dev_err(dev, "%s : Could not write command to 0x%x\n",
+                               __func__, fc->fd.command_base_addr);
+               return result;
+       }
+#if F54_WATCHDOG
+       /* start watchdog timer */
+       hrtimer_start(&instance_data->watchdog, ktime_set(1, 0),
+                                                       HRTIMER_MODE_REL);
+#endif
+       return count;
+}
+
+static ssize_t rmi_fn_54_force_cal_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count) {
+       unsigned long val;
+       int error, result;
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *instance_data;
+       struct rmi_driver *driver;
+       u8 command;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+       driver = fc->rmi_dev->driver;
+
+       /* need to convert the string data to an actual value */
+       error = strict_strtoul(buf, 10, &val);
+       if (error)
+               return error;
+       /* Do nothing if not set to 1. This prevents accidental commands. */
+       if (val != 1)
+               return count;
+
+       command = (unsigned char)FORCE_CAL;
+
+       if (instance_data->status == BUSY)
+               return -EBUSY;
+       /* Write the command to the command register */
+       result = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr,
+                                               &command, 1);
+       if (result < 0) {
+               dev_err(dev, "%s : Could not write command to 0x%x\n",
+                               __func__, fc->fd.command_base_addr);
+               return result;
+       }
+       return count;
+}
+
+static ssize_t rmi_fn_54_status_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *instance_data;
+
+       fc = to_rmi_function_container(dev);
+       instance_data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", instance_data->status);
+}
+
+static ssize_t rmi_fn_54_num_rx_electrodes_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                               data->query.number_of_receiver_electrodes);
+}
+
+static ssize_t rmi_fn_54_num_tx_electrodes_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.number_of_transmitter_electrodes);
+}
+
+static ssize_t rmi_fn_54_has_image16_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.has_image16);
+}
+
+static ssize_t rmi_fn_54_has_image8_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.has_image8);
+}
+
+static ssize_t rmi_fn_54_has_baseline_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.has_baseline);
+}
+
+static ssize_t rmi_fn_54_clock_rate_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.clock_rate);
+}
+
+
+static ssize_t rmi_fn_54_touch_controller_family_show(struct device *dev,
+                               struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.touch_controller_family);
+}
+
+
+static ssize_t rmi_fn_54_has_pixel_touch_threshold_adjustment_show(
+               struct device *dev, struct device_attribute *attr, char *buf) {
+       struct rmi_function_container *fc;
+       struct rmi_fn_54_data *data;
+
+       fc = to_rmi_function_container(dev);
+       data = fc->data;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                   &nbs