Input: touch: synaptics: Direct Touch kernel files.
Xiaohui Tao [Fri, 15 Jun 2012 18:58:25 +0000 (11:58 -0700)]
Code drop from synaptics

Below is the detailed description of the change:

* Support for multiple RMI4 devices has been added.

* The Kconfig options have been further simplified. CONFIG_RMI4_BUS and
CONFIG_RMI4_GENERIC are replaced by a single control, CONFIG_RMI4_CORE.
You'll need to update your defconfig file appropriately.

* some debugfs and sysfs files have moved around.  If you have tools or
scripts that depend on these files, you'll need to update the paths.

* The driver_name field of rmi_device_platform_data has been removed, as
it was no longer necessary.

* Polling support has been added.  Polling works on I2C and SPIv1.  It
does not work for SPIv2, since that requires a working ATTN line.

* A sensor_type field has been added to the F11 per-sensor platform
data.  This allows you to specify whether the device is touchscreen or
touchpad type sensor in cases where the register map does not allow this
to be determined programmatically.

* F11 platform data has been updated to a per-sensor basis (remember that
a single F11 module might have more than one 2D sensor attached to it).

* F11 virtual button maps have been switched to a per-sensor basis.

* F11 Type B support is always on, and removed from Kconfig. Per-sensor
platformdata is provided if you need to force Multifinger Type A input.

* IMPORTANT: the RMI4 driver has been converted over to the Linux kernel
bus and driver model.  This means that the sysfs file structure has changed.
Some files have moved to debugfs, and for remaining files, the sysfs tree
structure has changed.  Refer to Documentation/ABI/testing/debugfs-rmi4 and
sysfs-rmi4 for full details.

* ALSO IMPORTANT: The Kconfig options have been simplified. Several have
been eliminated, and others have been consolidated.  Please consult Kconfig
and make any necessary related changes to your kernel configuration.

* ATTN interrupts are not enabled until the F01 function driver is bound to
the sensor.  This should eliminate spurious interrupts that were seen during
the system bootup process.

Bug 960856
Bug 1253719

Change-Id: I773ec9210e0d6c7e8f03d551ca61bbda156080f7
Signed-off-by: Xiaohui Tao <xtao@nvidia.com>
Reviewed-on: http://git-master/r/130310
Reviewed-by: Seema Khowala <seemaj@nvidia.com>
Tested-by: Seema Khowala <seemaj@nvidia.com>
Reviewed-by: Thomas Cherry <tcherry@nvidia.com>

26 files changed:
drivers/input/touchscreen/rmi4/Kconfig [new file with mode: 0644]
drivers/input/touchscreen/rmi4/Makefile
drivers/input/touchscreen/rmi4/rmi_bus.c
drivers/input/touchscreen/rmi4/rmi_dev.c
drivers/input/touchscreen/rmi4/rmi_driver.c
drivers/input/touchscreen/rmi4/rmi_driver.h
drivers/input/touchscreen/rmi4/rmi_f01.c
drivers/input/touchscreen/rmi4/rmi_f01.h [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f09.c
drivers/input/touchscreen/rmi4/rmi_f11.c
drivers/input/touchscreen/rmi4/rmi_f17.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f19.c
drivers/input/touchscreen/rmi4/rmi_f1a.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f21.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f30.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f31.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f34.c
drivers/input/touchscreen/rmi4/rmi_f34.h [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f41.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_f54.c
drivers/input/touchscreen/rmi4/rmi_fw_update.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_i2c.c
drivers/input/touchscreen/rmi4/rmi_smbus.c [new file with mode: 0644]
drivers/input/touchscreen/rmi4/rmi_spi.c
include/linux/rmi.h
include/uapi/linux/input.h

diff --git a/drivers/input/touchscreen/rmi4/Kconfig b/drivers/input/touchscreen/rmi4/Kconfig
new file mode 100644 (file)
index 0000000..09a57af
--- /dev/null
@@ -0,0 +1,226 @@
+#
+# RMI4 configuration
+#
+config RMI4_CORE
+       tristate "Synaptics RMI4 bus support"
+       help
+         Say Y here if you want to support the Synaptics RMI4 bus.  This is
+         required for all RMI4 device support.
+
+         If unsure, say Y.
+
+config RMI4_DEBUG
+       bool "RMI4 Debugging"
+       depends on RMI4_CORE
+       select DEBUG_FS
+       help
+         Say Y here to enable debug feature in the RMI4 driver.
+
+         Note that the RMI4 driver debug features can generate a lot of
+         output (potentially clogging up your dmesg output) and generally
+         slow down driver operation.  It's recommended to enable them only
+         if you are actively developing/debugging RMI4 features.
+
+         If unsure, say N.
+
+config RMI4_FWLIB
+       bool "RMI4 Firmware Update"
+       depends on RMI4_CORE
+       help
+         Say Y here to enable in-kernel firmware update capability.
+
+         The RMI4 core will check for firmware updates during the device
+         initialization process, and apply the updates if appropriate.
+
+config RMI4_I2C
+       tristate "RMI4 I2C Support"
+       depends on RMI4_CORE && I2C
+       help
+         Say Y here if you want to support RMI4 devices connected to an I2C
+         bus.
+
+         If unsure, say Y.
+
+
+config RMI4_SPI
+       tristate "RMI4 SPI Support"
+       depends on RMI4_CORE && SPI
+       help
+         Say Y here if you want to support RMI4 devices connected to an SPI
+         bus.
+
+         If unsure, say Y.
+
+config RMI4_SMB
+       tristate "RMI4 SMB Support"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to support RMI4 devices connected to an SMB
+         bus.
+
+         If unsure, say Y.
+
+
+config RMI4_F1A
+       tristate "RMI4 Function 1A (capacitive button sensor)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 1A.
+
+         Function 1A provides self testing for touchscreens and touchpads.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f1a.
+
+config RMI4_F09
+       tristate "RMI4 Function 09 (self testing)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 09.
+
+         Function 09 provides self testing for touchscreens and touchpads.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f09.
+
+config RMI4_F11
+       tristate "RMI4 Function 11 (2D pointing)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 11.
+
+         Function 11 provides 2D multifinger pointing for touchscreens and
+         touchpads.  For sensors that support relative pointing, F11 also
+         provides mouse input.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f11.
+
+config RMI4_F11_PEN
+       bool "RMI4 F11 Pen Support"
+       depends on RMI4_F11
+       help
+         Say Y here to add support for pen input to RMI4 function 11.
+
+         If this feature is enabled, when pen inputs are detected they
+         will be reported to the input stream as MT_TOOL_PEN.  Otherwise,
+         pens will be treated the same as fingers.
+
+         Not all UI implementations deal gracefully with pen discrimination.
+         If your system is not recognizing pen touches and you know your
+         sensor supports pen input, you probably want to turn this feature
+         off.
+
+config RMI4_VIRTUAL_BUTTON
+       tristate "RMI4 Vitual Button"
+       depends on RMI4_F11
+       help
+         Say Y here if you want to add support for RMI4 virtual button to F11.
+
+         The virtual button feature implement the virtual button device in
+         certain RMI4 touch sensors.
+
+         This works only if your sensor supports F11 gestures.
+
+config RMI4_F17
+       tristate "RMI4 Function 17 (pointing sticks)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 17.
+
+         Function 19 provides support for capacitive and resistive
+         pointing sticks.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f17.
+
+config RMI4_F19
+       tristate "RMI4 Function 19 (0D pointing)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 19.
+
+         Function 19 provides support for capacitive buttons for sensors
+         that implement capacitive buttons.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f19.
+
+config RMI4_F21
+       tristate "RMI4 Function 21 (2D Force)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 21.
+
+         Function 21 provides 2D Force Sensing for ForcePad products.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f21.
+
+config RMI4_F30
+       tristate "RMI4 Function 30 (GPIO LED)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 30.
+
+         Function 30 provides GPIO LED support for sensors.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f30.
+
+config RMI4_F31
+       tristate "RMI4 Function 31 (LED)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 31.
+
+         Function 31 provides LED support for sensors.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f31.
+
+config RMI4_F34
+       tristate "RMI4 Function 34 (device reflash)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 34.
+
+         Function 34 provides firmware upgrade capability for your sensor.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f34.
+
+config RMI4_F41
+       tristate "RMI4 Function 41 (active pen)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 41.
+
+         Function 41 provides active pen support for active pen enabled sensors.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f41.
+
+config RMI4_F54
+       tristate "RMI4 Function 54 (analog diagnostics)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 54.
+
+         Function 54 provides access to various diagnostic features in
+         certain RMI4 touch sensors.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-f54.
+
+config RMI4_DEV
+       tristate "Synaptics direct RMI device support (rmidev)"
+       depends on GPIO_SYSFS && (RMI4_I2C || RMI4_SPI)
+       help
+         Say Y here to add support for rmidev.
+
+         The rmidev feature implements a character device providing access
+         to RMI4 sensor register maps.
+
+         To compile this driver as a module, choose M here: the
+         module will be called rmi-dev.
index a7375ed..639a4d7 100644 (file)
@@ -1,18 +1,28 @@
-#
-# Makefile for Synaptics Touchscreen (RMI4/SPI)
-#
-GCOV_PROFILE := y
 
-ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_core.o
+rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
+#rmi_core-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_fw_update.o
 
-#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
+# Function drivers
+#obj-$(CONFIG_RMI4_F09) += rmi_f09.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f1a.o
 obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f11.o
+#obj-$(CONFIG_RMI4_F17) += rmi_f17.o
 obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f19.o
+#obj-$(CONFIG_RMI4_F21) += rmi_f21.o
+#obj-$(CONFIG_RMI4_F30) += rmi_f30.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f31.o
 obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f34.o
+#obj-$(CONFIG_RMI4_F41) += rmi_f41.o
 obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_f54.o
+
+# Transport layers
+obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_spi.o
+obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
+
+# Other features
 obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi_dev.o
+
+
+ccflags-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += -DDEBUG
index def8a20..b11ff27 100644 (file)
 /*
- * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011, 2012 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.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
+
 #include <linux/kernel.h>
 #include <linux/device.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
+#include <linux/kconfig.h>
 #include <linux/list.h>
+#include <linux/pm.h>
 #include <linux/rmi.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include "rmi_driver.h"
 
-static struct rmi_function_list {
-       struct list_head list;
-       struct rmi_function_handler *fh;
-} rmi_supported_functions;
+DEFINE_MUTEX(rmi_bus_mutex);
 
-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;
+static struct attribute *function_dev_attrs[] = {
+       NULL,
+};
 
-       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);
+static struct attribute_group function_dev_attr_group = {
+       .attrs = function_dev_attrs,
+};
 
-       pr_info("rmi_driver->driver.name =  %s\n", rmi_driver->driver.name);
-       pr_info("device:rmi_device:rmi_device_platform_data:driver_name = %s\n",
-               pdata->driver_name);
+static const struct attribute_group *function_dev_attr_groups[] = {
+       &function_dev_attr_group,
+       NULL,
+};
 
-       if (!strcmp(pdata->driver_name, rmi_driver->driver.name)) {
-               rmi_dev->driver = rmi_driver;
-               return 1;
-       }
-       pr_info("names DO NOT match, so return nothing\n");
+struct device_type rmi_function_type = {
+       .name = "rmi_function",
+       .groups = function_dev_attr_groups,
+};
+EXPORT_SYMBOL_GPL(rmi_function_type);
 
-       return 0;
-}
+static struct attribute *sensor_dev_attrs[] = {
+       NULL,
+};
+static struct attribute_group sensor_dev_attr_group = {
+       .attrs = sensor_dev_attrs,
+};
+
+static const struct attribute_group *sensor_dev_attr_groups[] = {
+       &sensor_dev_attr_group,
+       NULL,
+};
+
+struct device_type rmi_sensor_type = {
+       .name = "rmi_sensor",
+       .groups = sensor_dev_attr_groups,
+};
+EXPORT_SYMBOL_GPL(rmi_sensor_type);
+
+static atomic_t physical_device_count = ATOMIC_INIT(0);
+
+#ifdef CONFIG_RMI4_DEBUG
+static struct dentry *rmi_debugfs_root;
+#endif
 
 #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;
+       struct device_driver *driver = dev->driver;
+       const struct dev_pm_ops *pm;
 
+       if (!driver)
+               return 0;
+
+       pm = driver->pm;
        if (pm && pm->suspend)
                return pm->suspend(dev);
-#endif
+       if (driver->suspend)
+               return driver->suspend(dev, PMSG_SUSPEND);
 
        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__);
+       struct device_driver *driver = dev->driver;
+       const struct dev_pm_ops *pm;
 
+       if (!driver)
+               return 0;
+
+       pm = driver->pm;
        if (pm && pm->resume)
                return pm->resume(dev);
-#endif
+       if (driver->resume)
+               return driver->resume(dev);
 
        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);
+static SIMPLE_DEV_PM_OPS(rmi_bus_pm_ops,
+                        rmi_bus_suspend, rmi_bus_resume);
 
-       return 0;
-}
 
-static int rmi_bus_remove(struct device *dev)
+static void release_rmidev_device(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);
+       kfree(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
-};
-
+/**
+ * rmi_register_phys_device - register a physical device connection on the RMI
+ * bus.  Physical drivers provide communication from the devices on the bus to
+ * the RMI4 sensor on a bus such as SPI, I2C, and so on.
+ *
+ * @phys: the physical device to register
+ */
 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;
@@ -146,168 +132,254 @@ int rmi_register_phys_device(struct rmi_phys_device *phys)
 
        rmi_dev->phys = phys;
        rmi_dev->dev.bus = &rmi_bus_type;
-       dev_set_name(&rmi_dev->dev, "sensor%02d", phys_device_num++);
+       rmi_dev->dev.type = &rmi_sensor_type;
+
+       rmi_dev->number = atomic_inc_return(&physical_device_count) - 1;
+       rmi_dev->dev.release = release_rmidev_device;
+
+       dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number);
+       dev_dbg(phys->dev, "%s: Registered %s as %s.\n", __func__,
+               pdata->sensor_name, dev_name(&rmi_dev->dev));
+
+#ifdef CONFIG_RMI4_DEBUG
+       if (rmi_debugfs_root) {
+               rmi_dev->debugfs_root = debugfs_create_dir(
+                       dev_name(&rmi_dev->dev), rmi_debugfs_root);
+               if (!rmi_dev->debugfs_root)
+                       dev_err(&rmi_dev->dev, "Failed to create debugfs root.\n");
+       }
+#endif
 
        phys->rmi_dev = rmi_dev;
-       pr_info("registering physical device:\n");
-       pr_info("dev.init_name = %s\n", rmi_dev->dev.init_name);
-       pr_info("dev.bus->name = %s\n", rmi_dev->dev.bus->name);
        return device_register(&rmi_dev->dev);
 }
-EXPORT_SYMBOL(rmi_register_phys_device);
+EXPORT_SYMBOL_GPL(rmi_register_phys_device);
 
+/**
+ * rmi_unregister_phys_device - unregister a physical device connection
+ * @phys: the physical driver to unregister
+ *
+ */
 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__);
+
+#ifdef CONFIG_RMI4_DEBUG
+       if (rmi_dev->debugfs_root)
+               debugfs_remove(rmi_dev->debugfs_root);
+#endif
 
        device_unregister(&rmi_dev->dev);
-       kfree(rmi_dev);
 }
-EXPORT_SYMBOL(rmi_unregister_phys_device);
+EXPORT_SYMBOL_GPL(rmi_unregister_phys_device);
 
-int rmi_register_driver(struct rmi_driver *driver)
+static int rmi_bus_match(struct device *dev, struct device_driver *drv)
 {
-       pr_info("in function ____%s____  \n", __func__);
-       driver->driver.bus = &rmi_bus_type;
-       return driver_register(&driver->driver);
-}
-EXPORT_SYMBOL(rmi_register_driver);
+       struct rmi_function_driver *fn_drv;
+       struct rmi_function_dev *fn;
+
+       /*
+        * This seems a little broken to me.  It  means a system can only ever
+        * have one kind of sensor driver.  It'll work for now, but I think in
+        * the long run we need to revisit this.
+        */
+       if (dev->type == &rmi_sensor_type && drv == &rmi_sensor_driver.driver)
+               return 1;
 
-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 (dev->type != &rmi_function_type)
+       return 0;
 
-       if (rmi_dev->driver == driver)
-               rmi_dev->driver = NULL;
+       fn = to_rmi_function_dev(dev);
+       fn_drv = to_rmi_function_driver(drv);
 
-       return 0;
+       return fn->fd.function_number == fn_drv->func;
 }
 
-void rmi_unregister_driver(struct rmi_driver *driver)
+static int rmi_function_probe(struct device *dev)
 {
-       bus_for_each_dev(&rmi_bus_type, NULL, driver, __rmi_driver_remove);
-       driver_unregister(&driver->driver);
-}
-EXPORT_SYMBOL(rmi_unregister_driver);
+       struct rmi_function_driver *fn_drv;
+       struct rmi_function_dev *fn = to_rmi_function_dev(dev);
 
-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__);
+       fn_drv = to_rmi_function_driver(dev->driver);
 
-       driver = rmi_dev->driver;
-       if (driver && driver->fh_add)
-               driver->fh_add(rmi_dev, data);
+       if (fn_drv->probe)
+               return fn_drv->probe(fn);
 
        return 0;
 }
 
-int rmi_register_function_driver(struct rmi_function_handler *fh)
+static int rmi_function_remove(struct device *dev)
 {
-       struct rmi_function_list *entry;
-       struct rmi_function_handler *fh_dup;
+       struct rmi_function_driver *fn_drv;
+       struct rmi_function_dev *fn = to_rmi_function_dev(dev);
 
-       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;
+       fn_drv = to_rmi_function_driver(dev->driver);
 
-       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);
+       if (fn_drv->remove)
+               return fn_drv->remove(fn);
 
        return 0;
 }
-EXPORT_SYMBOL(rmi_register_function_driver);
 
-static int __rmi_bus_fh_remove(struct device *dev, void *data)
+static int rmi_sensor_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->fh_remove)
-               driver->fh_remove(rmi_dev, data);
+       driver = to_rmi_driver(dev->driver);
 
+       if (!driver->remove)
+               return driver->remove(rmi_dev);
        return 0;
 }
 
-void rmi_unregister_function_driver(struct rmi_function_handler *fh)
+static int rmi_bus_remove(struct device *dev)
+{
+       if (dev->type == &rmi_function_type)
+               return rmi_function_remove(dev);
+       else if (dev->type == &rmi_sensor_type)
+               return rmi_sensor_remove(dev);
+       return -EINVAL;
+}
+
+struct bus_type rmi_bus_type = {
+       .name           = "rmi",
+       .match          = rmi_bus_match,
+       .remove         = rmi_bus_remove,
+       .pm             = &rmi_bus_pm_ops,
+};
+EXPORT_SYMBOL_GPL(rmi_bus_type);
+
+/**
+ * rmi_register_function_driver - register a driver for an RMI function
+ * @fn_drv: RMI driver that should be registered.
+ * @module: pointer to module that implements the driver
+ * @mod_name: name of the module implementing the driver
+ *
+ * This function performs additional setup of RMI function driver and
+ * registers it with the RMI core so that it can be bound to
+ * RMI function devices.
+ */
+int __rmi_register_function_driver(struct rmi_function_driver *fn_drv,
+                                    struct module *owner,
+                                    const char *mod_name)
 {
-       struct rmi_function_list *entry, *n;
-       pr_info("in function ____%s____  \n", __func__);
+       int error;
 
-       /* notify devices of the removal of the function handler */
-       bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_remove);
+       fn_drv->driver.bus = &rmi_bus_type;
+       fn_drv->driver.owner = owner;
+       if (!fn_drv->driver.probe)
+               fn_drv->driver.probe = rmi_function_probe;
+       fn_drv->driver.mod_name = mod_name;
 
-       list_for_each_entry_safe(entry, n, &rmi_supported_functions.list, list)
-               if (entry->fh->func == fh->func) {
-                       list_del(&entry->list);
-                       kfree(entry);
+       error = driver_register(&fn_drv->driver);
+       if (error) {
+               pr_err("driver_register() failed for %s, error: %d\n",
+                       fn_drv->driver.name, error);
+               return error;
                }
+
+       return 0;
 }
-EXPORT_SYMBOL(rmi_unregister_function_driver);
+EXPORT_SYMBOL_GPL(__rmi_register_function_driver);
 
-struct rmi_function_handler *rmi_get_function_handler(int id)
+/**
+ * rmi_unregister_function_driver - unregister given RMI function driver
+ * @fn_drv: RMI driver that should be unregistered.
+ *
+ * This function unregisters given function driver from RMI core which
+ * causes it to be unbound from the function devices.
+ */
+void rmi_unregister_function_driver(struct rmi_function_driver *fn_drv)
 {
-       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;
+       driver_unregister(&fn_drv->driver);
+}
+EXPORT_SYMBOL_GPL(rmi_unregister_function_driver);
 
-       return NULL;
+/**
+ * rmi_for_each_dev - provides a way for other parts of the system to enumerate
+ * the devices on the RMI bus.
+ *
+ * @data - will be passed into the callback function.
+ * @func - will be called for each device.
+ */
+int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data))
+{
+       int retval;
+       mutex_lock(&rmi_bus_mutex);
+       retval = bus_for_each_dev(&rmi_bus_type, NULL, data, func);
+       mutex_unlock(&rmi_bus_mutex);
+       return retval;
 }
-EXPORT_SYMBOL(rmi_get_function_handler);
+EXPORT_SYMBOL_GPL(rmi_for_each_dev);
 
 static int __init rmi_bus_init(void)
 {
        int error;
 
-       pr_info("in function ____%s____  \n", __func__);
-       INIT_LIST_HEAD(&rmi_supported_functions.list);
+       mutex_init(&rmi_bus_mutex);
 
        error = bus_register(&rmi_bus_type);
-       if (error < 0) {
-               pr_err("%s: error registering the RMI bus: %d\n", __func__,
-                      error);
+       if (error) {
+               pr_err("%s: error registering the RMI bus: %d\n",
+                       __func__, error);
                return error;
        }
-       pr_info("%s: successfully registered RMI bus.\n", __func__);
+
+#ifdef CONFIG_RMI4_DEBUG
+       rmi_debugfs_root = debugfs_create_dir(rmi_bus_type.name, NULL);
+       if (!rmi_debugfs_root)
+               pr_err("%s: Failed to create debugfs root.\n",
+                       __func__);
+       else if (IS_ERR(rmi_debugfs_root)) {
+               pr_err("%s: Kernel may not contain debugfs support, code=%ld\n",
+                       __func__, PTR_ERR(rmi_debugfs_root));
+               rmi_debugfs_root = NULL;
+       }
+#endif
+
+       error = rmi_register_function_driver(&rmi_f01_driver);
+       if (error) {
+               pr_err("%s: error registering the RMI F01 driver: %d\n",
+                       __func__, error);
+               goto err_unregister_bus;
+       }
+
+       error = rmi_register_sensor_driver();
+       if (error) {
+               pr_err("%s: error registering the RMI sensor driver: %d\n",
+                       __func__, error);
+               goto err_unregister_f01;
+       }
 
        return 0;
+
+err_unregister_f01:
+       rmi_unregister_function_driver(&rmi_f01_driver);
+err_unregister_bus:
+       bus_unregister(&rmi_bus_type);
+       return error;
 }
 
 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);
-       }
-
+       /*
+        * We should only ever get here if all drivers are unloaded, so
+        * all we have to do at this point is unregister ourselves.
+        */
+#ifdef CONFIG_RMI4_DEBUG
+       if (rmi_debugfs_root)
+               debugfs_remove(rmi_debugfs_root);
+#endif
+       rmi_unregister_sensor_driver();
+       rmi_unregister_function_driver(&rmi_f01_driver);
        bus_unregister(&rmi_bus_type);
 }
 
 module_init(rmi_bus_init);
 module_exit(rmi_bus_exit);
 
-MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com");
 MODULE_DESCRIPTION("RMI bus");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(RMI_DRIVER_VERSION);
index fa21ef9..ff2f1ce 100644 (file)
@@ -1,50 +1,62 @@
 /*
  * 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.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
-#include <linux/fs.h>
 #include <linux/delay.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
+#include <linux/fs.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
 #include <linux/syscalls.h>
+#include <linux/uaccess.h>
 
-#include <linux/rmi.h>
 #include "rmi_driver.h"
 
 #define CHAR_DEVICE_NAME "rmi"
+#define DEVICE_CLASS_NAME "rmidev"
 
+#define RMI_CHAR_DEV_TMPBUF_SZ 128
+#define RMI_REG_ADDR_PAGE_SELECT 0xFF
 #define REG_ADDR_LIMIT 0xFFFF
 
+struct rmidev_data {
+       /* mutex for file operation*/
+       struct mutex file_mutex;
+       /* main char dev structure */
+       struct cdev main_dev;
+
+       /* pointer to the corresponding RMI4 device.  We use this to do */
+       /* read, write, etc. */
+       struct rmi_device *rmi_dev;
+       /* reference count */
+       int ref_count;
+
+       struct class *device_class;
+};
+
+
 /*store dynamically allocated major number of char device*/
-static int rmi_char_dev_major_num;
+static int rmidev_major_num;
+
+
+static struct class *rmidev_class;
 
 
 /* file operations for RMI char device */
 
 /*
- * rmi_char_dev_llseek: - use to setup register address
+ * rmidev_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
+ *       register address
  *
  *       if whence == SEEK_CUR,
  *       offset from current position
@@ -54,17 +66,17 @@ static int rmi_char_dev_major_num;
  *
  * @whence: SEEK_SET , SEEK_CUR or SEEK_END
  */
-static loff_t rmi_char_dev_llseek(struct file *filp, loff_t off, int whence)
+static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
 {
        loff_t newpos;
-       struct rmi_char_dev *my_char_dev = filp->private_data;
+       struct rmidev_data *data = filp->private_data;
 
-       if (IS_ERR(my_char_dev)) {
+       if (IS_ERR(data)) {
                pr_err("%s: pointer of char device is invalid", __func__);
                return -EBADF;
        }
 
-       mutex_lock(&(my_char_dev->mutex_file_op));
+       mutex_lock(&(data->file_mutex));
 
        switch (whence) {
        case SEEK_SET:
@@ -85,7 +97,7 @@ static loff_t rmi_char_dev_llseek(struct file *filp, loff_t off, int whence)
        }
 
        if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
-               dev_err(my_char_dev->phys->dev, "newpos 0x%04x is invalid.\n",
+               dev_err(&data->rmi_dev->dev, "newpos 0x%04x is invalid.\n",
                        (unsigned int)newpos);
                newpos = -EINVAL;
                goto clean_up;
@@ -94,12 +106,12 @@ static loff_t rmi_char_dev_llseek(struct file *filp, loff_t off, int whence)
        filp->f_pos = newpos;
 
 clean_up:
-       mutex_unlock(&(my_char_dev->mutex_file_op));
+       mutex_unlock(&(data->file_mutex));
        return newpos;
 }
 
 /*
- *  rmi_char_dev_read: - use to read data from RMI stream
+ *  rmidev_read: - use to read data from RMI stream
  *
  *  @filp: file structure for read
  *  @buf: user-level buffer pointer
@@ -110,13 +122,16 @@ clean_up:
  *     @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,
+static ssize_t rmidev_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;
+       struct rmidev_data *data = filp->private_data;
+       ssize_t retval  = 0;
+       u8 *tmpbuf;
+
+       tmpbuf = kcalloc(count+1, sizeof(u8), GFP_KERNEL);
+       if (!tmpbuf)
+               return -ENOMEM;
 
        /* limit offset to REG_ADDR_LIMIT-1 */
        if (count > (REG_ADDR_LIMIT - *f_pos))
@@ -125,39 +140,32 @@ static ssize_t rmi_char_dev_read(struct file *filp, char __user *buf,
        if (count == 0)
                return 0;
 
-       if (IS_ERR(my_char_dev)) {
+       if (IS_ERR(data)) {
                pr_err("%s: pointer of char device is invalid", __func__);
-               ret_value = -EBADF;
-               return ret_value;
+               return -EBADF;
        }
 
-       mutex_lock(&(my_char_dev->mutex_file_op));
+       mutex_lock(&(data->file_mutex));
 
-       phys = my_char_dev->phys;
-       /*
-        * just let it go through , because we do not know the register is FIFO
-        * register or not
-        */
+       retval = rmi_read_block(data->rmi_dev, *f_pos, tmpbuf, count);
 
-       ret_value = phys->read_block(phys, *f_pos, tmpbuf, count);
-
-       if (ret_value < 0)
+       if (retval < 0)
                goto clean_up;
-       else
-               *f_pos += ret_value;
 
        if (copy_to_user(buf, tmpbuf, count))
-               ret_value = -EFAULT;
+               retval = -EFAULT;
+       else
+               *f_pos += retval;
 
 clean_up:
 
-       mutex_unlock(&(my_char_dev->mutex_file_op));
-
-       return ret_value;
+       mutex_unlock(&(data->file_mutex));
+       kfree(tmpbuf);
+       return retval;
 }
 
 /*
- * rmi_char_dev_write: - use to write data into RMI stream
+ * rmidev_write: - use to write data into RMI stream
  *
  * @filep : file structure for write
  * @buf: user-level buffer pointer contains data to be written
@@ -167,13 +175,16 @@ clean_up:
  * @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,
+static ssize_t rmidev_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;
+       struct rmidev_data *data = filp->private_data;
+       ssize_t retval  = 0;
+       u8 *tmpbuf;
+
+       tmpbuf = kcalloc(count+1, sizeof(u8), GFP_KERNEL);
+       if (!tmpbuf)
+               return -ENOMEM;
 
        /* limit offset to REG_ADDR_LIMIT-1 */
        if (count > (REG_ADDR_LIMIT - *f_pos))
@@ -182,128 +193,113 @@ static ssize_t rmi_char_dev_write(struct file *filp, const char __user *buf,
        if (count == 0)
                return 0;
 
-       if (IS_ERR(my_char_dev)) {
+       if (IS_ERR(data)) {
                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;
+               return -EBADF;
        }
 
-       mutex_lock(&(my_char_dev->mutex_file_op));
+       if (copy_from_user(tmpbuf, buf, count))
+               return -EFAULT;
 
-       phys = my_char_dev->phys;
-       /*
-        * just let it go through , because we do not know the register is FIFO
-        * register or not
-        */
+       mutex_lock(&(data->file_mutex));
 
-       ret_value = phys->write_block(phys, *f_pos, tmpbuf, count);
+       retval = rmi_write_block(data->rmi_dev, *f_pos, tmpbuf, count);
 
-       if (ret_value >= 0)
+       if (retval >= 0)
                *f_pos += count;
 
-       mutex_unlock(&(my_char_dev->mutex_file_op));
-
-       return ret_value;
+       mutex_unlock(&(data->file_mutex));
+       kfree(tmpbuf);
+       return retval;
 }
 
 /*
- * rmi_char_dev_open: - get a new handle for from RMI stream
+ * rmidev_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)
+static int rmidev_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;
+       struct rmidev_data *data = container_of(inp->i_cdev,
+                       struct rmidev_data, main_dev);
+       int retval = 0;
 
-       filp->private_data = my_dev;
+       filp->private_data = data;
 
-       if (!phys)
+       if (!data->rmi_dev)
                return -EACCES;
 
-       mutex_lock(&(my_dev->mutex_file_op));
-       if (my_dev->ref_count < 1)
-               my_dev->ref_count++;
-       else
-               ret_value = -EACCES;
+       dev_dbg(&data->rmi_dev->dev, "%s.", __func__);
 
-       mutex_unlock(&(my_dev->mutex_file_op));
+       mutex_lock(&(data->file_mutex));
+       if (data->ref_count < 1)
+               data->ref_count++;
+       else
+               retval = -EACCES;
+       mutex_unlock(&(data->file_mutex));
 
-       return ret_value;
+       return retval;
 }
 
 /*
- *  rmi_char_dev_release: - release an existing handle
+ *  rmidev_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)
+static int rmidev_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;
+       struct rmidev_data *data = container_of(inp->i_cdev,
+                       struct rmidev_data, main_dev);
 
-       if (!phys)
+       if (!data->rmi_dev)
                return -EACCES;
 
-       mutex_lock(&(my_dev->mutex_file_op));
+       dev_dbg(&data->rmi_dev->dev, "%s.", __func__);
 
-       my_dev->ref_count--;
-       if (my_dev->ref_count < 0)
-               my_dev->ref_count = 0;
-
-       mutex_unlock(&(my_dev->mutex_file_op));
+       mutex_lock(&(data->file_mutex));
+       data->ref_count--;
+       if (data->ref_count < 0)
+               data->ref_count = 0;
+       mutex_unlock(&(data->file_mutex));
 
        return 0;
 }
 
-static const struct file_operations rmi_char_dev_fops = {
+static const struct file_operations rmidev_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,
+       .llseek =   rmidev_llseek,
+       .read =     rmidev_read,
+       .write =    rmidev_write,
+       .open =     rmidev_open,
+       .release =  rmidev_release,
 };
 
 /*
- * rmi_char_dev_clean_up - release memory or unregister driver
- * @rmi_char_dev: rmi_char_dev structure
+ * rmidev_device_cleanup - release memory or unregister driver
+ * @rmidev_data: instance data for a particular device.
  *
  */
-static void rmi_char_dev_clean_up(struct rmi_char_dev *char_dev,
-                       struct class *char_device_class)
+static void rmidev_device_cleanup(struct rmidev_data *data)
 {
        dev_t devno;
 
        /* Get rid of our char dev entries */
-       if (char_dev) {
-               devno = char_dev->main_dev.dev;
+       if (data) {
+               devno = data->main_dev.dev;
 
-               cdev_del(&char_dev->main_dev);
-               kfree(char_dev);
+               if (data->device_class)
+                       device_destroy(data->device_class, devno);
 
-               if (char_device_class) {
-                       device_destroy(char_device_class, devno);
-                       class_unregister(char_device_class);
-                       class_destroy(char_device_class);
-               }
+               cdev_del(&data->main_dev);
+               kfree(data);
 
                /* cleanup_module is never called if registering failed */
                unregister_chrdev_region(devno, 1);
-               pr_debug("%s: rmi_char_dev is removed\n", __func__);
+               pr_debug("%s: rmidev device is removed\n", __func__);
        }
 }
 
@@ -318,111 +314,139 @@ 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)
+static int rmidev_attach(struct device *dev, void *data)
 {
-       struct rmi_char_dev *char_dev;
+       int retval = 0;
+       struct rmi_device *rmi_dev;
+       struct rmidev_data *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);
+       if (dev->type != &rmi_sensor_type)
+               return 0;
+       dev_dbg(dev, "%s is interested.\n", __func__);
+       rmi_dev = to_rmi_device(dev);
+
+       if (rmidev_major_num) {
+               dev_no = MKDEV(rmidev_major_num, rmi_dev->number);
+               retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
        } else {
-               result = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
+               retval = 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);
+               rmidev_major_num = MAJOR(dev_no);
+               dev_dbg(dev, "Major number of rmidev: %d\n",
+                                rmidev_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);
+       if (retval < 0) {
+               dev_err(dev, "Failed to get minor dev number %d, code %d.\n",
+                       rmi_dev->number, retval);
+               return retval;
+       } else
+               dev_dbg(dev, "Allocated rmidev %d %d.\n",
+                        MAJOR(dev_no), MINOR(dev_no));
+
+       char_dev = devm_kzalloc(dev, sizeof(struct rmidev_data), GFP_KERNEL);
+       if (!char_dev)
                return -ENOMEM;
+       char_dev->rmi_dev = rmi_dev;
+       mutex_init(&char_dev->file_mutex);
+
+       cdev_init(&char_dev->main_dev, &rmidev_fops);
+
+       retval = cdev_add(&char_dev->main_dev, dev_no, 1);
+       if (retval) {
+               dev_err(dev, "Error %d adding rmi_char_dev.\n", retval);
+               rmidev_device_cleanup(char_dev);
+               goto error_exit;
        }
 
-       mutex_init(&char_dev->mutex_file_op);
+       char_dev->device_class = rmidev_class;
+       device_ptr = device_create(char_dev->device_class, NULL, dev_no, NULL,
+                       CHAR_DEVICE_NAME"%d", MINOR(dev_no));
 
-       phys->char_dev = char_dev;
-       char_dev->phys = phys;
+       if (IS_ERR(device_ptr)) {
+               dev_err(dev, "Failed to create rmi device.\n");
+               rmidev_device_cleanup(char_dev);
+               retval = -ENODEV;
+               goto error_exit;
+       }
 
-       cdev_init(&char_dev->main_dev, &rmi_char_dev_fops);
+       return 0;
+
+error_exit:
+       devm_kfree(dev, char_dev);
+       return retval;
+}
+
+static int rmidev_notifier_call(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       struct device *dev = data;
 
-       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;
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               dev_dbg(dev, "%s: added device.\n", __func__);
+               break;
+       case BUS_NOTIFY_DEL_DEVICE:
+               dev_dbg(dev, "%s: removed device.\n", __func__);
+               break;
+       default:
+               dev_dbg(dev, "%s: unknown action %lu.\n", __func__, action);
+               break;
        }
+       return 0;
+}
+
+static struct notifier_block rmi_bus_notifier = {
+       .notifier_call = rmidev_notifier_call,
+};
+
+static int __init rmidev_init(void)
+{
+       int error = 0;
+       pr_debug("%s: rmi_dev initialization.\n", __func__);
 
        /* create device node */
-       phys->rmi_char_device_class =
-               class_create(THIS_MODULE, CHAR_DEVICE_NAME);
+       rmidev_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
 
-       if (IS_ERR(phys->rmi_char_device_class)) {
-               dev_err(phys->dev, "Failed to create /dev/%s.\n",
+       if (IS_ERR(rmidev_class)) {
+               pr_err("%s: ERROR - Failed to create /dev/%s.\n", __func__,
                        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;
+       rmidev_class->devnode = rmi_char_devnode;
+
+       /* Ask the bus to let us know when new devices appear. */
+       error = bus_register_notifier(&rmi_bus_type, &rmi_bus_notifier);
+       if (error) {
+               pr_err("%s: failed to register bus notifier, code=%d.\n",
+                      __func__, error);
+               return error;
        }
 
-       return 0;
-}
-EXPORT_SYMBOL(rmi_char_dev_register);
+       /* Bind to any previously existing sensors. */
+       rmi_for_each_dev(NULL, rmidev_attach);
 
-/* rmi_char_dev_unregister - unregister char device (called from up-level)
- *
- * @phys: pointer to an rmi_phys_device structure
- */
+       return error;
+}
 
-void rmi_char_dev_unregister(struct rmi_phys_device *phys)
+static void __exit rmidev_exit(void)
 {
-       /* clean up */
-       if (phys)
-               rmi_char_dev_clean_up(phys->char_dev,
-                                phys->rmi_char_device_class);
+       pr_debug("%s: exiting.\n", __func__);
+       bus_unregister_notifier(&rmi_bus_type, &rmi_bus_notifier);
+       class_destroy(rmidev_class);
 }
-EXPORT_SYMBOL(rmi_char_dev_unregister);
 
-MODULE_AUTHOR("Synaptics, Inc.");
+module_init(rmidev_init);
+module_exit(rmidev_exit);
+
+MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
 MODULE_DESCRIPTION("RMI4 Char Device");
 MODULE_LICENSE("GPL");
index f59c1f4..a5a1ae9 100644 (file)
 /*
- * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011, 2012 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.
+ * This driver provides the core support for a single RMI4-based device.
  *
  * 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.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/device.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/kconfig.h>
 #include <linux/list.h>
+#include <linux/module.h>
 #include <linux/pm.h>
-#include <linux/gpio.h>
-#include <linux/workqueue.h>
 #include <linux/rmi.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
 #include "rmi_driver.h"
+#include "rmi_f01.h"
 
-#define DELAY_DEBUG 0
-#define REGISTER_DEBUG 0
+#define CONFIG_RMI4_DEBUG 1
 
-#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
+#define DEFAULT_RESET_DELAY_MS 100
 
-/* sysfs files for attributes for driver values. */
-static ssize_t rmi_driver_hasbsr_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf);
+#define DEFAULT_POLL_INTERVAL_MS       13
 
-static ssize_t rmi_driver_bsr_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf);
+#define IRQ_DEBUG(data) (IS_ENABLED(CONFIG_RMI4_DEBUG) && data->irq_debug)
 
-static ssize_t rmi_driver_bsr_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count);
+#ifdef CONFIG_RMI4_DEBUG
+struct driver_debugfs_data {
+       bool done;
+       struct rmi_device *rmi_dev;
+};
 
-static ssize_t rmi_driver_enabled_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf);
+static int debug_open(struct inode *inodep, struct file *filp)
+{
+       struct driver_debugfs_data *data;
+       struct rmi_device *rmi_dev;
 
-static ssize_t rmi_driver_enabled_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count);
+       rmi_dev = inodep->i_private;
+       data = kzalloc(sizeof(struct driver_debugfs_data),
+                               GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->rmi_dev = inodep->i_private;
+       filp->private_data = data;
+       return 0;
+}
 
-static ssize_t rmi_driver_phys_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf);
+static int debug_release(struct inode *inodep, struct file *filp)
+{
+       kfree(filp->private_data);
+       return 0;
+}
 
-static ssize_t rmi_driver_version_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf);
+static ssize_t delay_read(struct file *filp, char __user *buffer, size_t size,
+                   loff_t *offset) {
+       struct driver_debugfs_data *data = filp->private_data;
+       struct rmi_device_platform_data *pdata =
+                       data->rmi_dev->phys->dev->platform_data;
+       int retval;
+       char *local_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 (data->done)
+               return 0;
 
-#if DELAY_DEBUG
-static ssize_t rmi_delay_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf);
+       data->done = 1;
 
-static ssize_t rmi_delay_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count);
-#endif
+       local_buf = kcalloc(size, sizeof(u8), GFP_KERNEL);
+       if (!local_buf)
+               return -ENOMEM;
 
-static struct device_attribute attrs[] = {
-       __ATTR(hasbsr, RMI_RO_ATTR,
-              rmi_driver_hasbsr_show, rmi_store_error),
-       __ATTR(bsr, RMI_RO_ATTR,
-              rmi_driver_bsr_show, rmi_driver_bsr_store),
-       __ATTR(enabled, RMI_RO_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),
+       retval = snprintf(local_buf, 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);
+
+       if (retval <= 0 || copy_to_user(buffer, local_buf, retval))
+               retval = -EFAULT;
+       kfree(local_buf);
+
+       return retval;
+}
+
+static ssize_t delay_write(struct file *filp, const char __user *buffer,
+                          size_t size, loff_t *offset) {
+       struct driver_debugfs_data *data = filp->private_data;
+       struct rmi_device_platform_data *pdata =
+                       data->rmi_dev->phys->dev->platform_data;
+       int retval;
+       char *local_buf;
+       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;
+
+       local_buf = kcalloc(size, sizeof(u8), GFP_KERNEL);
+       if (!local_buf)
+               return -ENOMEM;
+
+       retval = copy_from_user(local_buf, buffer, size);
+       if (retval) {
+               kfree(local_buf);
+               return -EFAULT;
+       }
+
+       retval = sscanf(local_buf, "%u %u %u %u %u", &new_read_delay,
+                       &new_write_delay, &new_block_delay,
+                       &new_pre_delay, &new_post_delay);
+       kfree(local_buf);
+
+       if (retval != 5) {
+               dev_err(&data->rmi_dev->dev,
+                       "Incorrect number of values provided for delay.");
+               return -EINVAL;
+       }
+       dev_dbg(&data->rmi_dev->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 size;
+}
+
+static const struct file_operations delay_fops = {
+       .owner = THIS_MODULE,
+       .open = debug_open,
+       .release = debug_release,
+       .read = delay_read,
+       .write = delay_write,
 };
 
+#define PHYS_NAME "phys"
 
-/*
-** ONLY needed for POLLING mode of the driver
-*/
-struct rmi_device *polled_synaptics_rmi_device = NULL;
-EXPORT_SYMBOL(polled_synaptics_rmi_device);
+static ssize_t phys_read(struct file *filp, char __user *buffer, size_t size,
+                   loff_t *offset) {
+       struct driver_debugfs_data *data = filp->private_data;
+       struct rmi_phys_info *info = &data->rmi_dev->phys->info;
+       int retval;
+       char *local_buf;
 
-/* Useful helper functions for u8* */
+       if (data->done)
+               return 0;
 
-void u8_set_bit(u8 *target, int pos)
-{
-       target[pos/8] |= 1<<pos%8;
+       local_buf = kcalloc(size, sizeof(u8), GFP_KERNEL);
+       if (!local_buf)
+               return -ENOMEM;
+
+       data->done = 1;
+
+       retval = snprintf(local_buf, size,
+               "%-5s %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);
+       if (retval <= 0 || copy_to_user(buffer, local_buf, retval))
+               retval = -EFAULT;
+       kfree(local_buf);
+
+       return retval;
+}
+
+static const struct file_operations phys_fops = {
+       .owner = THIS_MODULE,
+       .open = debug_open,
+       .release = debug_release,
+       .read = phys_read,
+};
+
+static ssize_t attn_count_read(struct file *filp, char __user *buffer,
+               size_t size, loff_t *offset) {
+       struct driver_debugfs_data *data = filp->private_data;
+       struct rmi_driver_data *rmi_data = dev_get_drvdata(&data->rmi_dev->dev);
+       int retval;
+       char *local_buf;
+
+       if (data->done)
+               return 0;
+
+       local_buf = kcalloc(size, sizeof(u8), GFP_KERNEL);
+       if (!local_buf)
+               return -ENOMEM;
+
+       data->done = 1;
+
+       retval = snprintf(local_buf, size, "%d\n",
+                         rmi_data->attn_count.counter);
+       if (retval <= 0 || copy_to_user(buffer, local_buf, retval))
+               retval = -EFAULT;
+       kfree(local_buf);
+
+       return retval;
 }
 
-void u8_clear_bit(u8 *target, int pos)
+static const struct file_operations attn_count_fops = {
+       .owner = THIS_MODULE,
+       .open = debug_open,
+       .release = debug_release,
+       .read = attn_count_read,
+};
+
+static int setup_debugfs(struct rmi_device *rmi_dev)
 {
-       target[pos/8] &= ~(1<<pos%8);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi_phys_info *info = &rmi_dev->phys->info;
+       int retval = 0;
+
+       if (!rmi_dev->debugfs_root)
+               return -ENODEV;
+
+       if (IS_ENABLED(CONFIG_RMI4_SPI) && !strncmp("spi", info->proto, 3)) {
+               data->debugfs_delay = debugfs_create_file("delay",
+                               RMI_RW_ATTR, rmi_dev->debugfs_root, rmi_dev,
+                               &delay_fops);
+               if (!data->debugfs_delay || IS_ERR(data->debugfs_delay)) {
+                       dev_warn(&rmi_dev->dev, "Failed to create debugfs delay.\n");
+                       data->debugfs_delay = NULL;
+       }
+       }
+
+       data->debugfs_phys = debugfs_create_file(PHYS_NAME, RMI_RO_ATTR,
+                               rmi_dev->debugfs_root, rmi_dev, &phys_fops);
+       if (!data->debugfs_phys || IS_ERR(data->debugfs_phys)) {
+               dev_warn(&rmi_dev->dev, "Failed to create debugfs phys.\n");
+               data->debugfs_phys = NULL;
+       }
+
+       data->debugfs_irq = debugfs_create_bool("irq_debug",
+                       RMI_RW_ATTR, rmi_dev->debugfs_root, &data->irq_debug);
+       if (!data->debugfs_irq || IS_ERR(data->debugfs_irq)) {
+               dev_warn(&rmi_dev->dev, "Failed to create debugfs irq_debug.\n");
+               data->debugfs_irq = NULL;
+       }
+
+       data->debugfs_attn_count = debugfs_create_file("attn_count",
+                               RMI_RO_ATTR,
+                               rmi_dev->debugfs_root,
+                               rmi_dev, &attn_count_fops);
+       if (!data->debugfs_phys || IS_ERR(data->debugfs_attn_count)) {
+               dev_warn(&rmi_dev->dev, "Failed to create debugfs attn_count.\n");
+               data->debugfs_attn_count = NULL;
+       }
+
+       return retval;
 }
 
-bool u8_is_set(u8 *target, int pos)
+static void teardown_debugfs(struct rmi_device *rmi_dev)
 {
-       return target[pos/8] & 1<<pos%8;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
+       if (IS_ENABLED(CONFIG_RMI4_SPI) && data->debugfs_delay)
+               debugfs_remove(data->debugfs_delay);
+       if (data->debugfs_phys)
+               debugfs_remove(data->debugfs_phys);
+       if (data->debugfs_irq)
+               debugfs_remove(data->debugfs_irq);
+       if (data->debugfs_attn_count)
+               debugfs_remove(data->debugfs_attn_count);
 }
+#else
+#define teardown_debugfs(rmi_dev)
+#define setup_debugfs(rmi_dev) 0
+#endif
 
-bool u8_is_any_set(u8 *target, int size)
+static irqreturn_t rmi_irq_thread(int irq, void *p)
 {
-       int i;
-       for (i = 0; i < size; i++) {
-               if (target[i])
-                       return true;
+       struct rmi_phys_device *phys = p;
+       struct rmi_device *rmi_dev = phys->rmi_dev;
+       struct rmi_driver *driver = rmi_dev->driver;
+       struct rmi_device_platform_data *pdata = phys->dev->platform_data;
+       struct rmi_driver_data *data;
+
+       data = dev_get_drvdata(&rmi_dev->dev);
+
+       if IRQ_DEBUG(data)
+               dev_dbg(phys->dev, "ATTN gpio, value: %d.\n",
+                               gpio_get_value(pdata->attn_gpio));
+
+       if (gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity) {
+               atomic_inc(&data->attn_count);
+               if (driver && driver->irq_handler && rmi_dev)
+                       driver->irq_handler(rmi_dev, irq);
        }
-       return false;
+
+       return IRQ_HANDLED;
 }
 
-void u8_or(u8 *dest, u8 *target1, u8 *target2, int size)
+static int process_interrupt_requests(struct rmi_device *rmi_dev);
+
+static void rmi_poll_work(struct work_struct *work)
 {
-       int i;
-       for (i = 0; i < size; i++)
-               dest[i] = target1[i] | target2[i];
+       struct rmi_driver_data *data =
+                       container_of(work, struct rmi_driver_data, poll_work);
+       struct rmi_device *rmi_dev = data->rmi_dev;
+
+       process_interrupt_requests(rmi_dev);
 }
 
-void u8_and(u8 *dest, u8 *target1, u8 *target2, int size)
+/* This is the timer function for polling - it simply has to schedule work
+ * and restart the timer. */
+static enum hrtimer_restart rmi_poll_timer(struct hrtimer *timer)
 {
-       int i;
-       for (i = 0; i < size; i++)
-               dest[i] = target1[i] & target2[i];
+       struct rmi_driver_data *data =
+                       container_of(timer, struct rmi_driver_data, poll_timer);
+
+       if (!data->enabled)
+               return HRTIMER_NORESTART;
+       if (!work_pending(&data->poll_work))
+               schedule_work(&data->poll_work);
+       hrtimer_start(&data->poll_timer, data->poll_interval, HRTIMER_MODE_REL);
+       return HRTIMER_NORESTART;
 }
 
-/* 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)
+static int enable_polling(struct rmi_device *rmi_dev)
 {
-       *dest = src[1] * 0x100 + src[0];
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
+       dev_dbg(&rmi_dev->dev, "Polling enabled.\n");
+       INIT_WORK(&data->poll_work, rmi_poll_work);
+       hrtimer_init(&data->poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       data->poll_timer.function = rmi_poll_timer;
+       hrtimer_start(&data->poll_timer, data->poll_interval, HRTIMER_MODE_REL);
+
+       return 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)
+static void disable_polling(struct rmi_device *rmi_dev)
 {
-       dest[0] = src % 0x100;
-       dest[1] = src / 0x100;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
+       dev_dbg(&rmi_dev->dev, "Polling disabled.\n");
+       hrtimer_cancel(&data->poll_timer);
+       cancel_work_sync(&data->poll_work);
 }
 
-static bool has_bsr(struct rmi_driver_data *data)
+static void disable_sensor(struct rmi_device *rmi_dev)
 {
-       return (data->pdt_props & HAS_BSR_MASK) != 0;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
+       if (!data->enabled)
+               return;
+
+       if (!data->irq)
+               disable_polling(rmi_dev);
+
+       if (rmi_dev->phys->disable_device)
+               rmi_dev->phys->disable_device(rmi_dev->phys);
+
+       if (data->irq) {
+               disable_irq(data->irq);
+               free_irq(data->irq, rmi_dev->phys);
+       }
+
+       data->enabled = false;
 }
 
-/* Utility routine to set bits in a register. */
-int rmi_set_bits(struct rmi_device *rmi_dev, unsigned short address,
-                unsigned char bits)
+static int enable_sensor(struct rmi_device *rmi_dev)
 {
-       unsigned char reg_contents;
-       int retval;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi_phys_device *rmi_phys;
+       int retval = 0;
+       struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
 
-       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)
+       if (data->enabled)
                return 0;
-       else if (retval == 0)
-               return -EIO;
+
+       if (rmi_dev->phys->enable_device) {
+               retval = rmi_dev->phys->enable_device(rmi_dev->phys);
+               if (retval)
+                       return retval;
+               }
+
+       rmi_phys = rmi_dev->phys;
+       if (data->irq) {
+               retval = request_threaded_irq(data->irq,
+                               rmi_phys->hard_irq ? rmi_phys->hard_irq : NULL,
+                               rmi_phys->irq_thread ?
+                                       rmi_phys->irq_thread : rmi_irq_thread,
+                               data->irq_flags,
+                               dev_name(&rmi_dev->dev), rmi_phys);
+               if (retval)
+                       return retval;
+       } else {
+               retval = enable_polling(rmi_dev);
+               if (retval < 0)
+                       return retval;
+       }
+
+       data->enabled = true;
+
+       if (!pdata->level_triggered &&
+                   gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity)
+               retval = process_interrupt_requests(rmi_dev);
+
        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)
+/* sysfs show and store fns for driver attributes */
+
+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 = dev_get_drvdata(&rmi_dev->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)
 {
-       unsigned char reg_contents;
        int retval;
+       unsigned long val;
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
 
-       retval = rmi_read_block(rmi_dev, address, &reg_contents, 1);
-       if (retval)
+       rmi_dev = to_rmi_device(dev);
+       data = dev_get_drvdata(&rmi_dev->dev);
+
+       /* need to convert the string data to an actual value */
+       retval = strict_strtoul(buf, 10, &val);
+       if (retval < 0 || val > 255) {
+               dev_err(dev, "Invalid value '%s' written to BSR.\n", buf);
+               return -EINVAL;
+       }
+
+       retval = rmi_write(rmi_dev, BSR_LOCATION, (u8)val);
+       if (retval < 0) {
+               dev_err(dev, "%s : failed to write bsr %lu to %#06x\n",
+                       __func__, val, BSR_LOCATION);
                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;
+       }
+
+       data->bsr = val;
+
+       return count;
 }
-EXPORT_SYMBOL(rmi_clear_bits);
 
-static void rmi_free_function_list(struct rmi_device *rmi_dev)
+static ssize_t rmi_driver_enabled_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
-       struct rmi_function_container *entry, *n;
-       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct rmi_device *rmi_dev;
+       struct rmi_driver_data *data;
 
-       list_for_each_entry_safe(entry, n, &data->rmi_functions.list, list) {
-               kfree(entry->irq_mask);
-               list_del(&entry->list);
-       }
+       rmi_dev = to_rmi_device(dev);
+       data = dev_get_drvdata(&rmi_dev->dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", data->enabled);
 }
 
-static int init_one_function(struct rmi_device *rmi_dev,
-                            struct rmi_function_container *fc)
+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 = dev_get_drvdata(&rmi_dev->dev);
+
+       if (sysfs_streq(buf, "0"))
+               new_value = false;
+       else if (sysfs_streq(buf, "1"))
+               new_value = true;
+       else
+               return -EINVAL;
 
-       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;
+       if (new_value) {
+               retval = enable_sensor(rmi_dev);
+               if (retval) {
+                       dev_err(dev, "Failed to enable sensor, code=%d.\n",
+                               retval);
+                       return -EIO;
                }
-               fc->fh = fh;
+       } else {
+               disable_sensor(rmi_dev);
        }
 
-       if (!fc->fh->init)
-               return 0;
+       return count;
+}
 
-       dev_set_name(&(fc->dev), "fn%02x", fc->fd.function_number);
+/** This sysfs attribute is deprecated, and will be removed in a future release.
+ */
+static struct device_attribute attrs[] = {
+       __ATTR(enabled, RMI_RW_ATTR,
+              rmi_driver_enabled_show, rmi_driver_enabled_store),
+};
 
-       fc->dev.parent = &rmi_dev->dev;
+static struct device_attribute bsr_attribute = __ATTR(bsr, RMI_RW_ATTR,
+              rmi_driver_bsr_show, rmi_driver_bsr_store);
 
-       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;
+static void rmi_free_function_list(struct rmi_device *rmi_dev)
+{
+       struct rmi_function_dev *entry, *n;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
+       if (!data) {
+               dev_err(&rmi_dev->dev, "WTF: No driver data in %s\n", __func__);
+               return;
        }
 
-       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;
+       data->f01_dev = NULL;
+
+       if (list_empty(&data->rmi_functions.list))
+               return;
+
+       list_for_each_entry_safe(entry, n, &data->rmi_functions.list, list) {
+               device_unregister(&entry->dev);
+               list_del(&entry->list);
        }
+}
 
-       return 0;
+static void release_fndev_device(struct device *dev)
+{
+       kobject_put(&dev->kobj);
+}
+
+static int reset_one_function(struct rmi_function_dev *fn_dev)
+{
+       struct rmi_function_driver *fn_drv;
+       int retval = 0;
+
+       if (!fn_dev || !fn_dev->dev.driver)
+               return 0;
+
+       fn_drv = to_rmi_function_driver(fn_dev->dev.driver);
+       if (fn_drv->reset) {
+               retval = fn_drv->reset(fn_dev);
+               if (retval < 0)
+                       dev_err(&fn_dev->dev, "Reset failed with code %d.\n",
+                               retval);
+       }
 
-error_exit:
-       device_unregister(&fc->dev);
        return retval;
 }
 
-static void rmi_driver_fh_add(struct rmi_device *rmi_dev,
-                             struct rmi_function_handler *fh)
+static int configure_one_function(struct rmi_function_dev *fn_dev)
 {
-       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);
-                       }
+       struct rmi_function_driver *fn_drv;
+       int retval = 0;
+
+       if (!fn_dev || !fn_dev->dev.driver)
+               return 0;
+
+       fn_drv = to_rmi_function_driver(fn_dev->dev.driver);
+       if (fn_drv->config) {
+               retval = fn_drv->config(fn_dev);
+               if (retval < 0)
+                       dev_err(&fn_dev->dev, "Config failed with code %d.\n",
+                               retval);
        }
 
+       return retval;
 }
 
-static void rmi_driver_fh_remove(struct rmi_device *rmi_dev,
-                                struct rmi_function_handler *fh)
+static int rmi_driver_process_reset_requests(struct rmi_device *rmi_dev)
 {
-       struct rmi_function_container *entry;
-       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi_function_dev *entry;
+       int retval;
 
-       list_for_each_entry(entry, &data->rmi_functions.list, list)
-               if (entry->fd.function_number == fh->func) {
-                       if (fh->remove)
-                               fh->remove(entry);
+       if (list_empty(&data->rmi_functions.list))
+               return 0;
 
-                       entry->fh = NULL;
-               }
+       list_for_each_entry(entry, &data->rmi_functions.list, list) {
+               retval = reset_one_function(entry);
+               if (retval < 0)
+                       return retval;
+       }
+
+       return 0;
 }
 
-static void construct_mask(u8 *mask, int num, int pos)
+static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev)
 {
-       int i;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi_function_dev *entry;
+       int retval;
+
+       if (list_empty(&data->rmi_functions.list))
+               return 0;
+
+       list_for_each_entry(entry, &data->rmi_functions.list, list) {
+               retval = configure_one_function(entry);
+               if (retval < 0)
+                       return retval;
+       }
 
-       for (i = 0; i < num; i++)
-               u8_set_bit(mask, pos+i);
+       return 0;
+}
+
+static void process_one_interrupt(struct rmi_function_dev *fn_dev,
+               unsigned long *irq_status, struct rmi_driver_data *data)
+{
+       struct rmi_function_driver *fn_drv;
+       DECLARE_BITMAP(irq_bits, data->num_of_irq_regs);
+
+       if (!fn_dev || !fn_dev->dev.driver)
+               return;
+
+       fn_drv = to_rmi_function_driver(fn_dev->dev.driver);
+       if (fn_dev->irq_mask && fn_drv->attention) {
+               bitmap_and(irq_bits, irq_status, fn_dev->irq_mask,
+                               data->irq_count);
+               if (!bitmap_empty(irq_bits, data->irq_count))
+                       fn_drv->attention(fn_dev, irq_bits);
+       }
 }
 
 static int process_interrupt_requests(struct rmi_device *rmi_dev)
 {
-       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->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];
+       struct rmi_function_dev *entry;
        int error;
 
        error = rmi_read_block(rmi_dev,
-                               data->f01_container->fd.data_base_addr + 1,
-                               irq_status, data->num_of_irq_regs);
+                               data->f01_dev->fd.data_base_addr + 1,
+                               data->irq_status, data->num_of_irq_regs);
        if (error < 0) {
-               dev_err(dev, "%s: failed to read irqs.", __func__);
+               dev_err(dev, "Failed to read irqs, code=%d\n", error);
                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);
 
+       mutex_lock(&data->irq_mutex);
+       bitmap_and(data->irq_status, data->irq_status, data->current_irq_mask,
+              data->irq_count);
        /* At this point, irq_status has all bits that are set in the
         * interrupt status register and are enabled.
         */
+       mutex_unlock(&data->irq_mutex);
 
-       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.
+       /* It would be nice to be able to use irq_chip to handle these
+        * nested IRQs.  Unfortunately, most of the current customers for
+        * this driver are using older kernels (3.0.x) that don't support
+        * the features required for that.  Once they've shifted to more
+        * recent kernels (say, 3.3 and higher), this should be switched to
+        * use irq_chip.
         */
-       if (!data || !data->f01_container || !data->f01_container->fh) {
-               dev_warn(&rmi_dev->dev,
-                        "Not ready to handle interrupts yet!\n");
-               return 0;
+       list_for_each_entry(entry, &data->rmi_functions.list, list) {
+               if (entry->irq_mask)
+                       process_one_interrupt(entry, data->irq_status, data);
        }
 
-       return process_interrupt_requests(rmi_dev);
+       return 0;
 }
 
-/*
- * Construct a function's IRQ mask. This should
- * be called once and stored.
+/**
+ * rmi_driver_set_input_params - set input device id and other data.
+ *
+ * @rmi_dev: Pointer to an RMI device
+ * @input: Pointer to input device
+ *
  */
-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);
+static int rmi_driver_set_input_params(struct rmi_device *rmi_dev,
+                               struct input_dev *input)
+{
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
 
-       return irq_mask;
+       input->name = SYNAPTICS_INPUT_DEVICE_NAME;
+       input->id.vendor  = SYNAPTICS_VENDOR_ID;
+       input->id.product = data->board;
+       input->id.version = data->rev;
+       input->id.bustype = BUS_RMI;
+       return 0;
 }
 
-/*
+/**
  * 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.
+ * other interrupts 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)
+static int rmi_driver_irq_save(struct rmi_device *rmi_dev,
+                               unsigned long *new_ints)
 {
        int retval = 0;
-       struct rmi_driver_data *data = rmi_get_driverdata(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
        struct device *dev = &rmi_dev->dev;
 
        mutex_lock(&data->irq_mutex);
        if (!data->irq_stored) {
-               /* Save current enabled interupts */
+               /* Save current enabled interrupts */
                retval = rmi_read_block(rmi_dev,
-                               data->f01_container->fd.control_base_addr+1,
+                               data->f01_dev->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!",
@@ -441,26 +719,24 @@ static int rmi_driver_irq_save(struct rmi_device *rmi_dev, u8 * new_ints)
                        goto error_unlock;
                }
                /*
-                * Disable every interupt except for function 54
+                * Disable every interrupt 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,
+                               data->f01_dev->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));
+               bitmap_copy(data->current_irq_mask, new_ints, data->irq_count);
                data->irq_stored = true;
        } else {
                retval = -ENOSPC; /* No space to store IRQs.*/
-               dev_err(dev, "%s: Attempted to save values when"
-                                               " already stored!", __func__);
+               dev_err(dev, "Attempted to save IRQs when already stored!");
        }
 
 error_unlock:
@@ -471,13 +747,14 @@ error_unlock:
 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 rmi_driver_data *data = dev_get_drvdata(&rmi_dev->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->f01_dev->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!",
@@ -498,95 +775,299 @@ error_unlock:
        return retval;
 }
 
-static int rmi_driver_fn_01_specific(struct rmi_device *rmi_dev,
+static int rmi_driver_irq_handler(struct rmi_device *rmi_dev, int irq)
+{
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
+       might_sleep();
+       /* Can get called before the driver is fully ready to deal with
+        * interrupts.
+        */
+       if (!data || !data->f01_dev) {
+               dev_dbg(&rmi_dev->dev,
+                        "Not ready to handle interrupts yet!\n");
+               return 0;
+       }
+
+       return process_interrupt_requests(rmi_dev);
+}
+
+static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       int error;
+
+       /* Can get called before the driver is fully ready to deal with
+        * this situation.
+        */
+       if (!data || !data->f01_dev) {
+               dev_warn(&rmi_dev->dev,
+                        "Not ready to handle reset yet!\n");
+               return 0;
+       }
+
+       error = rmi_driver_process_reset_requests(rmi_dev);
+       if (error < 0)
+               return error;
+
+
+       error = rmi_driver_process_config_requests(rmi_dev);
+       if (error < 0)
+               return error;
+
+       if (data->irq_stored) {
+               error = rmi_driver_irq_restore(rmi_dev);
+               if (error < 0)
+                       return error;
+       }
+
+       return 0;
+}
+
+/*
+ * Construct a function's IRQ mask. This should be called once and stored.
+ */
+int rmi_driver_irq_get_mask(struct rmi_device *rmi_dev,
+               struct rmi_function_dev *fn_dev) {
+       int i;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
+       /* call devm_kcalloc when it will be defined in kernel in future */
+       fn_dev->irq_mask = devm_kzalloc(&rmi_dev->dev,
+                       BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
+                       GFP_KERNEL);
+
+       if (!fn_dev->irq_mask)
+               return -ENOMEM;
+
+       for (i = 0; i < fn_dev->num_of_irqs; i++)
+               set_bit(fn_dev->irq_pos+i, fn_dev->irq_mask);
+       return 0;
+}
+
+static int init_function_device(struct rmi_device *rmi_dev,
+                            struct rmi_function_dev *fn_dev)
+{
+       int retval;
+
+       /* This memset might not be what we want to do... */
+       memset(&(fn_dev->dev), 0, sizeof(struct device));
+       dev_set_name(&(fn_dev->dev), "%s.fn%02x", dev_name(&rmi_dev->dev),
+                       fn_dev->fd.function_number);
+       fn_dev->dev.release = release_fndev_device;
+
+       fn_dev->dev.parent = &rmi_dev->dev;
+       fn_dev->dev.type = &rmi_function_type;
+       fn_dev->dev.bus = &rmi_bus_type;
+
+       if (IS_ENABLED(CONFIG_RMI4_DEBUG)) {
+               char dirname[12];
+
+               snprintf(dirname, 12, "F%02X", fn_dev->fd.function_number);
+               fn_dev->debugfs_root = debugfs_create_dir(dirname,
+                                                     rmi_dev->debugfs_root);
+               if (!fn_dev->debugfs_root)
+                       dev_warn(&fn_dev->dev, "Failed to create debugfs dir.\n");
+       }
+
+       dev_dbg(&rmi_dev->dev, "Register F%02X.\n", fn_dev->fd.function_number);
+       retval = device_register(&fn_dev->dev);
+       if (retval) {
+               dev_err(&rmi_dev->dev, "Failed device_register for F%02X.\n",
+                       fn_dev->fd.function_number);
+               return retval;
+       }
+
+       return 0;
+}
+
+static int create_function_dev(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;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi_function_dev *fn_dev = NULL;
        int retval = 0;
        struct device *dev = &rmi_dev->dev;
-       struct rmi_function_handler *fh =
-               rmi_get_function_handler(0x01);
+       struct rmi_device_platform_data *pdata;
 
-       data = rmi_get_driverdata(rmi_dev);
+       pdata = to_rmi_platform_data(rmi_dev);
 
-       dev_info(dev, "%s: Found F01, initializing.\n", __func__);
-       if (!fh)
-               dev_dbg(dev, "%s: No function handler for F01?!", __func__);
+       dev_dbg(dev, "Initializing F%02X for %s.\n", pdt_ptr->function_number,
+               pdata->sensor_name);
 
-       fc = kzalloc(sizeof(struct rmi_function_container), GFP_KERNEL);
-       if (!fc) {
-               retval = -ENOMEM;
+       fn_dev = devm_kzalloc(dev, sizeof(struct rmi_function_dev),
+                       GFP_KERNEL);
+       if (!fn_dev) {
+               dev_err(dev, "Failed to allocate F%02X device.\n",
+                       pdt_ptr->function_number);
+               return -ENOMEM;
+       }
+
+       copy_pdt_entry_to_fd(pdt_ptr, &fn_dev->fd, page_start);
+
+       fn_dev->rmi_dev = rmi_dev;
+       fn_dev->num_of_irqs = pdt_ptr->interrupt_source_count;
+       fn_dev->irq_pos = *current_irq_count;
+       *current_irq_count += fn_dev->num_of_irqs;
+
+       retval = rmi_driver_irq_get_mask(rmi_dev, fn_dev);
+       if (retval < 0) {
+               dev_err(dev, "%s: Failed to create irq_mask for F%02X.\n",
+                       __func__, pdt_ptr->function_number);
                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;
+       retval = init_function_device(rmi_dev, fn_dev);
+       if (retval < 0) {
+               dev_err(dev, "Failed to initialize F%02X device.\n",
+                       pdt_ptr->function_number);
+               return retval;
+       }
 
-       *current_irq_count += fc->num_of_irqs;
+       INIT_LIST_HEAD(&fn_dev->list);
+       /* we need to ensure that F01 is at the head of the list.
+        */
+       if (pdt_ptr->function_number == 0x01) {
+               list_add(&fn_dev->list, &data->rmi_functions.list);
+               data->f01_dev = fn_dev;
+       } else
+               list_add_tail(&fn_dev->list, &data->rmi_functions.list);
 
-       fc->rmi_dev        = rmi_dev;
-       fc->dev.parent     = &fc->rmi_dev->dev;
-       fc->fh = fh;
+       return 0;
+}
 
-       dev_set_name(&(fc->dev), "fn%02x", fc->fd.function_number);
+/*
+ * Once we find F01, we need to see if we're in bootloader mode.  If we are,
+ * we'll stop scanning the PDT with the current page (usually 0x00 in that
+ * case).
+ */
+static void check_bootloader_mode(struct rmi_device *rmi_dev,
+                                    struct pdt_entry *pdt_ptr,
+                                    u16 page_start)
+{
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct f01_device_status device_status;
+       int retval = 0;
 
-       retval = device_register(&fc->dev);
-       if (retval) {
-               dev_err(dev, "%s: Failed device_register for F01.\n", __func__);
-               goto error_free_data;
+       retval = rmi_read(rmi_dev, pdt_ptr->data_base_addr+page_start,
+                         &device_status);
+       if (retval < 0) {
+               dev_err(&rmi_dev->dev, "Failed to read device status.\n");
+               return;
        }
+       data->f01_bootloader_mode = device_status.flash_prog;
+       if (device_status.flash_prog)
+               dev_warn(&rmi_dev->dev,
+                        "WARNING: RMI4 device is in bootloader mode!\n");
 
-       data->f01_container = fc;
+}
 
-       return retval;
+/*
+ * We also reflash the device if (a) in kernel reflashing is
+ * enabled, and (b) the reflash module decides it requires reflashing.
+ *
+ * We have to do this before actually building the PDT because the reflash
+ * might cause various registers to move around.
+ */
+static int rmi_device_reflash(struct rmi_device *rmi_dev)
+{
+       struct pdt_entry pdt_entry;
+       int page;
+       struct device *dev = &rmi_dev->dev;
+       bool done;
+       bool has_f01 = false;
+       bool has_f34 = false;
+       struct pdt_entry f34_pdt, f01_pdt;
+       int i;
+       int retval;
+       struct rmi_device_platform_data *pdata;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
 
-error_free_data:
-       kfree(fc);
-       return retval;
+       dev_dbg(dev, "Initial reflash.\n");
+       pdata = to_rmi_platform_data(rmi_dev);
+       data->f01_bootloader_mode = false;
+       for (page = 0; (page <= RMI4_MAX_PAGE); 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, &pdt_entry,
+                                              sizeof(pdt_entry));
+                       if (retval != sizeof(pdt_entry)) {
+                               dev_err(dev, "Read PDT entry at %#06x 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) {
+                               memcpy(&f01_pdt, &pdt_entry, sizeof(pdt_entry));
+                               has_f01 = true;
+                               check_bootloader_mode(rmi_dev, &pdt_entry,
+                                                     page_start);
+                       } else if (pdt_entry.function_number == 0x34) {
+                               memcpy(&f34_pdt, &pdt_entry, sizeof(pdt_entry));
+                               has_f34 = true;
+                               }
+
+                       if (has_f01 && has_f34) {
+                               done = true;
+                               break;
+                       }
+               }
+
+               if (data->f01_bootloader_mode || done)
+                       break;
+       }
+
+       if (!has_f01) {
+               dev_warn(dev, "WARNING: Failed to find F01 for initial reflash.\n");
+       return -ENODEV;
+       }
+
+       if (has_f34)
+               rmi4_fw_update(rmi_dev, &f01_pdt, &f34_pdt);
+       else
+               dev_warn(dev, "WARNING: No F34 , firmware update will not be done.\n");
+       return 0;
 }
 
 /*
  * 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.
+ * firmware or configuration.
+ *
  */
-static int do_initial_reset(struct rmi_device* rmi_dev)
+static int rmi_device_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;
+       bool done = false;
+       struct rmi_device_platform_data *pdata;
 
-       pr_info("in function ____%s____  \n", __func__);
-
-       polled_synaptics_rmi_device = rmi_dev;
-
+       dev_dbg(dev, "Initial reset.\n");
+       pdata = to_rmi_platform_data(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,
+               for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) {
+                       retval = rmi_read_block(rmi_dev, i, &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);
+                               dev_err(dev, "Read PDT entry at %#06x failed, code = %d.\n",
+                                               i, retval);
                                return retval;
                        }
 
@@ -601,25 +1082,58 @@ static int do_initial_reset(struct rmi_device* rmi_dev)
                                retval = rmi_write_block(rmi_dev, cmd_addr,
                                                &cmd_buf, 1);
                                if (retval < 0) {
-                                       dev_err(dev, "Initial reset failed. "
-                                               "Code = %d.\n", retval);
+                                       dev_err(dev, "Initial reset failed. Code = %d.\n",
+                                               retval);
                                        return retval;
                                }
-                               mdelay(INITIAL_RESET_WAIT_MS);
+                               mdelay(pdata->reset_delay_ms);
                                return 0;
                        }
-               }
-       }
+                       }
+                       }
 
-       dev_warn(dev, "WARNING: Failed to find F01 for initial reset.\n");
        return -ENODEV;
 }
 
+static void get_prod_id(struct rmi_device *rmi_dev,
+                       struct rmi_driver_data *drvdata)
+{
+       struct device *dev = &rmi_dev->dev;
+       int retval;
+       int board = 0, rev = 0;
+       int i;
+       static const char * const pattern[] = {
+               "tm%4d-%d", "s%4d-%d", "s%4d-ver%1d"};
+       u8 product_id[RMI_PRODUCT_ID_LENGTH+1];
+
+       retval = rmi_read_block(rmi_dev,
+               drvdata->f01_dev->fd.query_base_addr+
+               sizeof(struct f01_basic_queries),
+               product_id, RMI_PRODUCT_ID_LENGTH);
+                       if (retval < 0) {
+               dev_err(dev, "Failed to read product id, code=%d!", retval);
+               return;
+       }
+       product_id[RMI_PRODUCT_ID_LENGTH] = '\0';
+
+       for (i = 0; i < sizeof(product_id); i++)
+               product_id[i] = tolower(product_id[i]);
 
-static int rmi_scan_pdt(struct rmi_device *rmi_dev)
+       for (i = 0; i < ARRAY_SIZE(pattern); i++) {
+               retval = sscanf(product_id, pattern[i], &board, &rev);
+               if (retval)
+                       break;
+       }
+       /* save board and rev data in the rmi_driver_data */
+       drvdata->board = board;
+       drvdata->rev = rev;
+       dev_dbg(dev, "Rmi_driver getProdID, set board: %d rev: %d\n",
+               drvdata->board, drvdata->rev);
+}
+
+static int rmi_count_irqs(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;
@@ -627,20 +1141,10 @@ static int rmi_scan_pdt(struct rmi_device *rmi_dev)
        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);
+       data = dev_get_drvdata(&rmi_dev->dev);
+       mutex_lock(&data->pdt_mutex);
 
-       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;
@@ -648,675 +1152,639 @@ static int rmi_scan_pdt(struct rmi_device *rmi_dev)
 
                done = true;
                for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) {
-                       retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry,
+                       retval = rmi_read_block(rmi_dev, i, &pdt_entry,
                                               sizeof(pdt_entry));
                        if (retval != sizeof(pdt_entry)) {
-                               dev_err(dev, "Read PDT entry at 0x%04x"
-                                       "failed.\n", i);
+                               dev_err(dev, "Read of PDT entry at %#06x 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);
+                       irq_count += pdt_entry.interrupt_source_count;
                        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);
+                       if (pdt_entry.function_number == 0x01)
+                               check_bootloader_mode(rmi_dev, &pdt_entry,
+                                                     page_start);
                }
+               done = done || data->f01_bootloader_mode;
        }
+       data->irq_count = irq_count;
        data->num_of_irq_regs = (irq_count + 7) / 8;
-       dev_dbg(dev, "%s: Done with PDT scan.\n", __func__);
-       return 0;
+       retval = 0;
 
 error_exit:
+       mutex_unlock(&data->pdt_mutex);
        return retval;
 }
 
+static int rmi_scan_pdt(struct rmi_device *rmi_dev)
+{
+       struct rmi_driver_data *data;
+       struct pdt_entry pdt_entry;
+       int page;
+       struct device *dev = &rmi_dev->dev;
+       int irq_count = 0;
+       bool done = false;
+       int i;
+       int 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);
-  }
+       dev_dbg(dev, "Scanning PDT...\n");
 
-  return;
-}
+       data = dev_get_drvdata(&rmi_dev->dev);
+       mutex_lock(&data->pdt_mutex);
 
-struct workqueue_struct *synaptics_rmi_polling_queue = NULL;
-struct delayed_work synaptics_rmi_polling_work;
+       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;
 
-#endif
+               done = true;
+               for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) {
+                       retval = rmi_read_block(rmi_dev, i, &pdt_entry,
+                                              sizeof(pdt_entry));
+                       if (retval != sizeof(pdt_entry)) {
+                               dev_err(dev, "Read of PDT entry at %#06x failed.\n",
+                                       i);
+                               goto error_exit;
+                       }
 
+                       if (RMI4_END_OF_PDT(pdt_entry.function_number))
+                               break;
 
-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, "Found F%02X on page %#04x\n",
+                                       pdt_entry.function_number, page);
+                       done = false;
 
-       dev_dbg(dev, "%s: Starting probe.\n", __func__);
+                       if (pdt_entry.function_number == 0x01)
+                               check_bootloader_mode(rmi_dev, &pdt_entry,
+                                                     page_start);
 
-       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;
-       }
+                       retval = create_function_dev(rmi_dev,
+                                       &pdt_entry, &irq_count, page_start);
 
-       rmi_set_driverdata(rmi_dev, data);
+                       if (retval)
+                               goto error_exit;
 
-       error = rmi_scan_pdt(rmi_dev);
-       if (error) {
-               dev_err(dev, "PDT scan failed with code %d.\n", error);
-               goto err_free_data;
+                       if (pdt_entry.function_number == 0x01)
+                               get_prod_id(rmi_dev, data);
        }
-
-       if (!data->f01_container) {
-               dev_err(dev, "missing f01 function!\n");
-               error = -EINVAL;
-               goto err_free_data;
+               done = done || data->f01_bootloader_mode;
        }
+       dev_dbg(dev, "%s: Done with PDT scan.\n", __func__);
+       retval = 0;
 
-       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_exit:
+       mutex_unlock(&data->pdt_mutex);
+       return retval;
+}
 
-       error = rmi_driver_f01_init(rmi_dev);
-       if (error < 0) {
-               dev_err(dev, "Failed to initialize F01.\n");
-               goto err_free_data;
-       }
+static int f01_notifier_call(struct notifier_block *nb,
+                               unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct rmi_function_dev *fn_dev;
 
-       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);
-       }
+       if (dev->type != &rmi_function_type)
+               return 0;
 
-       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;
-               }
-       }
+       fn_dev = to_rmi_function_dev(dev);
+       if (fn_dev->fd.function_number != 0x01)
+               return 0;
 
-       __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;
+       switch (action) {
+       case BUS_NOTIFY_BOUND_DRIVER:
+               enable_sensor(fn_dev->rmi_dev);
+               break;
+       case BUS_NOTIFY_UNBIND_DRIVER:
+               disable_sensor(fn_dev->rmi_dev);
+               break;
        }
+       return 0;
+}
 
-#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*/
+static struct notifier_block rmi_bus_notifier = {
+       .notifier_call = f01_notifier_call,
+};
 
 #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);
+static int suspend_one_device(struct rmi_function_dev *fn_dev)
+{
+       struct rmi_function_driver *fn_drv;
+       int retval = 0;
 
-#endif /* CONFIG_PM */
-       data->enabled = true;
+       if (!fn_dev->dev.driver)
+               return 0;
 
-       dev_info(dev, "connected RMI device manufacturer: %s product: %s\n",
-                data->manufacturer_id == 1 ? "synaptics" : "unknown",
-                data->product_id);
+       fn_drv = to_rmi_function_driver(fn_dev->dev.driver);
 
-#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;
+       if (fn_drv->suspend) {
+               retval = fn_drv->suspend(fn_dev);
+               if (retval < 0)
+                       dev_err(&fn_dev->dev, "Suspend failed, code: %d",
+                               retval);
+       }
 
- 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;
+       return retval;
 }
 
-#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;
+       struct rmi_function_dev *entry;
        int retval = 0;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
 
-       rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
+       data = dev_get_drvdata(&rmi_dev->dev);
 
        mutex_lock(&data->suspend_mutex);
        if (data->suspended)
                goto exit;
 
-       if (data->pre_suspend) {
+       if (!IS_ENABLED(CONFIG_HAS_EARLYSUSPEND) && 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;
-               }
+       disable_sensor(rmi_dev);
 
-       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)
+       /** Do it backwards so F01 comes last. */
+       list_for_each_entry_reverse(entry, &data->rmi_functions.list, list)
+               if (suspend_one_device(entry) < 0)
                        goto exit;
-       }
+
        data->suspended = true;
 
+       if (data->post_suspend)
+               retval = data->post_suspend(data->pm_data);
+
 exit:
        mutex_unlock(&data->suspend_mutex);
        return retval;
 }
 
+static int resume_one_device(struct rmi_function_dev *fn_dev)
+{
+       struct rmi_function_driver *fn_drv;
+       int retval = 0;
+
+       if (!fn_dev->dev.driver)
+               return 0;
+
+       fn_drv = to_rmi_function_driver(fn_dev->dev.driver);
+
+       if (fn_drv->resume) {
+               retval = fn_drv->resume(fn_dev);
+               if (retval < 0)
+                       dev_err(&fn_dev->dev, "Resume failed, code: %d",
+                               retval);
+       }
+
+       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;
+       struct rmi_function_dev *entry;
        int retval = 0;
+       struct rmi_device *rmi_dev = to_rmi_device(dev);
 
-       rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
-
+       data = dev_get_drvdata(&rmi_dev->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)
+       if (data->pre_resume) {
+               retval = data->pre_resume(data->pm_data);
+               if (retval)
                        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)
+       /** Do it forwards, so F01 comes first. */
+       list_for_each_entry(entry, &data->rmi_functions.list, list) {
+               if (resume_one_device(entry) < 0)
                                goto exit;
                }
 
-       if (data->post_resume) {
+       retval = enable_sensor(rmi_dev);
+       if (retval)
+               goto exit;
+
+
+       if (!IS_ENABLED(CONFIG_HAS_EARLYSUSPEND) && 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;
 }
 
-#endif /* CONFIG_PM */
+#if defined(CONFIG_HAS_EARLYSUSPEND)
 
-static int rmi_driver_remove(struct rmi_device *rmi_dev)
+static int early_suspend_one_device(struct rmi_function_dev *fn_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);
+       struct rmi_function_driver *fn_drv;
+       int retval = 0;
 
+       if (!fn_dev->dev.driver)
        return 0;
-}
 
-#ifdef UNIVERSAL_DEV_PM_OPS
-static UNIVERSAL_DEV_PM_OPS(rmi_driver_pm, rmi_driver_suspend,
-                           rmi_driver_resume, NULL);
-#endif
+       fn_drv = to_rmi_function_driver(fn_dev->dev.driver);
 
-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 = 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;
-}
+       if (fn_drv->early_suspend) {
+               retval = fn_drv->early_suspend(fn_dev);
+               if (retval < 0)
+                       dev_err(&fn_dev->dev, "Early suspend failed, code: %d",
+                               retval);
+       }
 
-/* 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;
+       return retval;
 }
 
-/* sysfs show and store fns for driver attributes */
-static ssize_t rmi_driver_hasbsr_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
+static void rmi_driver_early_suspend(struct early_suspend *h)
 {
-       struct rmi_device *rmi_dev;
+       struct rmi_device *rmi_dev =
+           container_of(h, struct rmi_device, early_suspend_handler);
        struct rmi_driver_data *data;
-       rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
+       struct rmi_function_dev *entry;
+       int retval = 0;
+
+       data = dev_get_drvdata(&rmi_dev->dev);
 
-       return snprintf(buf, PAGE_SIZE, "%u\n", has_bsr(data));
+       mutex_lock(&data->suspend_mutex);
+       if (data->early_suspended)
+               goto exit;
+
+       if (data->pre_suspend) {
+               retval = data->pre_suspend(data->pm_data);
+               if (retval) {
+                       dev_err(&rmi_dev->dev, "Presuspend failed with %d.\n",
+                               retval);
+                       goto exit;
+               }
+       }
+
+       /* Do it backwards, so F01 comes last. */
+       list_for_each_entry_reverse(entry, &data->rmi_functions.list, list)
+               if (early_suspend_one_device(entry) < 0)
+                       goto exit;
+
+       data->early_suspended = true;
+exit:
+       mutex_unlock(&data->suspend_mutex);
 }
 
-static ssize_t rmi_driver_bsr_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static int late_resume_one_device(struct rmi_function_dev *fn_dev)
 {
-       struct rmi_device *rmi_dev;
-       struct rmi_driver_data *data;
-       rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
+       struct rmi_function_driver *fn_drv;
+       int retval = 0;
 
-       return snprintf(buf, PAGE_SIZE, "%u\n", data->bsr);
+       if (!fn_dev->dev.driver)
+               return 0;
+
+       fn_drv = to_rmi_function_driver(fn_dev->dev.driver);
+
+       if (fn_drv->late_resume) {
+               retval = fn_drv->late_resume(fn_dev);
+               if (retval < 0)
+                       dev_err(&fn_dev->dev, "Late resume failed, code: %d",
+                               retval);
+       }
+
+       return retval;
 }
 
-static ssize_t rmi_driver_bsr_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
+static void rmi_driver_late_resume(struct early_suspend *h)
 {
-       int retval;
-       unsigned long val;
-       struct rmi_device *rmi_dev;
+       struct rmi_device *rmi_dev =
+           container_of(h, struct rmi_device, early_suspend_handler);
        struct rmi_driver_data *data;
+       struct rmi_function_dev *entry;
+       int retval = 0;
 
-       rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
+       data = dev_get_drvdata(&rmi_dev->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;
+       mutex_lock(&data->suspend_mutex);
+       if (!data->early_suspended)
+               goto exit;
+
+       /* Do it forwards, so F01 comes first. */
+       list_for_each_entry(entry, &data->rmi_functions.list, list) {
+               if (late_resume_one_device(entry) < 0)
+                       goto exit;
        }
 
-       retval = rmi_write(rmi_dev, BSR_LOCATION, (unsigned char)val);
+       if (data->post_resume) {
+               retval = data->post_resume(data->pm_data);
        if (retval) {
-               dev_err(dev, "%s : failed to write bsr %u to 0x%x\n",
-                       __func__, (unsigned int)val, BSR_LOCATION);
-               return retval;
+                       dev_err(&rmi_dev->dev, "Post resume failed with %d.\n",
+                               retval);
+                       goto exit;
+               }
        }
 
-       data->bsr = val;
+       data->early_suspended = false;
 
-       return count;
+exit:
+       mutex_unlock(&data->suspend_mutex);
 }
+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
 
-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;
-}
+#endif /* CONFIG_PM */
 
-static int enable_sensor(struct rmi_device *rmi_dev)
+static int rmi_driver_remove(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;
+       int i;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
 
-       data->enabled = true;
+       disable_sensor(rmi_dev);
 
+#if 0
+       if (IS_ENABLED(CONFIG_HAS_EARLYSUSPEND))
+               unregister_early_suspend(&rmi_dev->early_suspend_handler);
+#endif
+       teardown_debugfs(rmi_dev);
+
+       rmi_free_function_list(rmi_dev);
+       for (i = 0; i < ARRAY_SIZE(attrs); i++)
+               device_remove_file(&rmi_dev->dev, &attrs[i]);
+       if (data->pdt_props.has_bsr)
+               device_remove_file(&rmi_dev->dev, &bsr_attribute);
        return 0;
 }
 
-static ssize_t rmi_driver_enabled_show(struct device *dev,
-                                      struct device_attribute *attr, char *buf)
+static int rmi_driver_probe(struct device *dev)
 {
+       struct rmi_driver *rmi_driver;
+       struct rmi_driver_data *data = NULL;
+       struct rmi_device_platform_data *pdata;
+       int retval = 0;
+       int attr_count = 0;
        struct rmi_device *rmi_dev;
-       struct rmi_driver_data *data;
 
-       rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
+       if (!dev->driver) {
+               dev_err(dev, "No driver for RMI4 device during probe!\n");
+               return -ENODEV;
+       }
 
-       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;
+       if (dev->type != &rmi_sensor_type)
+               return -ENODEV;
 
        rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
+       rmi_driver = to_rmi_driver(dev->driver);
+       rmi_dev->driver = rmi_driver;
 
-       if (sysfs_streq(buf, "0"))
-               new_value = false;
-       else if (sysfs_streq(buf, "1"))
-               new_value = true;
-       else
-               return -EINVAL;
+       pdata = to_rmi_platform_data(rmi_dev);
 
-       if (new_value) {
-               retval = enable_sensor(rmi_dev);
-               if (retval) {
-                       dev_err(dev, "Failed to enable sensor, code=%d.\n",
-                               retval);
-                       return -EIO;
+       data = devm_kzalloc(dev, sizeof(struct rmi_driver_data), GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "%s: Failed to allocate driver data.\n", __func__);
+               return -ENOMEM;
                }
-       } else {
-               disable_sensor(rmi_dev);
-       }
+       INIT_LIST_HEAD(&data->rmi_functions.list);
+       data->rmi_dev = rmi_dev;
+       dev_set_drvdata(&rmi_dev->dev, data);
+       mutex_init(&data->pdt_mutex);
+
+       /* Right before a warm boot, the sensor might be in some unusual state,
+        * such as F54 diagnostics, or F34 bootloader mode.  In order to clear
+        * the sensor to a known state, we issue a initial reset to clear any
+        * previous settings and force it into normal operation.
+        *
+        * For a number of reasons, this initial reset may fail to return
+        * within the specified time, but we'll still be able to bring up the
+        * driver normally after that failure.  This occurs most commonly in
+        * a cold boot situation (where then firmware takes longer to come up
+        * than from a warm boot) and the reset_delay_ms in the platform data
+        * has been set too short to accomodate that.  Since the sensor will
+        * eventually come up and be usable, we don't want to just fail here
+        * and leave the customer's device unusable.  So we warn them, and
+        * continue processing.
+        */
+       if (!pdata->reset_delay_ms)
+               pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS;
+       retval = rmi_device_reset(rmi_dev);
+       if (retval)
+               dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n");
 
-       return count;
-}
+       retval = rmi_device_reflash(rmi_dev);
+       if (retval)
+               dev_warn(dev, "RMI reflash failed! Continuing in spite of this.\n");
 
-#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;
+       retval = rmi_read(rmi_dev, PDT_PROPERTIES_LOCATION, &data->pdt_props);
+       if (retval < 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 %#06x. Assuming 0x00.\n",
+                        PDT_PROPERTIES_LOCATION);
+       }
 
-       rmi_dev = to_rmi_device(dev);
-       data = rmi_get_driverdata(rmi_dev);
+       if (pdata->attn_gpio) {
+               data->irq = gpio_to_irq(pdata->attn_gpio);
+               if (pdata->level_triggered) {
+                       data->irq_flags = IRQF_ONESHOT |
+                               ((pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH)
+                               ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW);
+               } else {
+                       data->irq_flags =
+                               (pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH)
+                               ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+               }
+               dev_dbg(dev, "Mapped IRQ %d for GPIO %d.\n",
+                       data->irq, pdata->attn_gpio);
+       } else
+               data->poll_interval = ktime_set(0,
+                       (pdata->poll_interval_ms ? pdata->poll_interval_ms :
+                       DEFAULT_POLL_INTERVAL_MS) * 1000);
+
+       retval = rmi_count_irqs(rmi_dev);
+       if (retval) {
+               dev_err(dev, "IRQ counting for %s failed with code %d.\n",
+                       pdata->sensor_name, retval);
+               goto err_free_data;
+       }
 
-       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;
+       mutex_init(&data->irq_mutex);
+       data->irq_status = devm_kzalloc(dev,
+               BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
+               GFP_KERNEL);
+       if (!data->irq_status) {
+               dev_err(dev, "Failed to allocate irq_status.\n");
+               retval = -ENOMEM;
+               goto err_free_data;
        }
-       if (address < 0 || address > 0xFFFF) {
-               dev_err(dev, "Invalid address for reg store '%#06x'.\n",
-                       address);
-               return -EINVAL;
+
+       data->current_irq_mask = devm_kzalloc(dev, data->num_of_irq_regs,
+                               GFP_KERNEL);
+       if (!data->current_irq_mask) {
+               dev_err(dev, "Failed to allocate current_irq_mask.\n");
+               retval = -ENOMEM;
+               goto err_free_data;
        }
-       if (bytes < 0 || bytes >= sizeof(readbuf) || address+bytes > 65535) {
-               dev_err(dev, "Invalid byte count for reg store '%d'.\n",
-                       bytes);
-               return -EINVAL;
+
+       data->irq_mask_store = devm_kzalloc(dev,
+               BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
+               GFP_KERNEL);
+       if (!data->irq_mask_store) {
+               dev_err(dev, "Failed to allocate mask store.\n");
+               retval = -ENOMEM;
+               goto err_free_data;
        }
 
-       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;
+       retval = setup_debugfs(rmi_dev);
+       if (retval < 0)
+               dev_warn(dev, "Failed to setup debugfs. Code: %d.\n", retval);
+
+       retval = rmi_scan_pdt(rmi_dev);
+       if (retval) {
+               dev_err(dev, "PDT scan for %s failed with code %d.\n",
+                       pdata->sensor_name, retval);
+               goto err_free_data;
        }
 
-       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 (!data->f01_dev) {
+               dev_err(dev, "missing F01 device!\n");
+               retval = -EINVAL;
+               goto err_free_data;
+       }
+
+       dev_dbg(dev, "%s: Creating sysfs files.", __func__);
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               retval = device_create_file(dev, &attrs[attr_count]);
                if (retval < 0) {
-                       dev_err(dev, "Failed to format string. Code: %d",
-                               retval);
-                       return retval;
+                       dev_err(dev, "%s: Failed to create sysfs file %s.\n",
+                               __func__, attrs[attr_count].attr.name);
+                       goto err_free_data;
+               }
+       }
+       if (data->pdt_props.has_bsr) {
+               retval = device_create_file(dev, &bsr_attribute);
+               if (retval < 0) {
+                       dev_err(dev, "%s: Failed to create sysfs file bsr.\n",
+                               __func__);
+                       goto err_free_data;
                }
-               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 = rmi_read_block(rmi_dev,
+                               data->f01_dev->fd.control_base_addr+1,
+                               data->current_irq_mask, data->num_of_irq_regs);
+       if (retval < 0) {
+               dev_err(dev, "%s: Failed to read current IRQ mask.\n",
+                       __func__);
+               goto err_free_data;
+       }
 
-       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 (IS_ENABLED(CONFIG_PM)) {
+               data->pm_data = pdata->pm_data;
+               data->pre_suspend = pdata->pre_suspend;
+               data->post_suspend = pdata->post_suspend;
+               data->pre_resume = pdata->pre_resume;
+               data->post_resume = pdata->post_resume;
+
+               mutex_init(&data->suspend_mutex);
+
+#if 0
+               if (IS_ENABLED(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);
        }
-       if (new_read_delay < 0) {
-               dev_err(dev, "Byte delay must be positive microseconds.\n");
-               return -EINVAL;
+#endif
        }
-       if (new_write_delay < 0) {
-               dev_err(dev, "Write delay must be positive microseconds.\n");
-               return -EINVAL;
+
+       if (data->f01_dev->dev.driver) {
+               /* Driver already bound, so enable ATTN now. */
+               enable_sensor(rmi_dev);
        }
-       if (new_block_delay < 0) {
-               dev_err(dev, "Block delay must be positive microseconds.\n");
-               return -EINVAL;
+
+       if (IS_ENABLED(CONFIG_RMI4_DEV) && pdata->attn_gpio) {
+               retval = gpio_export(pdata->attn_gpio, false);
+               if (retval) {
+                       dev_warn(dev, "WARNING: Failed to export ATTN gpio!\n");
+                       retval = 0;
+               } else {
+                       retval = gpio_export_link(dev,
+                                                 "attn", pdata->attn_gpio);
+                       if (retval) {
+                               dev_warn(dev,
+                                       "WARNING: Failed to symlink ATTN gpio!\n");
+                               retval = 0;
+                       } else {
+                               dev_info(dev, "Exported ATTN GPIO %d.",
+                                       pdata->attn_gpio);
        }
-       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 0;
 
-       return count;
+ err_free_data:
+       rmi_free_function_list(rmi_dev);
+       for (attr_count--; attr_count >= 0; attr_count--)
+               device_remove_file(dev, &attrs[attr_count]);
+       if (data->pdt_props.has_bsr)
+               device_remove_file(dev, &bsr_attribute);
+       return retval;
 }
 
-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;
+static UNIVERSAL_DEV_PM_OPS(rmi_driver_pm, rmi_driver_suspend,
+                           rmi_driver_resume, NULL);
 
-       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
+struct rmi_driver rmi_sensor_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "rmi_generic",
+               .bus = &rmi_bus_type,
+               .pm = &rmi_driver_pm,
+               .probe = rmi_driver_probe,
+       },
+       .irq_handler = rmi_driver_irq_handler,
+       .reset_handler = rmi_driver_reset_handler,
+       .store_irq_mask = rmi_driver_irq_save,
+       .restore_irq_mask = rmi_driver_irq_restore,
+       .set_input_params = rmi_driver_set_input_params,
+       .remove = rmi_driver_remove,
+};
 
-static ssize_t rmi_driver_phys_show(struct device *dev,
-                                      struct device_attribute *attr, char *buf)
+int __init rmi_register_sensor_driver(void)
 {
-       struct rmi_device *rmi_dev;
-       struct rmi_phys_info *info;
-
-       rmi_dev = to_rmi_device(dev);
-       info = &rmi_dev->phys->info;
+       int retval;
 
-       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);
-}
+       retval = driver_register(&rmi_sensor_driver.driver);
+       if (retval) {
+               pr_err("%s: driver register failed, code=%d.\n", __func__,
+                      retval);
+               return retval;
+       }
 
-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);
-}
+       /* Ask the bus to let us know when drivers are bound to devices. */
+       retval = bus_register_notifier(&rmi_bus_type, &rmi_bus_notifier);
+       if (retval) {
+               pr_err("%s: failed to register bus notifier, code=%d.\n",
+                      __func__, retval);
+               return retval;
+       }
 
-static int __init rmi_driver_init(void)
-{
-       return rmi_register_driver(&sensor_driver);
+       return 0;
 }
 
-static void __exit rmi_driver_exit(void)
+void __exit rmi_unregister_sensor_driver(void)
 {
-       rmi_unregister_driver(&sensor_driver);
+       bus_unregister_notifier(&rmi_bus_type, &rmi_bus_notifier);
+       driver_unregister(&rmi_sensor_driver.driver);
 }
-
-module_init(rmi_driver_init);
-module_exit(rmi_driver_exit);
-
-MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
-MODULE_DESCRIPTION("RMI generic driver");
index 9e9f2c0..72b31f7 100644 (file)
 /*
- * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011, 2012 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.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
+
 #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
+#include <linux/ctype.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
 
-/* 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_DRIVER_VERSION "1.7"
+
+#define SYNAPTICS_INPUT_DEVICE_NAME "Synaptics RMI4 Touch Sensor"
+#define SYNAPTICS_VENDOR_ID 0x06cb
+
+#define CONFIG_RMI4_DEBUG 1
+
+/* Sysfs related macros */
+
+/* You must define FUNCTION_DATA and FNUM to use these functions. */
+#if defined(FNUM) && defined(FUNCTION_DATA)
+
+#define tricat(x, y, z) tricat_(x, y, z)
+
+#define tricat_(x, y, z) x##y##z
+
+#define show_union_struct_prototype(propname)\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(\
+                                       struct device *dev, \
+                                       struct device_attribute *attr, \
+                                       char *buf);\
+\
+static DEVICE_ATTR(propname, RMI_RO_ATTR,\
+               tricat(rmi_fn_, FNUM, _##propname##_show), \
+               NULL);
+
+#define store_union_struct_prototype(propname)\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(\
+                                       struct device *dev,\
+                                       struct device_attribute *attr,\
+                                       const char *buf, size_t count);\
+\
+static DEVICE_ATTR(propname, RMI_WO_ATTR,\
+               NULL,\
+               tricat(rmi_fn_, FNUM, _##propname##_store));
+
+#define show_store_union_struct_prototype(propname)\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(\
+                                       struct device *dev,\
+                                       struct device_attribute *attr,\
+                                       char *buf);\
+\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(\
+                                       struct device *dev,\
+                                       struct device_attribute *attr,\
+                                       const char *buf, size_t count);\
+\
+static DEVICE_ATTR(propname, RMI_RW_ATTR,\
+               tricat(rmi_fn_, FNUM, _##propname##_show),\
+               tricat(rmi_fn_, FNUM, _##propname##_store));
+
+#define simple_show_union_struct(regtype, propname, fmt)\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(struct device *dev,\
+                               struct device_attribute *attr, char *buf) {\
+       struct rmi_function_dev *fc;\
+       struct FUNCTION_DATA *data;\
+\
+       fc = to_rmi_function_dev(dev);\
+       data = fc->data;\
+\
+       return snprintf(buf, PAGE_SIZE, fmt,\
+                       data->regtype.propname);\
+}
+
+#define simple_show_union_struct2(regtype, reg_group, propname, fmt)\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(struct device *dev,\
+                               struct device_attribute *attr, char *buf) {\
+       struct rmi_function_dev *fc;\
+       struct FUNCTION_DATA *data;\
+\
+       fc = to_rmi_function_dev(dev);\
+       data = fc->data;\
+\
+       return snprintf(buf, PAGE_SIZE, fmt,\
+                       data->regtype.reg_group->propname);\
+}
+
+#define show_union_struct(regtype, reg_group, propname, fmt)\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(\
+                                       struct device *dev,\
+                                       struct device_attribute *attr,\
+                                       char *buf) {\
+       struct rmi_function_dev *fc;\
+       struct FUNCTION_DATA *data;\
+       int result;\
+\
+       fc = to_rmi_function_dev(dev);\
+       data = fc->data;\
+\
+       mutex_lock(&data->regtype##_mutex);\
+       /* Read current regtype values */\
+       result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
+                               (u8 *)data->regtype.reg_group,\
+                               sizeof(data->regtype.reg_group->regs));\
+       mutex_unlock(&data->regtype##_mutex);\
+       if (result < 0) {\
+               dev_dbg(dev, "%s : Could not read regtype at 0x%x\\n",\
+                                       __func__,\
+                                       data->regtype.reg_group->address);\
+               return result;\
+       } \
+       return snprintf(buf, PAGE_SIZE, fmt,\
+                       data->regtype.reg_group->propname);\
+}
+
+#define show_store_union_struct(regtype, reg_group, propname, fmt)\
+show_union_struct(regtype, reg_group, propname, fmt)\
+\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(\
+                                       struct device *dev,\
+                                       struct device_attribute *attr,\
+                                       const char *buf, size_t count) {\
+       int result;\
+       unsigned long val;\
+       unsigned long old_val;\
+       struct rmi_function_dev *fc;\
+       struct FUNCTION_DATA *data;\
+\
+       fc = to_rmi_function_dev(dev);\
+       data = fc->data;\
+\
+       /* need to convert the string data to an actual value */\
+       result = strict_strtoul(buf, 10, &val);\
+\
+       /* if an error occured, return it */\
+       if (result)\
+               return result;\
+       /* Check value maybe */\
+\
+       /* Read current regtype values */\
+       mutex_lock(&data->regtype##_mutex);\
+       result =\
+           rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
+                               (u8 *)data->regtype.reg_group,\
+                               sizeof(data->regtype.reg_group->regs));\
+\
+       if (result < 0) {\
+               mutex_unlock(&data->regtype##_mutex);\
+               dev_dbg(dev, "%s : Could not read regtype at 0x%x\\n",\
+                                        __func__,\
+                                       data->regtype.reg_group->address);\
+               return result;\
+       } \
+       /* if the current regtype registers are already set as we want them,\
+        * do nothing to them */\
+       if (data->regtype.reg_group->propname == val) {\
+               mutex_unlock(&data->regtype##_mutex);\
+               return count;\
+       } \
+       /* Write the regtype back to the regtype register */\
+       old_val = data->regtype.reg_group->propname;\
+       data->regtype.reg_group->propname = val;\
+       result =\
+           rmi_write_block(fc->rmi_dev, data->regtype.reg_group->address,\
+                               (u8 *)data->regtype.reg_group,\
+                               sizeof(data->regtype.reg_group->regs));\
+       if (result < 0) {\
+               dev_dbg(dev, "%s : Could not write regtype to 0x%x\\n",\
+                                       __func__,\
+                                       data->regtype.reg_group->address);\
+               /* revert change to local value if value not written */\
+               data->regtype.reg_group->propname = old_val;\
+               mutex_unlock(&data->regtype##_mutex);\
+               return result;\
+       } \
+       mutex_unlock(&data->regtype##_mutex);\
+       return count;\
+}
+
+
+#define show_repeated_union_struct(regtype, reg_group, propname, fmt)\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(struct device *dev,\
+                                       struct device_attribute *attr,\
+                                       char *buf) {\
+       struct rmi_function_dev *fc;\
+       struct FUNCTION_DATA *data;\
+       int reg_length;\
+       int result, size = 0;\
+       char *temp;\
+       int i;\
+\
+       fc = to_rmi_function_dev(dev);\
+       data = fc->data;\
+       mutex_lock(&data->regtype##_mutex);\
+\
+       /* Read current regtype values */\
+       reg_length = data->regtype.reg_group->length;\
+       result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
+                       (u8 *) data->regtype.reg_group->regs,\
+                       reg_length * sizeof(u8));\
+       mutex_unlock(&data->regtype##_mutex);\
+       if (result < 0) {\
+               dev_dbg(dev, "%s : Could not read regtype at 0x%x\n"\
+                                       "Data may be outdated.", __func__,\
+                                       data->regtype.reg_group->address);\
+       } \
+       temp = buf;\
+       for (i = 0; i < reg_length; i++) {\
+               result = snprintf(temp, PAGE_SIZE - size, fmt " ",\
+                               data->regtype.reg_group->regs[i].propname);\
+               if (result < 0) {\
+                       dev_err(dev, "%s : Could not write output.", __func__);\
+                       return result;\
+               } \
+               size += result;\
+               temp += result;\
+       } \
+       result = snprintf(temp, PAGE_SIZE - size, "\n");\
+       if (result < 0) {\
+                       dev_err(dev, "%s : Could not write output.", __func__);\
+                       return result;\
+       } \
+       return size + result;\
+}
+
+#define show_store_repeated_union_struct(regtype, reg_group, propname, fmt)\
+show_repeated_union_struct(regtype, reg_group, propname, fmt)\
+\
+static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(struct device *dev,\
+                                  struct device_attribute *attr,\
+                                  const char *buf, size_t count) {\
+       struct rmi_function_dev *fc;\
+       struct FUNCTION_DATA *data;\
+       int reg_length;\
+       int result;\
+       const char *temp;\
+       int i;\
+       unsigned int newval;\
+\
+       fc = to_rmi_function_dev(dev);\
+       data = fc->data;\
+       mutex_lock(&data->regtype##_mutex);\
+\
+       /* Read current regtype values */\
+\
+       reg_length = data->regtype.reg_group->length;\
+       result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
+                       (u8 *) data->regtype.reg_group->regs,\
+                       reg_length * sizeof(u8));\
+\
+       if (result < 0) {\
+               dev_dbg(dev, "%s: Could not read regtype at %#06x. "\
+                                       "Data may be outdated.", __func__,\
+                                       data->regtype.reg_group->address);\
+       } \
+       \
+       /* parse input */\
+       temp = buf;\
+       for (i = 0; i < reg_length; i++) {\
+               if (sscanf(temp, fmt, &newval) == 1) {\
+                       data->regtype.reg_group->regs[i].propname = newval;\
+               } else {\
+                       /* If we don't read a value for each position, abort, \
+                        * restore previous values locally by rereading */\
+                       result = rmi_read_block(fc->rmi_dev, \
+                                       data->regtype.reg_group->address,\
+                                       (u8 *) data->regtype.reg_group->regs,\
+                                       reg_length * sizeof(u8));\
+\
+                       if (result < 0) {\
+                               dev_dbg(dev, "%s: Couldn't read regtype at "\
+                                       "%#06x. Local data may be inaccurate", \
+                                       __func__,\
+                                       data->regtype.reg_group->address);\
+                       } \
+                       return -EINVAL;\
+               } \
+               /* move to next number */\
+               while (*temp != 0) {\
+                       temp++;\
+                       if (isspace(*(temp - 1)) && !isspace(*temp))\
+                               break;\
+               } \
+       } \
+       result = rmi_write_block(fc->rmi_dev, data->regtype.reg_group->address,\
+                       (u8 *) data->regtype.reg_group->regs,\
+                       reg_length * sizeof(u8));\
+       mutex_unlock(&data->regtype##_mutex);\
+       if (result < 0) {\
+               dev_dbg(dev, "%s: Could not write new values to %#06x\n", \
+                               __func__, data->regtype.reg_group->address);\
+               return result;\
+       } \
+       return count;\
+}
+
+/* Create templates for given types */
+#define simple_show_union_struct_unsigned(regtype, propname)\
+simple_show_union_struct(regtype, propname, "%u\n")
+
+#define simple_show_union_struct_unsigned2(regtype, reg_group, propname)\
+simple_show_union_struct2(regtype, reg_group, propname, "%u\n")
+
+#define show_union_struct_unsigned(regtype, reg_group, propname)\
+show_union_struct(regtype, reg_group, propname, "%u\n")
+
+#define show_store_union_struct_unsigned(regtype, reg_group, propname)\
+show_store_union_struct(regtype, reg_group, propname, "%u\n")
+
+#define show_repeated_union_struct_unsigned(regtype, reg_group, propname)\
+show_repeated_union_struct(regtype, reg_group, propname, "%u")
+
+#define show_store_repeated_union_struct_unsigned(regtype, reg_group, propname)\
+show_store_repeated_union_struct(regtype, reg_group, propname, "%u")
+
+/* Remove access to raw format string versions */
+/*#undef simple_show_union_struct
+#undef show_union_struct_unsigned
+#undef show_store_union_struct
+#undef show_repeated_union_struct
+#undef show_store_repeated_union_struct*/
+
+#endif
+
+#define GROUP(_attrs) { \
+       .attrs = _attrs,  \
+}
+
+#define attrify(nm) (&dev_attr_##nm.attr)
 
+#define PDT_PROPERTIES_LOCATION 0x00EF
+#define BSR_LOCATION 0x00FE
 
-#define RMI_PRODUCT_ID_LENGTH    10
-#define RMI_PRODUCT_INFO_LENGTH   2
-#define RMI_DATE_CODE_LENGTH      3
+struct pdt_properties {
+       u8 reserved_1:6;
+       u8 has_bsr:1;
+       u8 reserved_2:1;
+} __attribute__((__packed__));
 
 struct rmi_driver_data {
-       struct rmi_function_container rmi_functions;
+       struct rmi_function_dev rmi_functions;
+       struct rmi_device *rmi_dev;
 
-       struct rmi_function_container *f01_container;
+       struct rmi_function_dev *f01_dev;
+       bool f01_bootloader_mode;
 
+       atomic_t attn_count;
+       u32 irq_debug;
+       int irq;
+       int irq_flags;
        int num_of_irq_regs;
-       u8 *current_irq_mask;
-       u8 *irq_mask_store;
+       int irq_count;
+       unsigned long *irq_status;
+       unsigned long *current_irq_mask;
+       unsigned long *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;
+       /* Following are used when polling. */
+       struct hrtimer poll_timer;
+       struct work_struct poll_work;
+       ktime_t poll_interval;
+       struct mutex pdt_mutex;
+       struct pdt_properties pdt_props;
+       u8 bsr;
 
-       u8 manufacturer_id;
-       /* product id + null termination */
-       u8 product_id[RMI_PRODUCT_ID_LENGTH + 1];
+       int board;
+       int rev;
 
+       bool enabled;
 #ifdef CONFIG_PM
        bool suspended;
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+       bool early_suspended;
+#endif
        struct mutex suspend_mutex;
 
        void *pm_data;
        int (*pre_suspend) (const void *pm_data);
+       int (*post_suspend) (const void *pm_data);
+       int (*pre_resume) (const void *pm_data);
        int (*post_resume) (const void *pm_data);
 #endif
 
+#ifdef CONFIG_RMI4_DEBUG
+       struct dentry *debugfs_delay;
+       struct dentry *debugfs_phys;
+       struct dentry *debugfs_reg_ctl;
+       struct dentry *debugfs_reg;
+       struct dentry *debugfs_irq;
+       struct dentry *debugfs_attn_count;
+       u16 reg_debug_addr;
+       u8 reg_debug_size;
+#endif
+
        void *data;
 };
 
+#define PDT_START_SCAN_LOCATION 0x00e9
+#define PDT_END_SCAN_LOCATION  0x0005
+#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
+
 struct pdt_entry {
        u8 query_base_addr:8;
        u8 command_base_addr:8;
@@ -75,9 +416,7 @@ struct pdt_entry {
        u8 function_version:2;
        u8 bit7:1;
        u8 function_number:8;
-};
-
-int rmi_driver_f01_init(struct rmi_device *rmi_dev);
+} __attribute__((__packed__));
 
 static inline void copy_pdt_entry_to_fd(struct pdt_entry *pdt,
                                 struct rmi_function_descriptor *fd,
@@ -92,18 +431,17 @@ static inline void copy_pdt_entry_to_fd(struct pdt_entry *pdt,
        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);
+#ifdef CONFIG_RMI4_FWLIB
+extern void rmi4_fw_update(struct rmi_device *rmi_dev,
+               struct pdt_entry *f01_pdt, struct pdt_entry *f34_pdt);
+#else
+#define rmi4_fw_update(rmi_dev, f01_pdt, f34_pdt) 0
+#endif
 
-/* 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);
+extern struct rmi_driver rmi_sensor_driver;
+extern struct rmi_function_driver rmi_f01_driver;
+
+int rmi_register_sensor_driver(void);
+void rmi_unregister_sensor_driver(void);
 
 #endif
index 6ccdf24..4c0732a 100644 (file)
 /*
- * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011-2012 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.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
-#define DEBUG
-
 #include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/kconfig.h>
 #include <linux/rmi.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 #include "rmi_driver.h"
+#include "rmi_f01.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 FUNCTION_NUMBER 0x01
 
-#define RMI_IS_VALID_SLEEPMODE(mode) \
-       (mode >= RMI_SLEEP_MODE_NORMAL && mode <= RMI_SLEEP_MODE_RESERVED1)
-
-union f01_device_commands {
-       struct {
+/**
+ * @reset - set this bit to force a firmware reset of the sensor.
+ */
+struct f01_device_commands {
                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;
+       u8 reserved:7;
 };
 
-union f01_device_status {
-       struct {
-               u8 status_code:4;
-               u8 reserved:2;
-               u8 flash_prog:1;
-               u8 unconfigured:1;
-       };
-       u8 reg;
+/**
+ * @ctrl0 - see documentation in rmi_f01.h.
+ * @interrupt_enable - A mask of per-function interrupts on the touch sensor.
+ * @doze_interval - controls the interval between checks for finger presence
+ * when the touch sensor is in doze mode, in units of 10ms.
+ * @wakeup_threshold - controls the capacitance threshold at which the touch
+ * sensor will decide to wake up from that low power state.
+ * @doze_holdoff - controls how long the touch sensor waits after the last
+ * finger lifts before entering the doze state, in units of 100ms.
+ */
+struct f01_device_control {
+       struct f01_device_control_0 ctrl0;
+       u8 *interrupt_enable;
+       u8 doze_interval;
+       u8 wakeup_threshold;
+       u8 doze_holdoff;
 };
 
-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];
-};
+/**
+ * @has_ds4_queries - if true, the query registers relating to Design Studio 4
+ * features are present.
+ * @has_multi_phy - if true, multiple physical communications interfaces are
+ * supported.
+ * @has_guest - if true, a "guest" device is supported.
+ */
+struct f01_query_42 {
+               u8 has_ds4_queries:1;
+               u8 has_multi_phy:1;
+               u8 has_guest:1;
+               u8 reserved:5;
+} __attribute__((__packed__));
+
+/**
+ * @length - the length of the remaining Query43.* register block, not
+ * including the first register.
+ * @has_package_id_query -  the package ID query data will be accessible from
+ * inside the ProductID query registers.
+ * @has_packrat_query -  the packrat query data will be accessible from inside
+ * the ProductID query registers.
+ * @has_reset_query - the reset pin related registers are valid.
+ * @has_maskrev_query - the silicon mask revision number will be reported.
+ * @has_i2c_control - the register F01_RMI_Ctrl6 will exist.
+ * @has_spi_control - the register F01_RMI_Ctrl7 will exist.
+ * @has_attn_control - the register F01_RMI_Ctrl8 will exist.
+ * @reset_enabled - the hardware reset pin functionality has been enabled
+ * for this device.
+ * @reset_polarity - If this bit reports as ‘0’, it means that the reset state
+ * is active low. A ‘1’ means that the reset state is active high.
+ * @pullup_enabled - If set, it indicates that a built-in weak pull up has
+ * been enabled on the Reset pin; clear means that no pull-up is present.
+ * @reset_pin_number - This field represents which GPIO pin number has been
+ * assigned the reset functionality.
+ */
+struct f01_ds4_queries {
+       u8 length:4;
+       u8 reserved_1:4;
+
+       u8 has_package_id_query:1;
+       u8 has_packrat_query:1;
+       u8 has_reset_query:1;
+       u8 has_maskrev_query:1;
+       u8 reserved_2:4;
+
+       u8 has_i2c_control:1;
+       u8 has_spi_control:1;
+       u8 has_attn_control:1;
+       u8 reserved_3:5;
+
+       u8 reset_enabled:1;
+       u8 reset_polarity:1;
+       u8 pullup_enabled:1;
+       u8 reserved_4:1;
+       u8 reset_pin_number:4;
+} __attribute__((__packed__));
 
+/*
+ *
+ * @serialization - 7 bytes of device serialization data.  The meaning of
+ * these bytes varies from product to product, consult your product spec sheet.
+ */
 struct f01_data {
-       union f01_device_control device_control;
-       union f01_basic_queries basic_queries;
-       union f01_device_status device_status;
+       struct f01_device_control device_control;
+       struct f01_basic_queries basic_queries;
+       struct f01_device_status device_status;
+       u8 serialization[F01_SERIALIZATION_SIZE];
        u8 product_id[RMI_PRODUCT_ID_LENGTH+1];
 
+       u16 interrupt_enable_addr;
+       u16 doze_interval_addr;
+       u16 wakeup_threshold_addr;
+       u16 doze_holdoff_addr;
+
+       int irq_count;
+       int num_of_irq_regs;
+
 #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);
+#ifdef CONFIG_RMI4_DEBUG
+       struct dentry *debugfs_interrupt_enable;
+#endif
+};
 
-static ssize_t rmi_fn_01_manufacturer_show(struct device *dev,
-                                          struct device_attribute *attr,
-                                          char *buf);
+#ifdef CONFIG_RMI4_DEBUG
+struct f01_debugfs_data {
+       bool done;
+       struct rmi_function_dev *fn_dev;
+};
 
-static ssize_t rmi_fn_01_datecode_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf);
+static int f01_debug_open(struct inode *inodep, struct file *filp)
+{
+       struct f01_debugfs_data *data;
+       struct rmi_function_dev *fn_dev = inodep->i_private;
 
-static ssize_t rmi_fn_01_reportrate_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf);
+       data = kzalloc(sizeof(struct f01_debugfs_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
-static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
-                                         struct device_attribute *attr,
-                                         const char *buf, size_t count);
+       data->fn_dev = fn_dev;
+       filp->private_data = data;
+       return 0;
+}
 
-static ssize_t rmi_fn_01_reset_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count);
+static int f01_debug_release(struct inode *inodep, struct file *filp)
+{
+       kfree(filp->private_data);
+       return 0;
+}
 
-static ssize_t rmi_fn_01_sleepmode_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf);
+static ssize_t interrupt_enable_read(struct file *filp, char __user *buffer,
+                                    size_t size, loff_t *offset) {
+       int i;
+       int len;
+       int total_len = 0;
+       char local_buf[size];
+       char *current_buf = local_buf;
+       struct f01_debugfs_data *data = filp->private_data;
+       struct f01_data *f01 = data->fn_dev->data;
+
+       if (data->done)
+               return 0;
 
-static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
-                                        struct device_attribute *attr,
-                                        const char *buf, size_t count);
+       data->done = 1;
+
+       /* loop through each irq value and copy its
+        * string representation into buf */
+       for (i = 0; i < f01->irq_count; i++) {
+               int irq_reg;
+               int irq_shift;
+               int interrupt_enable;
+
+               irq_reg = i / 8;
+               irq_shift = i % 8;
+               interrupt_enable =
+                   ((f01->device_control.interrupt_enable[irq_reg]
+                       >> irq_shift) & 0x01);
+
+               /* get next irq value and write it to buf */
+               len = snprintf(current_buf, size - total_len,
+                       "%u ", interrupt_enable);
+               /* 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(&data->fn_dev->dev, "Failed to build interrupt_enable buffer, code = %d.\n",
+                                               len);
+                       return snprintf(local_buf, size, "unknown\n");
+               }
+       }
+       len = snprintf(current_buf, size - total_len, "\n");
+       if (len > 0)
+               total_len += len;
+       else
+               dev_warn(&data->fn_dev->dev, "%s: Failed to append carriage return.\n",
+                        __func__);
 
-static ssize_t rmi_fn_01_nosleep_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf);
+       if (copy_to_user(buffer, local_buf, total_len))
+               return -EFAULT;
 
-static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count);
+       return total_len;
+}
 
-static ssize_t rmi_fn_01_chargerinput_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf);
+static ssize_t interrupt_enable_write(struct file *filp,
+               const char __user *buffer, size_t size, loff_t *offset) {
+       int retval;
+       char buf[size];
+       char *local_buf = buf;
+       int i;
+       int irq_count = 0;
+       int irq_reg = 0;
+       struct f01_debugfs_data *data = filp->private_data;
+       struct f01_data *f01 = data->fn_dev->data;
+
+       retval = copy_from_user(buf, buffer, size);
+       if (retval)
+               return -EFAULT;
+
+       for (i = 0; i < f01->irq_count && *local_buf != 0;
+            i++, local_buf += 2) {
+               int irq_shift;
+               int interrupt_enable;
+               int result;
+
+               irq_reg = i / 8;
+               irq_shift = i % 8;
+
+               /* get next interrupt mapping value and store and bump up to
+                * point to next item in local_buf */
+               result = sscanf(local_buf, "%u", &interrupt_enable);
+               if ((result != 1) ||
+                       (interrupt_enable != 0 && interrupt_enable != 1)) {
+                       dev_err(&data->fn_dev->dev, "Interrupt enable[%d] is not a valid value 0x%x.\n",
+                               i, interrupt_enable);
+                       return -EINVAL;
+               }
+               if (interrupt_enable == 0) {
+                       f01->device_control.interrupt_enable[irq_reg] &=
+                               (1 << irq_shift) ^ 0xFF;
+               } else
+                       f01->device_control.interrupt_enable[irq_reg] |=
+                               (1 << irq_shift);
+               irq_count++;
+       }
 
-static ssize_t rmi_fn_01_chargerinput_store(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count);
+       /* Make sure the irq count matches */
+       if (irq_count != f01->irq_count) {
+               dev_err(&data->fn_dev->dev, "Interrupt enable count of %d doesn't match device count of %d.\n",
+                        irq_count, f01->irq_count);
+               return -EINVAL;
+       }
 
-static ssize_t rmi_fn_01_configured_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf);
+       /* write back to the control register */
+       retval = rmi_write_block(data->fn_dev->rmi_dev,
+                       f01->interrupt_enable_addr,
+                       f01->device_control.interrupt_enable,
+                       f01->num_of_irq_regs);
+       if (retval < 0) {
+               dev_err(&data->fn_dev->dev, "Could not write interrupt_enable mask to %#06x\n",
+                       f01->interrupt_enable_addr);
+               return retval;
+       }
 
-static ssize_t rmi_fn_01_unconfigured_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf);
+       return size;
+}
 
-static ssize_t rmi_fn_01_flashprog_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf);
+static const struct file_operations interrupt_enable_fops = {
+       .owner = THIS_MODULE,
+       .open = f01_debug_open,
+       .release = f01_debug_release,
+       .read = interrupt_enable_read,
+       .write = interrupt_enable_write,
+};
 
-static ssize_t rmi_fn_01_statuscode_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf);
+static int setup_debugfs(struct rmi_function_dev *fn_dev)
+{
+       struct f01_data *data = fn_dev->data;
 
-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_RO_ATTR,
-              rmi_fn_01_sleepmode_show, rmi_fn_01_sleepmode_store),
-       __ATTR(nosleep, RMI_RO_ATTR,
-              rmi_fn_01_nosleep_show, rmi_fn_01_nosleep_store),
-       __ATTR(chargerinput, RMI_RO_ATTR,
-              rmi_fn_01_chargerinput_show, rmi_fn_01_chargerinput_store),
-       __ATTR(reportrate, RMI_RO_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),
+       if (!fn_dev->debugfs_root)
+               return -ENODEV;
 
-       /* Command register access. */
-       __ATTR(reset, RMI_RO_ATTR,
-              rmi_show_error, rmi_fn_01_reset_store),
+       data->debugfs_interrupt_enable = debugfs_create_file("interrupt_enable",
+               RMI_RW_ATTR, fn_dev->debugfs_root, fn_dev,
+               &interrupt_enable_fops);
+       if (!data->debugfs_interrupt_enable)
+               dev_warn(&fn_dev->dev,
+                        "Failed to create debugfs interrupt_enable.\n");
 
-       /* 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),
-};
+               return 0;
+}
 
-/* 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)
+static void teardown_debugfs(struct f01_data *f01)
 {
-       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;
+       if (f01->debugfs_interrupt_enable)
+               debugfs_remove(f01->debugfs_interrupt_enable);
 }
+#else
+#define setup_debugfs(fn_dev) 0
+#define teardown_debugfs(f01)
+#endif
 
 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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n",
                        data->basic_queries.productinfo_1,
@@ -255,9 +330,9 @@ static ssize_t rmi_fn_01_productid_show(struct device *dev,
                                        char *buf)
 {
        struct f01_data *data = NULL;
-       struct rmi_function_container *fc = to_rmi_function_container(dev);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", data->product_id);
 }
@@ -267,40 +342,43 @@ static ssize_t rmi_fn_01_manufacturer_show(struct device *dev,
                                           char *buf)
 {
        struct f01_data *data = NULL;
-       struct rmi_function_container *fc = to_rmi_function_container(dev);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->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,
+static ssize_t rmi_fn_01_serialization_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);
+       int i, n, count = 0;
+       char *local_buf = buf;
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
-       return snprintf(buf, PAGE_SIZE, "20%02u-%02u-%02u\n",
-                       data->basic_queries.year,
-                       data->basic_queries.month,
-                       data->basic_queries.day);
+       for (i = 0; i < F01_SERIALIZATION_SIZE; i++) {
+               n = snprintf(local_buf, PAGE_SIZE - count, "%02X ",
+                            data->serialization[i]);
+               count += n;
+               local_buf += n;
+       }
+       return count;
 }
 
 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;
+       struct rmi_function_dev *fn_dev = 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);
+       fn_dev = to_rmi_function_dev(dev);
 
        if (sscanf(buf, "%u", &reset) != 1)
                return -EINVAL;
@@ -309,12 +387,16 @@ static ssize_t rmi_fn_01_reset_store(struct device *dev,
 
        /* 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));
+               /* Command register always reads as 0, so just use a local. */
+               struct f01_device_commands commands = {
+                       .reset = 1
+               };
+               retval = rmi_write_block(fn_dev->rmi_dev,
+                                        fn_dev->fd.command_base_addr,
+                                        &commands, sizeof(commands));
                if (retval < 0) {
-                       dev_err(dev, "%s: failed to issue reset command, "
-                               "error = %d.", __func__, retval);
+                       dev_err(dev, "Failed to issue reset command, code = %d.",
+                                               retval);
                        return retval;
                }
        }
@@ -327,25 +409,24 @@ static ssize_t rmi_fn_01_sleepmode_show(struct device *dev,
                                        char *buf)
 {
        struct f01_data *data = NULL;
-       struct rmi_function_container *fc = to_rmi_function_container(dev);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE,
-                       "%d\n", data->device_control.sleep_mode);
+                       "%d\n", data->device_control.ctrl0.sleep_mode);
 }
 
 static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
                                         struct device_attribute *attr,
-                                        const char *buf,
-                                        size_t count)
+                                        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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        retval = strict_strtoul(buf, 10, &new_value);
        if (retval < 0 || !RMI_IS_VALID_SLEEPMODE(new_value)) {
@@ -354,10 +435,10 @@ static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
        }
 
        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));
+       data->device_control.ctrl0.sleep_mode = new_value;
+       retval = rmi_write_block(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
        if (retval >= 0)
                retval = count;
        else
@@ -366,39 +447,38 @@ static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
 }
 
 static ssize_t rmi_fn_01_nosleep_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
+                                     struct device_attribute *attr, char *buf)
 {
        struct f01_data *data = NULL;
-       struct rmi_function_container *fc = to_rmi_function_container(dev);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
-       return snprintf(buf, PAGE_SIZE, "%d\n", data->device_control.nosleep);
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+               data->device_control.ctrl0.nosleep);
 }
 
 static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
                                       struct device_attribute *attr,
-                                      const char *buf,
-                                      size_t count)
+                                      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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        retval = strict_strtoul(buf, 10, &new_value);
-       if (retval < 0 || new_value < 0 || new_value > 1) {
+       if (retval < 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));
+       data->device_control.ctrl0.nosleep = new_value;
+       retval = rmi_write_block(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
        if (retval >= 0)
                retval = count;
        else
@@ -407,40 +487,38 @@ static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
 }
 
 static ssize_t rmi_fn_01_chargerinput_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
+                                     struct device_attribute *attr, char *buf)
 {
        struct f01_data *data = NULL;
-       struct rmi_function_container *fc = to_rmi_function_container(dev);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       data->device_control.charger_input);
+                       data->device_control.ctrl0.charger_input);
 }
 
 static ssize_t rmi_fn_01_chargerinput_store(struct device *dev,
                                       struct device_attribute *attr,
-                                      const char *buf,
-                                      size_t count)
+                                      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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        retval = strict_strtoul(buf, 10, &new_value);
-       if (retval < 0 || new_value < 0 || new_value > 1) {
+       if (retval < 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));
+       data->device_control.ctrl0.charger_input = new_value;
+       retval = rmi_write_block(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
        if (retval >= 0)
                retval = count;
        else
@@ -449,40 +527,38 @@ static ssize_t rmi_fn_01_chargerinput_store(struct device *dev,
 }
 
 static ssize_t rmi_fn_01_reportrate_show(struct device *dev,
-                                     struct device_attribute *attr,
-                                     char *buf)
+                                     struct device_attribute *attr, char *buf)
 {
        struct f01_data *data = NULL;
-       struct rmi_function_container *fc = to_rmi_function_container(dev);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       data->device_control.report_rate);
+                       data->device_control.ctrl0.report_rate);
 }
 
 static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
                                       struct device_attribute *attr,
-                                      const char *buf,
-                                      size_t count)
+                                      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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        retval = strict_strtoul(buf, 10, &new_value);
-       if (retval < 0 || new_value < 0 || new_value > 1) {
+       if (retval < 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));
+       data->device_control.ctrl0.report_rate = new_value;
+       retval = rmi_write_block(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
        if (retval >= 0)
                retval = count;
        else
@@ -490,191 +566,722 @@ static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
        return retval;
 }
 
-static ssize_t rmi_fn_01_configured_show(struct device *dev,
+static ssize_t rmi_fn_01_interrupt_enable_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct rmi_function_dev *fn_dev;
+       struct f01_data *data;
+       int i, len, total_len = 0;
+       char *current_buf = buf;
+
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       /* loop through each irq value and copy its
+        * string representation into buf */
+       for (i = 0; i < data->irq_count; i++) {
+               int irq_reg;
+               int irq_shift;
+               int interrupt_enable;
+
+               irq_reg = i / 8;
+               irq_shift = i % 8;
+               interrupt_enable =
+                   ((data->device_control.interrupt_enable[irq_reg]
+                       >> irq_shift) & 0x01);
+
+               /* get next irq value and write it to buf */
+               len = snprintf(current_buf, PAGE_SIZE - total_len,
+                       "%u ", interrupt_enable);
+               /* 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, "Failed to build interrupt_enable buffer, code = %d.\n",
+                                               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_fn_01_doze_interval_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct f01_data *data = NULL;
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
+
+       data = fn_dev->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->device_control.doze_interval);
+
+}
+
+static ssize_t rmi_fn_01_doze_interval_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;
+       u16 ctrl_addr;
+
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
+
+       data = fn_dev->data;
+
+       retval = strict_strtoul(buf, 10, &new_value);
+       if (retval < 0 || new_value > 255) {
+               dev_err(dev, "%s: Invalid doze interval %s.", __func__, buf);
+               return -EINVAL;
+       }
+
+       data->device_control.doze_interval = new_value;
+       ctrl_addr = fn_dev->fd.control_base_addr + sizeof(u8) +
+                       (sizeof(u8)*(data->num_of_irq_regs));
+       dev_dbg(dev, "doze_interval store address %x, value %d",
+               ctrl_addr, data->device_control.doze_interval);
+
+       retval = rmi_write_block(fn_dev->rmi_dev, data->doze_interval_addr,
+                       &data->device_control.doze_interval,
+                       sizeof(u8));
+       if (retval >= 0)
+               retval = count;
+       else
+               dev_err(dev, "Failed to write doze interval.\n");
+       return retval;
+
+}
+
+static ssize_t rmi_fn_01_wakeup_threshold_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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       data->device_control.configured);
+                       data->device_control.wakeup_threshold);
 }
 
-static ssize_t rmi_fn_01_unconfigured_show(struct device *dev,
+static ssize_t rmi_fn_01_wakeup_threshold_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_dev *fn_dev = to_rmi_function_dev(dev);
+
+       data = fn_dev->data;
+
+       retval = strict_strtoul(buf, 10, &new_value);
+       if (retval < 0 || new_value > 255) {
+               dev_err(dev, "%s: Invalid wakeup threshold %s.", __func__, buf);
+               return -EINVAL;
+       }
+
+       data->device_control.doze_interval = new_value;
+       retval = rmi_write_block(fn_dev->rmi_dev, data->wakeup_threshold_addr,
+                       &data->device_control.wakeup_threshold,
+                       sizeof(u8));
+       if (retval >= 0)
+               retval = count;
+       else
+               dev_err(dev, "Failed to write wakeup threshold.\n");
+       return retval;
+
+}
+
+static ssize_t rmi_fn_01_doze_holdoff_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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       data->device_status.unconfigured);
+                       data->device_control.doze_holdoff);
+
 }
 
-static ssize_t rmi_fn_01_flashprog_show(struct device *dev,
+
+static ssize_t rmi_fn_01_doze_holdoff_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_dev *fn_dev = to_rmi_function_dev(dev);
+
+       data = fn_dev->data;
+
+       retval = strict_strtoul(buf, 10, &new_value);
+       if (retval < 0 || new_value > 255) {
+               dev_err(dev, "%s: Invalid doze holdoff %s.", __func__, buf);
+               return -EINVAL;
+       }
+
+       data->device_control.doze_interval = new_value;
+       retval = rmi_write_block(fn_dev->rmi_dev, data->doze_holdoff_addr,
+                       &data->device_control.doze_holdoff,
+                       sizeof(u8));
+       if (retval >= 0)
+               retval = count;
+       else
+               dev_err(dev, "Failed to write doze holdoff.\n");
+       return retval;
+
+}
+
+/* Placeholder */
+static ssize_t rmi_fn_01_allow_doze_show(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
 {
+       unsigned int a = 1;
+       return snprintf(buf, PAGE_SIZE, "%d\n", a);
+
+}
+
+static ssize_t rmi_fn_01_allow_doze_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       return count;
+}
+
+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_dev *fn_dev = to_rmi_function_dev(dev);
+
+       data = fn_dev->data;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->device_control.ctrl0.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_dev *fn_dev = to_rmi_function_dev(dev);
+
+       data = fn_dev->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);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->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 device_attribute *attr, char *buf)
 {
        struct f01_data *data = NULL;
-       struct rmi_function_container *fc = to_rmi_function_container(dev);
+       struct rmi_function_dev *fn_dev = to_rmi_function_dev(dev);
 
-       data = fc->data;
+       data = fn_dev->data;
 
        return snprintf(buf, PAGE_SIZE, "0x%02x\n",
                        data->device_status.status_code);
 }
 
-int rmi_driver_f01_init(struct rmi_device *rmi_dev)
+static struct device_attribute dev_attr_doze_interval =
+               __ATTR(doze_interval, RMI_RW_ATTR,
+                       rmi_fn_01_doze_interval_show,
+                               rmi_fn_01_doze_interval_store);
+static struct device_attribute dev_attr_wakeup_threshold =
+               __ATTR(wakeup_threshold, RMI_RW_ATTR,
+                       rmi_fn_01_wakeup_threshold_show,
+                       rmi_fn_01_wakeup_threshold_store);
+static struct device_attribute dev_attr_doze_holdoff =
+               __ATTR(doze_holdoff, RMI_RW_ATTR,
+                       rmi_fn_01_doze_holdoff_show,
+                       rmi_fn_01_doze_holdoff_store);
+
+static struct device_attribute dev_attr_productinfo =
+       __ATTR(productinfo, RMI_RO_ATTR,
+              rmi_fn_01_productinfo_show, NULL);
+static struct device_attribute dev_attr_productid =
+       __ATTR(productid, RMI_RO_ATTR,
+              rmi_fn_01_productid_show, NULL);
+static struct device_attribute dev_attr_manufacturer =
+       __ATTR(manufacturer, RMI_RO_ATTR,
+              rmi_fn_01_manufacturer_show, NULL);
+
+/* control register access */
+static struct device_attribute dev_attr_sleepmode =
+       __ATTR(sleepmode, RMI_RW_ATTR,
+              rmi_fn_01_sleepmode_show, rmi_fn_01_sleepmode_store);
+static struct device_attribute dev_attr_nosleep =
+       __ATTR(nosleep, RMI_RW_ATTR,
+              rmi_fn_01_nosleep_show, rmi_fn_01_nosleep_store);
+static struct device_attribute dev_attr_chargerinput =
+       __ATTR(chargerinput, RMI_RW_ATTR,
+              rmi_fn_01_chargerinput_show, rmi_fn_01_chargerinput_store);
+static struct device_attribute dev_attr_reportrate =
+       __ATTR(reportrate, RMI_RW_ATTR,
+              rmi_fn_01_reportrate_show, rmi_fn_01_reportrate_store);
+/* We don't want arbitrary callers changing the interrupt enable mask,
+ * so it's read only.
+ */
+static struct device_attribute dev_attr_interrupt_enable =
+       __ATTR(interrupt_enable, RMI_RO_ATTR,
+              rmi_fn_01_interrupt_enable_show, NULL);
+
+/* Allow Doze: TBA */
+static struct device_attribute dev_attr_allow_doze = 
+       __ATTR(allow_doze, RMI_RW_ATTR,
+               rmi_fn_01_allow_doze_show, rmi_fn_01_allow_doze_store);
+
+/* We make configured RO, since the driver uses that to look for
+ * resets.  We don't want someone faking us out by changing that
+ * bit.
+ */
+static struct device_attribute dev_attr_configured =
+       __ATTR(configured, RMI_RO_ATTR,
+              rmi_fn_01_configured_show, NULL);
+
+/* Command register access. */
+static struct device_attribute dev_attr_reset =
+       __ATTR(reset, RMI_WO_ATTR,
+              NULL, rmi_fn_01_reset_store);
+
+/* Status register access. */
+static struct device_attribute dev_attr_unconfigured =
+       __ATTR(unconfigured, RMI_RO_ATTR,
+              rmi_fn_01_unconfigured_show, NULL);
+static struct device_attribute dev_attr_flashprog =
+       __ATTR(flashprog, RMI_RO_ATTR,
+              rmi_fn_01_flashprog_show, NULL);
+static struct device_attribute dev_attr_statuscode =
+       __ATTR(statuscode, RMI_RO_ATTR,
+              rmi_fn_01_statuscode_show, NULL);
+static struct device_attribute dev_attr_serialization =
+       __ATTR(serialization, RMI_RO_ATTR,
+              rmi_fn_01_serialization_show, NULL);
+
+static struct attribute *attrs[] = {
+       &dev_attr_productinfo.attr,
+       &dev_attr_productid.attr,
+       &dev_attr_manufacturer.attr,
+       &dev_attr_sleepmode.attr,
+       &dev_attr_nosleep.attr,
+       &dev_attr_chargerinput.attr,
+       &dev_attr_reportrate.attr,
+       &dev_attr_interrupt_enable.attr,
+       &dev_attr_allow_doze.attr,
+
+       /* We make configured RO, since the driver uses that to look for
+        * resets.  We don't want someone faking us out by changing that
+        * bit.
+        */
+       &dev_attr_configured.attr,
+       &dev_attr_reset.attr,
+       &dev_attr_unconfigured.attr,
+       &dev_attr_flashprog.attr,
+       &dev_attr_statuscode.attr,
+       &dev_attr_serialization.attr,
+       NULL
+};
+
+static struct attribute_group fn01_attrs = GROUP(attrs);
+
+static int rmi_f01_alloc_memory(struct rmi_function_dev *fn_dev,
+       int num_of_irq_regs)
 {
-       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;
+       struct f01_data *f01;
 
-       data = kzalloc(sizeof(struct f01_data), GFP_KERNEL);
-       if (!data) {
-               dev_err(&rmi_dev->dev, "Failed to allocate F01 data.\n");
+       f01 = devm_kzalloc(&fn_dev->dev, sizeof(struct f01_data), GFP_KERNEL);
+       if (!f01) {
+               dev_err(&fn_dev->dev, "Failed to allocate fn_01_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;
+       f01->device_control.interrupt_enable = devm_kzalloc(&fn_dev->dev,
+                       sizeof(u8)*(num_of_irq_regs),
+                       GFP_KERNEL);
+       if (!f01->device_control.interrupt_enable) {
+               dev_err(&fn_dev->dev, "Failed to allocate interrupt enable.\n");
+               return -ENOMEM;
        }
+       fn_dev->data = f01;
 
+       return 0;
+}
+
+static int rmi_f01_initialize(struct rmi_function_dev *fn_dev)
+{
+       u8 temp;
+       int retval;
+       u16 query_addr = fn_dev->fd.query_base_addr;
+       u16 ctrl_addr = fn_dev->fd.control_base_addr;
+       struct rmi_device *rmi_dev = fn_dev->rmi_dev;
+       struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev);
+       struct f01_data *data = fn_dev->data;
+       struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
+
+       /* Set the configured bit and (optionally) other important stuff
+        * in the device control register. */
+       retval = rmi_read_block(rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read F01 control.\n");
+               return retval;
+       }
+       switch (pdata->power_management.nosleep) {
+       case RMI_F01_NOSLEEP_DEFAULT:
+               break;
+       case RMI_F01_NOSLEEP_OFF:
+               data->device_control.ctrl0.nosleep = 0;
+               break;
+       case RMI_F01_NOSLEEP_ON:
+               data->device_control.ctrl0.nosleep = 1;
+               break;
+       }
        /* 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,
+       if (data->device_control.ctrl0.sleep_mode != RMI_SLEEP_MODE_NORMAL) {
+               dev_warn(&fn_dev->dev,
                         "WARNING: Non-zero sleep mode found. Clearing...\n");
-               data->device_control.sleep_mode = RMI_SLEEP_MODE_NORMAL;
+               data->device_control.ctrl0.sleep_mode = RMI_SLEEP_MODE_NORMAL;
+       }
+
+       data->device_control.ctrl0.configured = 1;
+       retval = rmi_write_block(rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to write F01 control.\n");
+               return retval;
        }
 
-       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");
+       data->irq_count = driver_data->irq_count;
+       data->num_of_irq_regs = driver_data->num_of_irq_regs;
+       ctrl_addr += sizeof(struct f01_device_control_0);
+
+       data->interrupt_enable_addr = ctrl_addr;
+       retval = rmi_read_block(rmi_dev, ctrl_addr,
+                       data->device_control.interrupt_enable,
+                       sizeof(u8)*(data->num_of_irq_regs));
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read F01 control interrupt enable register.\n");
                goto error_exit;
        }
+       ctrl_addr += data->num_of_irq_regs;
 
        /* 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;
+       retval = rmi_read(rmi_dev, fn_dev->fd.data_base_addr + 1, &temp);
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read Interrupt Status.\n");
+               return retval;
        }
 
-       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");
+       /* read queries */
+       retval = rmi_read_block(rmi_dev, query_addr, &data->basic_queries,
+                               sizeof(data->basic_queries));
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read device query registers.\n");
+               return retval;
+       }
+       query_addr += sizeof(data->basic_queries);
+
+       retval = rmi_read_block(rmi_dev, query_addr, data->serialization,
+                               F01_SERIALIZATION_SIZE);
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read device serialization.\n");
+               return retval;
+       }
+       query_addr += F01_SERIALIZATION_SIZE;
+
+       retval = rmi_read_block(rmi_dev, query_addr, data->product_id,
+                               RMI_PRODUCT_ID_LENGTH);
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read product ID.\n");
+               return retval;
+       }
+       data->product_id[RMI_PRODUCT_ID_LENGTH] = '\0';
+       dev_info(&fn_dev->dev, "found RMI device, manufacturer: %s, product: %s\n",
+                data->basic_queries.manufacturer_id == 1 ?
+                                                       "synaptics" : "unknown",
+                data->product_id);
+
+       /* read control register */
+       if (data->basic_queries.has_adjustable_doze) {
+               data->doze_interval_addr = ctrl_addr;
+               ctrl_addr++;
+
+               if (pdata->power_management.doze_interval) {
+                       data->device_control.doze_interval =
+                               pdata->power_management.doze_interval;
+                       retval = rmi_write(rmi_dev, data->doze_interval_addr,
+                                       data->device_control.doze_interval);
+                       if (retval < 0) {
+                               dev_err(&fn_dev->dev, "Failed to configure F01 doze interval register.\n");
+                               goto error_exit;
+                       }
+               } else {
+                       retval = rmi_read(rmi_dev, data->doze_interval_addr,
+                                       &data->device_control.doze_interval);
+                       if (retval < 0) {
+                               dev_err(&fn_dev->dev, "Failed to read F01 doze interval register.\n");
                goto error_exit;
        }
-       driver_data->manufacturer_id = data->basic_queries.manufacturer_id;
+               }
+
+               data->wakeup_threshold_addr = ctrl_addr;
+               ctrl_addr++;
 
-       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");
+               if (pdata->power_management.wakeup_threshold) {
+                       data->device_control.wakeup_threshold =
+                               pdata->power_management.wakeup_threshold;
+                       retval = rmi_write(rmi_dev, data->wakeup_threshold_addr,
+                                       data->device_control.wakeup_threshold);
+                       if (retval < 0) {
+                               dev_err(&fn_dev->dev, "Failed to configure F01 wakeup threshold register.\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");
+               } else {
+                       retval = rmi_read(rmi_dev, data->wakeup_threshold_addr,
+                                       &data->device_control.wakeup_threshold);
+                       if (retval < 0) {
+                               dev_err(&fn_dev->dev, "Failed to read F01 wakeup threshold register.\n");
+                               goto error_exit;
+                       }
+               }
+       }
+
+       if (data->basic_queries.has_adjustable_doze_holdoff) {
+               data->doze_holdoff_addr = ctrl_addr;
+               ctrl_addr++;
+
+               if (pdata->power_management.doze_holdoff) {
+                       data->device_control.doze_holdoff =
+                               pdata->power_management.doze_holdoff;
+                       retval = rmi_write(rmi_dev, data->doze_holdoff_addr,
+                                       data->device_control.doze_holdoff);
+                       if (retval < 0) {
+                               dev_err(&fn_dev->dev, "Failed to configure F01 doze holdoff register.\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;
+               } else {
+                       retval = rmi_read(rmi_dev, data->doze_holdoff_addr,
+                                       &data->device_control.doze_holdoff);
+                       if (retval < 0) {
+                               dev_err(&fn_dev->dev, "Failed to read F01 doze holdoff register.\n");
                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;
+               }
+       }
+
+       retval = rmi_read_block(rmi_dev, fn_dev->fd.data_base_addr,
+               &data->device_status, sizeof(data->device_status));
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read device status.\n");
                        goto error_exit;
                }
+
+       if (data->device_status.unconfigured) {
+               dev_err(&fn_dev->dev, "Device reset during configuration process, status: %#02x!\n",
+                               data->device_status.status_code);
+               retval = -EINVAL;
+               goto error_exit;
        }
 
-       return error;
+       if (IS_ENABLED(CONFIG_RMI4_DEBUG)) {
+               retval = setup_debugfs(fn_dev);
+               if (retval < 0)
+                       dev_warn(&fn_dev->dev, "Failed to setup debugfs. Code: %d.\n",
+                               retval);
+       }
+
+       return retval;
 
  error_exit:
        kfree(data);
+       return retval;
+}
+
+static int rmi_f01_create_sysfs(struct rmi_function_dev *fn_dev)
+{
+       int retval = 0;
+       struct f01_data *data = fn_dev->data;
+
+       dev_dbg(&fn_dev->dev, "Creating sysfs files.");
+       if (sysfs_create_group(&fn_dev->dev.kobj, &fn01_attrs) < 0) {
+               dev_err(&fn_dev->dev, "Failed to create query sysfs files.");
+               return -ENODEV;
+       }
+       if (data->basic_queries.has_lts) {
+               retval = sysfs_create_file(&fn_dev->dev.kobj,
+                       &dev_attr_doze_interval.attr);
+               if (retval < 0) {
+                       dev_err(&fn_dev->dev, "Failed to create sysfs file for doze internal.");
+                       goto err_remove_sysfs_group;
+               }
+       }
+       if (data->basic_queries.has_adjustable_doze) {
+               retval = sysfs_create_file(&fn_dev->dev.kobj,
+                       &dev_attr_wakeup_threshold.attr);
+               if (retval < 0) {
+                       dev_err(&fn_dev->dev, "Failed to create sysfs file for wakeup threshold.");
+                       goto err_remove_sysfs_doze_interval;
+               }
+       }
+       if (data->basic_queries.has_adjustable_doze_holdoff) {
+               retval = sysfs_create_file(&fn_dev->dev.kobj,
+                       &dev_attr_doze_holdoff.attr);
+               if (retval < 0) {
+                       dev_err(&fn_dev->dev, "Failed to create sysfs file for doze holdoff.");
+                       goto err_remove_sysfs_wakeup_threshold;
+               }
+       }
+       return 0;
+
+err_remove_sysfs_wakeup_threshold:
+       sysfs_remove_file(&fn_dev->dev.kobj, &dev_attr_wakeup_threshold.attr);
+
+err_remove_sysfs_doze_interval:
+       sysfs_remove_file(&fn_dev->dev.kobj, &dev_attr_doze_interval.attr);
+
+err_remove_sysfs_group:
+       sysfs_remove_group(&fn_dev->dev.kobj, &fn01_attrs);
+       return retval;
+}
+
+static int rmi_f01_config(struct rmi_function_dev *fn_dev)
+{
+       struct f01_data *data = fn_dev->data;
+       int retval;
+
+       retval = rmi_write_block(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to write device_control.reg.\n");
+               return retval;
+       }
+
+       retval = rmi_write_block(fn_dev->rmi_dev, data->interrupt_enable_addr,
+                       data->device_control.interrupt_enable,
+                       sizeof(u8)*(data->num_of_irq_regs));
+
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to write interrupt enable.\n");
+               return retval;
+       }
+       if (data->basic_queries.has_lts) {
+               retval = rmi_write_block(fn_dev->rmi_dev,
+                                       data->doze_interval_addr,
+                                       &data->device_control.doze_interval,
+                                       sizeof(u8));
+               if (retval < 0) {
+                       dev_err(&fn_dev->dev, "Failed to write doze interval.\n");
+                       return retval;
+               }
+       }
+
+       if (data->basic_queries.has_adjustable_doze) {
+               retval = rmi_write_block(
+                               fn_dev->rmi_dev, data->wakeup_threshold_addr,
+                               &data->device_control.wakeup_threshold,
+                               sizeof(u8));
+               if (retval < 0) {
+                       dev_err(&fn_dev->dev, "Failed to write wakeup threshold.\n");
+                       return retval;
+               }
+       }
+
+       if (data->basic_queries.has_adjustable_doze_holdoff) {
+               retval = rmi_write_block(fn_dev->rmi_dev,
+                                       data->doze_holdoff_addr,
+                                       &data->device_control.doze_holdoff,
+                                       sizeof(u8));
+               if (retval < 0) {
+                       dev_err(&fn_dev->dev, "Failed to write doze holdoff.\n");
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+static int rmi_f01_probe(struct rmi_function_dev *fn_dev)
+{
+       struct rmi_driver_data *driver_data =
+                       dev_get_drvdata(&fn_dev->rmi_dev->dev);
+       int error;
+
+       error = rmi_f01_alloc_memory(fn_dev, driver_data->num_of_irq_regs);
+       if (error < 0)
+               return error;
+
+       error = rmi_f01_initialize(fn_dev);
+       if (error < 0)
+               return error;
+
+       error = rmi_f01_create_sysfs(fn_dev);
+       if (error < 0)
        return error;
+
+       return 0;
 }
 
 #ifdef CONFIG_PM
-
-static int rmi_f01_suspend(struct rmi_function_container *fc)
+static int rmi_f01_suspend(struct rmi_function_dev *fn_dev)
 {
-       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;
+       struct rmi_device *rmi_dev = fn_dev->rmi_dev;
+       struct f01_data *data = fn_dev->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;
+       data->old_nosleep = data->device_control.ctrl0.nosleep;
+       data->device_control.ctrl0.nosleep = 0;
+       data->device_control.ctrl0.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));
+                       fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
        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;
+               dev_err(&fn_dev->dev, "Failed to write sleep mode. Code: %d.\n",
+                       retval);
+               data->device_control.ctrl0.nosleep = data->old_nosleep;
+               data->device_control.ctrl0.sleep_mode = RMI_SLEEP_MODE_NORMAL;
        } else {
                data->suspended = true;
                retval = 0;
@@ -683,27 +1290,25 @@ static int rmi_f01_suspend(struct rmi_function_container *fc)
        return retval;
 }
 
-static int rmi_f01_resume(struct rmi_function_container *fc)
+static int rmi_f01_resume(struct rmi_function_dev *fn_dev)
 {
-       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;
+       struct rmi_device *rmi_dev = fn_dev->rmi_dev;
+       struct f01_data *data = fn_dev->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;
+       data->device_control.ctrl0.nosleep = data->old_nosleep;
+       data->device_control.ctrl0.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));
+       retval = rmi_write_block(rmi_dev, fn_dev->fd.control_base_addr,
+                       &data->device_control.ctrl0,
+                       sizeof(data->device_control.ctrl0));
        if (retval < 0)
-               dev_err(&fc->dev, "Failed to restore normal operation. "
-                       "Code: %d.\n", retval);
+               dev_err(&fn_dev->dev,
+                       "Failed to restore normal operation. Code: %d.\n",
+                       retval);
        else {
                data->suspended = false;
                retval = 0;
@@ -713,63 +1318,70 @@ static int rmi_f01_resume(struct rmi_function_container *fc)
 }
 #endif /* CONFIG_PM */
 
-static int rmi_f01_init(struct rmi_function_container *fc)
+static int rmi_f01_remove(struct rmi_function_dev *fn_dev)
 {
+       struct f01_data *data = fn_dev->data;
+
+       if (IS_ENABLED(CONFIG_RMI4_DEBUG))
+               teardown_debugfs(fn_dev->data);
+
+       sysfs_remove_group(&fn_dev->dev.kobj, &fn01_attrs);
+
+       if (data->basic_queries.has_lts)
+               sysfs_remove_file(&fn_dev->dev.kobj,
+                                 &dev_attr_doze_interval.attr);
+
+       if (data->basic_queries.has_adjustable_doze)
+               sysfs_remove_file(&fn_dev->dev.kobj,
+                                 &dev_attr_wakeup_threshold.attr);
+
+       if (data->basic_queries.has_adjustable_doze_holdoff)
+               sysfs_remove_file(&fn_dev->dev.kobj,
+                                 &dev_attr_doze_holdoff.attr);
+
        return 0;
 }
 
-static int rmi_f01_attention(struct rmi_function_container *fc, u8 *irq_bits)
+static int rmi_f01_attention(struct rmi_function_dev *fn_dev,
+                                               unsigned long *irq_bits)
 {
-       struct rmi_device *rmi_dev = fc->rmi_dev;
-       struct f01_data *data = fc->data;
-       int error;
+       struct rmi_device *rmi_dev = fn_dev->rmi_dev;
+       struct f01_data *data = fn_dev->data;
+       int retval;
 
-       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;
+       retval = rmi_read_block(rmi_dev, fn_dev->fd.data_base_addr,
+               &data->device_status, sizeof(data->device_status));
+       if (retval < 0) {
+               dev_err(&fn_dev->dev, "Failed to read device status, code: %d.\n",
+                       retval);
+               return retval;
+       }
+       if (data->device_status.unconfigured) {
+               dev_warn(&fn_dev->dev, "Device reset detected.\n");
+               retval = rmi_dev->driver->reset_handler(rmi_dev);
+               if (retval < 0)
+                       return retval;
        }
-
-       /* 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,
+struct rmi_function_driver rmi_f01_driver = {
+       .driver = {
+               .name = "rmi_f01",
+       },
+       .func = FUNCTION_NUMBER,
+       .probe = rmi_f01_probe,
+       .remove = rmi_f01_remove,
+       .config = rmi_f01_config,
        .attention = rmi_f01_attention,
+
 #ifdef CONFIG_PM
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+       .early_suspend = rmi_f01_suspend,
+       .late_resume = rmi_f01_resume,
+#else
        .suspend = rmi_f01_suspend,
        .resume = rmi_f01_resume,
-#endif
+#endif  /* defined(CONFIG_HAS_EARLYSUSPEND) && !def... */
+#endif  /* CONFIG_PM */
 };
-
-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_f01.h b/drivers/input/touchscreen/rmi4/rmi_f01.h
new file mode 100644 (file)
index 0000000..511b389
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+
+#ifndef _RMI_F01_H
+#define _RMI_F01_H
+
+#define RMI_PRODUCT_ID_LENGTH    10
+#define RMI_PRODUCT_INFO_LENGTH   2
+
+#define RMI_DATE_CODE_LENGTH      3
+
+#define PRODUCT_ID_OFFSET 0x10
+#define PRODUCT_INFO_OFFSET 0x1E
+
+#define F01_RESET_MASK 0x01
+
+#define F01_SERIALIZATION_SIZE 7
+
+/**
+ * @manufacturer_id - reports the identity of the manufacturer of the RMI
+ * device. Synaptics RMI devices report a Manufacturer ID of $01.
+ * @custom_map - at least one custom, non
+ * RMI-compatible register exists in the register address map for this device.
+ * @non-compliant - the device implements a register map that is not compliant
+ * with the RMI specification.
+ * @has_lts - the device uses Synaptics' LTS hardware architecture.
+ * @has_sensor_id - the SensorID query register (F01_RMI_Query22) exists.
+ * @has_charger_input - the ChargerConnected bit (F01_RMI_Ctrl0, bit 5) is
+ * meaningful.
+ * @has_adjustable_doze - the doze (power management) control registers exist.
+ * @has_adjustable_doze_holdoff - the doze holdoff register exists.
+ * @has_product_properties - indicates the presence of F01_RMI_Query42,
+ * ProductProperties2.
+ * @productinfo_1 - meaning varies from product to product, consult your
+ * product spec sheet.
+ * @productinfo_2 - meaning varies from product to product, consult your
+ * product spec sheet.
+ */
+struct f01_basic_queries {
+       u8 manufacturer_id:8;
+
+       u8 custom_map:1;
+       u8 non_compliant:1;
+       u8 has_lts:1;
+       u8 has_sensor_id:1;
+       u8 has_charger_input:1;
+       u8 has_adjustable_doze:1;
+       u8 has_adjustable_doze_holdoff:1;
+       u8 has_product_properties_2:1;
+
+       u8 productinfo_1:7;
+       u8 q2_bit_7:1;
+       u8 productinfo_2:7;
+       u8 q3_bit_7:1;
+
+} __attribute__((__packed__));
+
+/** The status code field reports the most recent device status event.
+ * @no_error - should be self explanatory.
+ * @reset_occurred - no other event was seen since the last reset.
+ * @invalid_config - general device configuration has a problem.
+ * @device_failure - general device hardware failure.
+ * @config_crc - configuration failed memory self check.
+ * @firmware_crc - firmware failed memory self check.
+ * @crc_in_progress - bootloader is currently testing config and fw areas.
+ */
+enum rmi_device_status {
+       no_error = 0x00,
+       reset_occurred = 0x01,
+       invalid_config = 0x02,
+       device_failure = 0x03,
+       config_crc = 0x04,
+       firmware_crc = 0x05,
+       crc_in_progress = 0x06
+};
+
+/**
+ * @status_code - reports the most recent device status event.
+ * @flash_prog - if set, this indicates that flash programming is enabled and
+ * normal operation is not possible.
+ * @unconfigured - the device has lost its configuration for some reason.
+ */
+struct f01_device_status {
+       enum rmi_device_status status_code:4;
+       u8 reserved:2;
+       u8 flash_prog:1;
+       u8 unconfigured:1;
+} __attribute__((__packed__));
+
+/* 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)
+
+/**
+ * @sleep_mode - This field controls power management on the device. This
+ * field affects all functions of the device together.
+ * @nosleep - When set to ‘1’, this bit disables whatever sleep mode may be
+ * selected by the sleep_mode field,and forces the device to run at full power
+ * without sleeping.
+ * @charger_input - When this bit is set to ‘1’, the touch controller employs
+ * a noise-filtering algorithm designed for use with a connected battery
+ * charger.
+ * @report_rate - sets the report rate for the device.  The effect of this
+ * setting is highly product dependent.  Check the spec sheet for your
+ * particular touch sensor.
+ * @configured - written by the host as an indicator that the device has been
+ * successfuly configured.
+ */
+struct f01_device_control_0 {
+       u8 sleep_mode:2;
+       u8 nosleep:1;
+       u8 reserved:2;
+       u8 charger_input:1;
+       u8 report_rate:1;
+       u8 configured:1;
+} __attribute__((__packed__));
+
+#endif
index 4328d49..70ececb 100644 (file)
@@ -1,66 +1,65 @@
 /*
- * Copyright (c) 2011 Synaptics Incorporated
- * Copyright (c) 2011 Unixphere
+ * Copyright (c) 2011, 2012 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.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
+
 #include <linux/kernel.h>
 #include <linux/rmi.h>
 #include <linux/input.h>
 #include <linux/slab.h>
+#include "rmi_driver.h"
 
 #define QUERY_BASE_INDEX 1
-#define MAX_LEN 256
+#define FUNCTION_NUMBER 0x09
 
 /* data specific to fn $09 that needs to be kept around */
 struct f09_query {
-       u8 Limit_Register_Count;
+       u8 limit_register_count;
        union {
                struct {
-                       u8 Result_Register_Count:3;
-                       u8 Reserved:3;
-                       u8 InternalLimits:1;
-                       u8 HostTestEn:1;
-               };
+                       u8 result_register_count:3;
+                       u8 reserved:3;
+                       u8 internal_limits:1;
+                       u8 host_test_enable:1;
+               } __attribute__((__packed__));
                u8 f09_bist_query1;
        };
 };
 
 struct f09_control {
-       /* test1 */
-       u8 Test1LimitLo;
-       u8 Test1LimitHi;
-       u8 Test1LimitDiff;
-       /* test2 */
-       u8 Test2LimitLo;
-       u8 Test2LimitHi;
-       u8 Test2LimitDiff;
+       union {
+               struct {
+                       u8 test1_limit_low:8;
+                       u8 test1_limit_high:8;
+                       u8 test1_limit_diff:8;
+               } __attribute__((__packed__));
+               u8 f09_control_test1[3];
+       };
+       union {
+               struct {
+                       u8 test2_limit_low:8;
+                       u8 test2_limit_high:8;
+                       u8 test2_limit_diff:8;
+               } __attribute__((__packed__));
+               u8 f09_control_test2[3];
+       };
 };
 
 struct f09_data {
-       u8 TestNumberControl;
-       u8 Overall_BIST_Result;
-       u8 TestResult1;
-       u8 TestResult2;
-       u8 Transmitter_Number;
+       u8 test_number_control;
+       u8 overall_bist_result;
+       u8 test_result1;
+       u8 test_result2;
+       u8 transmitter_number;
 
        union {
                struct {
-                       u8 Receiver_Number:6;
-                       u8 Limit_Failure_Code:2;
-               };
+                       u8 receiver_number:6;
+                       u8 limit_failure_code:2;
+               } __attribute__((__packed__));
                u8 f09_bist_data2;
        };
 };
@@ -68,195 +67,212 @@ struct f09_data {
 struct f09_cmd {
        union {
                struct {
-                       u8 RunBIST:1;
-               };
+                       u8 run_bist:1;
+               } __attribute__((__packed__));
                u8 f09_bist_cmd0;
        };
 };
 
 struct rmi_fn_09_data {
        struct f09_query query;
+       struct f09_data data;
+       struct f09_cmd cmd;
+       struct f09_control control;
+       signed char status;
 };
 
-static ssize_t rmi_f09_Limit_Register_Count_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf);
+static ssize_t rmi_f09_status_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *instance_data;
+
+       fn_dev = to_rmi_function_dev(dev);
+       instance_data = fn_dev->data;
 
-static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf);
+       return snprintf(buf, PAGE_SIZE, "%d\n", instance_data->status);
+}
 
-static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
+static ssize_t rmi_f09_status_store(struct device *dev,
                                      struct device_attribute *attr,
-                                       const char *buf, size_t count);
+                               const char *buf, size_t count)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *instance_data;
+
+       fn_dev = to_rmi_function_dev(dev);
+       instance_data = fn_dev->data;
 
-static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf);
-#if defined(RMI_SYS_ATTR)
-static ssize_t rmi_f09_InternalLimits_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf);
+       /* any write to status resets 1 */
+       instance_data->status = 0;
 
-static ssize_t rmi_f09_Overall_BIST_Result_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf);
+       return 0;
+}
 
-static ssize_t rmi_f09_Overall_BIST_Result_store(struct device *dev,
+static ssize_t rmi_f09_limit_register_count_show(struct device *dev,
                                       struct device_attribute *attr,
-                                      const char *buf, size_t count);
-#endif
+                                       char *buf)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
 
-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),
-};
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.limit_register_count);
+}
 
-static int rmi_f09_init(struct rmi_function_container *fc)
+static ssize_t rmi_f09_host_test_enable_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
-       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 attr_count = 0;
-       int retval = 0;
-
-       dev_info(&fc->dev, "Intializing F09 values.");
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
 
-       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;
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.host_test_enable);
+}
 
-       pdata = to_rmi_platform_data(rmi_dev);
-       query_base_addr = fc->fd.query_base_addr;
+static ssize_t rmi_f09_host_test_enable_store(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
+       unsigned int new_value;
+       int result;
 
-       /* 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;
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       if (sscanf(buf, "%u", &new_value) != 1) {
+               dev_err(dev, "hostTestEnable has an invalid length.\n");
+               return -EINVAL;
        }
 
-       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;
+       if (new_value > 1) {
+               dev_err(dev, "Invalid hostTestEnable bit %s.\n", buf);
+               return -EINVAL;
                }
+       data->query.host_test_enable = new_value;
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.query_base_addr,
+               data->query.host_test_enable);
+       if (result < 0) {
+               dev_err(dev, "%s: Could not write hostTestEnable to %#06x\n",
+                               __func__, fn_dev->fd.query_base_addr);
+               return result;
        }
-       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;
+       return count;
+
 }
 
-static void rmi_f09_remove(struct rmi_function_container *fc)
+static ssize_t rmi_f09_internal_limits_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
-       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);
-}
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
 
-static struct rmi_function_handler function_handler = {
-       .func = 0x09,
-       .init = rmi_f09_init,
-       .remove = rmi_f09_remove
-};
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.internal_limits);
+}
 
-static int __init rmi_f09_module_init(void)
+static ssize_t rmi_f09_result_register_count_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
-       int error;
-
-       error = rmi_register_function_driver(&function_handler);
-       if (error < 0) {
-               pr_err("%s: register failed!\n", __func__);
-               return error;
-       }
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
 
-       return 0;
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->query.result_register_count);
 }
 
-static void rmi_f09_module_exit(void)
+static ssize_t rmi_f09_overall_bist_result_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
-       rmi_unregister_function_driver(&function_handler);
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
+
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->data.overall_bist_result);
 }
 
+static ssize_t rmi_f09_test_result1_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
 
-static ssize_t rmi_f09_Limit_Register_Count_show(struct device *dev,
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       data->data.test_result1);
+}
+
+static ssize_t rmi_f09_test_result2_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct rmi_function_container *fc;
+       struct rmi_function_dev *fn_dev;
        struct rmi_fn_09_data *data;
 
-       fc = to_rmi_function_container(dev);
-       data = fc->data;
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
        return snprintf(buf, PAGE_SIZE, "%u\n",
-                       data->query.Limit_Register_Count);
+                       data->data.test_result2);
 }
 
-static ssize_t rmi_f09_HostTestEn_show(struct device *dev,
+static ssize_t rmi_f09_run_bist_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct rmi_function_container *fc;
+       struct rmi_function_dev *fn_dev;
        struct rmi_fn_09_data *data;
 
-       fc = to_rmi_function_container(dev);
-       data = fc->data;
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
        return snprintf(buf, PAGE_SIZE, "%u\n",
-                       data->query.HostTestEn);
+                       data->cmd.run_bist);
 }
 
-static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
+static ssize_t rmi_f09_run_bist_store(struct device *dev,
                                      struct device_attribute *attr,
                                        const char *buf, size_t count)
 {
-       struct rmi_function_container *fc;
+       struct rmi_function_dev *fn_dev;
        struct rmi_fn_09_data *data;
        unsigned int new_value;
        int result;
 
-       fc = to_rmi_function_container(dev);
-       data = fc->data;
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
        if (sscanf(buf, "%u", &new_value) != 1) {
-               dev_err(dev,
-               "%s: Error - HostTestEn_store has an "
-               "invalid len.\n",
-               __func__);
+               dev_err(dev, "run_bist_store has an invalid len.\n");
                return -EINVAL;
        }
 
-       if (new_value < 0 || new_value > 1) {
-               dev_err(dev, "%s: Invalid HostTestEn bit %s.", __func__, buf);
+       if (new_value > 1) {
+               dev_err(dev, "%s: Invalid run_bist 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);
+       data->cmd.run_bist = new_value;
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.command_base_addr,
+               data->cmd.run_bist);
        if (result < 0) {
-               dev_err(dev, "%s : Could not write HostTestEn_store to 0x%x\n",
-                               __func__, fc->fd.query_base_addr);
+               dev_err(dev, "Could not write run_bist_store to %#06x\n",
+                               fn_dev->fd.command_base_addr);
                return result;
        }
 
@@ -264,37 +280,348 @@ static ssize_t rmi_f09_HostTestEn_store(struct device *dev,
 
 }
 
-#if defined(RMI_SYS_ATTR)
- ssize_t rmi_f09_InternalLimits_show(struct device *dev,
+static ssize_t rmi_f09_control_test1_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct rmi_function_container *fc;
+       struct rmi_function_dev *fn_dev;
        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);
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u %u %u\n",
+                       data->control.test1_limit_low,
+                       data->control.test1_limit_high,
+                       data->control.test1_limit_diff);
 }
-#endif
 
-static ssize_t rmi_f09_Result_Register_Count_show(struct device *dev,
+static ssize_t rmi_f09_control_test1_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
+       unsigned int new_low, new_high, new_diff;
+       int result;
+
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       if (sscanf(buf, "%u %u %u", &new_low, &new_high, &new_diff) != 3) {
+               dev_err(dev, "f09_control_test1_store has an invalid len.\n");
+               return -EINVAL;
+       }
+
+       // Could we take a look at rmi spec?
+       /*if (new_low > 1 || new_high < 0 || new_high
+                       || new_diff < 0 || new_diff) {
+               dev_err(dev, "Invalid f09_control_test1_diff bit %s.", buf);
+               return -EINVAL;
+       }*/
+       data->control.test1_limit_low = new_low;
+       data->control.test1_limit_high = new_high;
+       data->control.test1_limit_diff = new_diff;
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+               data->control.test1_limit_low);
+       if (result < 0) {
+               dev_err(dev, "Could not write f09_control_test1_limit_low to %#06x.\n",
+                               fn_dev->fd.control_base_addr);
+               return result;
+       }
+
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+               data->control.test1_limit_high);
+       if (result < 0) {
+               dev_err(dev, "Could not write f09_control_test1_limit_high to %#06x\n",
+                               fn_dev->fd.control_base_addr);
+               return result;
+       }
+
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+               data->control.test1_limit_diff);
+       if (result < 0) {
+               dev_err(dev, "Could not write f09_control_test1_limit_diff to %#06x\n",
+                               fn_dev->fd.control_base_addr);
+               return result;
+       }
+
+       return count;
+
+}
+
+static ssize_t rmi_f09_control_test2_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct rmi_function_container *fc;
+       struct rmi_function_dev *fn_dev;
        struct rmi_fn_09_data *data;
 
-       fc = to_rmi_function_container(dev);
-       data = fc->data;
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       return snprintf(buf, PAGE_SIZE, "%u %u %u\n",
+                       data->control.test2_limit_low,
+                       data->control.test2_limit_high,
+                       data->control.test2_limit_diff);
+}
+
+static ssize_t rmi_f09_control_test2_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
+       unsigned int new_low, new_high, new_diff;
+       int result;
+
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       if (sscanf(buf, "%u %u %u", &new_low, &new_high, &new_diff) != 3) {
+               dev_err(dev, "f09_control_test1_store has an invalid len.\n");
+               return -EINVAL;
+       }
+
+       // Should we take a look at rmi spec?
+       /*if (new_low < 0 || new_low > 1 || new_high < 0 || new_high > 1 ||
+                       new_diff < 0 || new_diff > 1) {
+               dev_err(dev, "Invalid f09_control_test2_diff bit %s.", buf);
+               return -EINVAL;
+       }*/
+       data->control.test2_limit_low = new_low;
+       data->control.test2_limit_high = new_high;
+       data->control.test2_limit_diff = new_diff;
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+               data->control.test2_limit_low);
+       if (result < 0) {
+               dev_err(dev, "Could not write f09_control_test2_limit_low to %#06x\n",
+                               fn_dev->fd.control_base_addr);
+               return result;
+       }
+
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+               data->control.test2_limit_high);
+       if (result < 0) {
+               dev_err(dev, "Could not write f09_control_test2_limit_high to %#06x\n",
+                               fn_dev->fd.control_base_addr);
+               return result;
+       }
+
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+               data->control.test2_limit_diff);
+       if (result < 0) {
+               dev_err(dev, "%s : Could not write f09_control_test2_limit_diff to 0x%x\n",
+                               __func__, fn_dev->fd.control_base_addr);
+               return result;
+       }
+
+       return count;
+
+}
+
+
+static ssize_t rmi_f09_test_number_control_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
+
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
        return snprintf(buf, PAGE_SIZE, "%u\n",
-                       data->query.Result_Register_Count);
+                       data->data.test_number_control);
 }
 
-module_init(rmi_f09_module_init);
-module_exit(rmi_f09_module_exit);
+static ssize_t rmi_f09_test_number_control_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct rmi_function_dev *fn_dev;
+       struct rmi_fn_09_data *data;
+       unsigned int new_value;
+       int result;
+
+       fn_dev = to_rmi_function_dev(dev);
+       data = fn_dev->data;
+       if (sscanf(buf, "%u", &new_value) != 1) {
+               dev_err(dev, "test_number_control_store has aninvalid len.\n");
+               return -EINVAL;
+       }
+
+       if (new_value > 1) {
+               dev_err(dev, "Invalid test_number_control bit %s.", buf);
+               return -EINVAL;
+       }
+       data->data.test_number_control = new_value;
+       result = rmi_write(fn_dev->rmi_dev, fn_dev->fd.control_base_addr,
+               data->data.test_number_control);
+       if (result < 0) {
+               dev_err(dev, "Could not write test_number_control_store to %#06x\n",
+                               fn_dev->fd.data_base_addr);
+               return result;
+       }
+
+       return count;
+}
+
+static struct device_attribute attrs[] = {
+       __ATTR(status, RMI_RW_ATTR,
+                  rmi_f09_status_show, rmi_f09_status_store),
+       __ATTR(limitRegisterCount, RMI_RO_ATTR,
+              rmi_f09_limit_register_count_show, NULL),
+       __ATTR(hostTestEnable, RMI_RW_ATTR,
+              rmi_f09_host_test_enable_show, rmi_f09_host_test_enable_store),
+       __ATTR(internalLimits, RMI_RO_ATTR,
+              rmi_f09_internal_limits_show, NULL),
+       __ATTR(resultRegisterCount, RMI_RO_ATTR,
+              rmi_f09_result_register_count_show, NULL),
+       __ATTR(overall_bist_result, RMI_RO_ATTR,
+              rmi_f09_overall_bist_result_show, NULL),
+       __ATTR(test_number_control, RMI_RW_ATTR,
+              rmi_f09_test_number_control_show,
+              rmi_f09_test_number_control_store),
+       __ATTR(test_result1, RMI_RO_ATTR,
+              rmi_f09_test_result1_show, NULL),
+       __ATTR(test_result2, RMI_RO_ATTR,
+              rmi_f09_test_result2_show, NULL),
+       __ATTR(run_bist, RMI_RW_ATTR,
+              rmi_f09_run_bist_show, rmi_f09_run_bist_store),
+       __ATTR(f09_control_test1, RMI_RW_ATTR,
+              rmi_f09_control_test1_show, rmi_f09_control_test1_store),
+       __ATTR(f09_control_test2, RMI_RW_ATTR,
+              rmi_f09_control_test2_show, rmi_f09_control_test2_store),
+};
+
+static int rmi_f09_alloc_memory(struct rmi_function_dev *fn_dev)
+{
+       struct rmi_fn_09_data *f09;
+
+       f09 = devm_kzalloc(&fn_dev->dev, sizeof(struct rmi_fn_09_data),
+                       GFP_KERNEL);
+       if (!f09) {
+               dev_err(&fn_dev->dev, "Failed to allocate rmi_fn_09_data.\n");
+               return -ENOMEM;
+       }
+       fn_dev->data = f09;
+
+       return 0;
+}
+
+static int rmi_f09_initialize(struct rmi_function_dev *fn_dev)
+{
+       struct rmi_device *rmi_dev = fn_dev->rmi_dev;
+       struct rmi_device_platform_data *pdata;
+       struct rmi_fn_09_data *f09 = fn_dev->data;
+       u16 query_base_addr;
+       int rc;
+
+
+       pdata = to_rmi_platform_data(rmi_dev);
+       query_base_addr = fn_dev->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(&fn_dev->dev, "Failed to read query register from %#06x\n",
+                               query_base_addr);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int rmi_f09_create_sysfs(struct rmi_function_dev *fn_dev)
+{
+       int attr_count = 0;
+       int rc;
+
+       dev_dbg(&fn_dev->dev, "Creating sysfs files.");
+       /* Set up sysfs device attributes. */
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               if (sysfs_create_file
+                   (&fn_dev->dev.kobj, &attrs[attr_count].attr) < 0) {
+                       dev_err(&fn_dev->dev, "Failed to create sysfs file for %s.",
+                            attrs[attr_count].attr.name);
+                       rc = -ENODEV;
+                       goto err_remove_sysfs;
+               }
+       }
+
+       return 0;
+
+err_remove_sysfs:
+       for (attr_count--; attr_count >= 0; attr_count--)
+               sysfs_remove_file(&fn_dev->dev.kobj,
+                                 &attrs[attr_count].attr);
+
+       return rc;
+}
+
+static int rmi_f09_probe(struct rmi_function_dev *fn_dev)
+{
+       int rc;
+
+       dev_info(&fn_dev->dev, "Intializing F09 values.");
+
+       rc = rmi_f09_alloc_memory(fn_dev);
+       if (rc < 0)
+               return rc;
+
+       rc = rmi_f09_initialize(fn_dev);
+       if (rc < 0)
+               return rc;
+
+       rc = rmi_f09_create_sysfs(fn_dev);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int rmi_f09_remove(struct rmi_function_dev *fn_dev)
+{
+       int attr_count;
+
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
+               sysfs_remove_file(&fn_dev->dev.kobj,
+                                 &attrs[attr_count].attr);
+
+       return 0;
+}
+
+static int rmi_f09_attention(struct rmi_function_dev *fn_dev,
+                                               unsigned long *irq_bits)
+{
+       struct rmi_device *rmi_dev = fn_dev->rmi_dev;
+       struct rmi_fn_09_data *data = fn_dev->data;
+       int error;
+       error = rmi_read_block(rmi_dev, fn_dev->fd.command_base_addr,
+                       (u8 *)&data->cmd, sizeof(data->cmd));
+
+       if (error < 0) {
+               dev_err(&fn_dev->dev, "Failed to read command register.\n");
+               return error;
+       }
+
+       if (data->cmd.run_bist) {
+               dev_warn(&rmi_dev->dev, "Command register not cleared: %#04x.\n",
+                       data->cmd.run_bist);
+       }
+       return 0;
+}
+
+static struct rmi_function_driver function_driver = {
+       .driver = {
+               .name = "rmi_f09",
+       },
+       .func = FUNCTION_NUMBER,
+       .probe = rmi_f09_probe,
+       .remove = rmi_f09_remove,
+       .attention = rmi_f09_attention,
+};
+
+module_rmi_function_driver(function_driver);
 
 MODULE_AUTHOR("Allie Xiong <axiong@Synaptics.com>");
 MODULE_DESCRIPTION("RMI F09 module");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(RMI_DRIVER_VERSION);
index 7530720..bb73602 100644 (file)
@@ -1,26 +1,27 @@
 /*
- * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011,2012 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.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
+#define FUNCTION_DATA f11_data
+#define FUNCTION_NUMBER 0x11
+
 #include <linux/kernel.h>
-#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fs.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/kconfig.h>
 #include <linux/rmi.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include "rmi_driver.h"
 
 #define F11_MAX_NUM_OF_SENSORS         8
 #define F11_MAX_NUM_OF_FINGERS         10
 #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 FINGER_STATE_MASK      0x03
+#define GET_FINGER_STATE(f_states, i) \
+       ((f_states[i / 4] >> (2 * (i % 4))) & FINGER_STATE_MASK)
 
 #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);
+#define NAME_BUFFER_SIZE 256
 
-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);
+/*
+ *  F11_INPUT_SOURCE_SENSOR is default mode of operation.
+ *  F11_INPUT_SOURCE_USER_APP is used when sensor images are being
+ *  sent over to the host and the host has a user space app that
+ *  processes the images and generates finger events
+ */
+#define F11_INPUT_SOURCE_SENSOR                0
+#define F11_INPUT_SOURCE_USER_APP      1
 
-static ssize_t rmi_fn_11_relreport_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf);
+/* character device name for fast image transfer (if enabled) */
+/*
+** the device_register will add another digit to this, making it "rawsensor0X"
+*/
+#define RAW_FINGER_DATA_CHAR_DEVICE_NAME "rawtouch0"
 
-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,
+static ssize_t f11_mode_show(struct device *dev,
                                     struct device_attribute *attr, char *buf);
 
-static ssize_t rmi_f11_rezero_store(struct device *dev,
+static ssize_t f11_mode_store(struct device *dev,
                                         struct device_attribute *attr,
-                                        const char *buf, size_t count);
-
-
-static struct device_attribute attrs[] = {
-       __ATTR(flip, RMI_RO_ATTR, rmi_fn_11_flip_show, rmi_fn_11_flip_store),
-       __ATTR(clip, RMI_RO_ATTR, rmi_fn_11_clip_show, rmi_fn_11_clip_store),
-       __ATTR(offset, RMI_RO_ATTR,
-               rmi_fn_11_offset_show, rmi_fn_11_offset_store),
-       __ATTR(swap, RMI_RO_ATTR, rmi_fn_11_swap_show, rmi_fn_11_swap_store),
-       __ATTR(relreport, RMI_RO_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_RO_ATTR, rmi_show_error, rmi_f11_rezero_store)
-};
+                             const char *buf,
+                             size_t count);
 
+/** A note about RMI4 F11 register structure.
+ *
+ *  There may be one or more individual 2D touch surfaces associated with an
+ * instance for F11.  For example, a handheld device might have a touchscreen
+ * display on the front, and a touchpad on the back.  F11 represents these touch
+ * surfaces as individual sensors, up to 7 on a given RMI4 device.
+ *
+ * The properties for
+ * a given sensor are described by its query registers.  The number of query
+ * registers and the layout of their contents are described by the F11 device
+ * queries as well as the per-sensor query information.  The query registers
+ * for sensor[n+1] immediately follow those for sensor[n], so the start address
+ * of the sensor[n+1] queries can only be computed if you know the size of the
+ * sensor[n] queries.  Because each of the sensors may have different
+ * properties, the size of the query registers for each sensor must be
+ * calculated on a sensor by sensor basis.
+ *
+ * Similarly, each sensor has control registers that govern its behavior.  The
+ * size and layout of the control registers for a given sensor can be determined
+ * by parsing that sensors query registers.  The control registers for
+ * sensor[n+1] immediately follow those for sensor[n], so you can only know
+ * the start address for the sensor[n+1] controls if you know the size (and
+ * location) of the sensor[n] controls.
+ *
+ * And in a likewise fashion, each sensor has data registers where it reports
+ * its touch data and other interesting stuff.  The size and layout of a
+ * sensors data registers must be determined by parsing its query registers.
+ * The data registers for sensor[n+1] immediately follow those for sensor[n],
+ * so you can only know the start address for the sensor[n+1] controls if you
+ * know the size (and location) of the sensor[n] controls.
+ *
+ * The short story is that we need to read and parse a lot of query
+ * registers in order to determine the attributes of a sensor[0].  Then
+ * we need to use that data to compute the size of the control and data
+ * registers for sensor[0].  Once we have that figured out, we can then do
+ * the same thing for each subsequent sensor.
+ *
+ * The end result is that we have a number of structs that aren't used to
+ * directly generate the input events, but their size, location and contents
+ * are critical to determining where the data we are interested in lives.
+ *
+ * At this time, the driver does not yet comprehend all possible F11
+ * configuration options, but it should be sufficient to cover 99% of RMI4 F11
+ * devices currently in the field.
+ */
 
-union f11_2d_commands {
-       struct {
+/**
+ * @rezero - writing 1 to this will cause the sensor to calibrate to the
+ * current capacitive state.
+ */
+struct f11_2d_commands {
                u8 rezero:1;
-       };
-       u8 reg;
-};
-
+       u8 reserved:7;
+} __attribute__((__packed__));
 
+/** This query is always present, and is on a per device basis.  All other
+ * queries are on a per-sensor basis.
+ *
+ * @nbr_of_sensors - the number of 2D sensors on the touch device.
+ * @has_query9 - indicates the F11_2D_Query9 register exists.
+ * @has_query11 - indicates the F11_2D_Query11 register exists.
+ * @has_query12 - indicates the F11_2D_Query12 register exists.
+ */
 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 {
+       u8 has_query12:1;
+       u8 has_query27:1;
+       u8 has_query28:1;
+} __attribute__((__packed__));
+
+/** Query registers 1 through 4 are always present.
+ * @number_of_fingers - describes the maximum number of fingers the 2-D sensor
+ * supports.
+ * @has_rel - the sensor supports relative motion reporting.
+ * @has_abs - the sensor supports absolute poition reporting.
+ * @has_gestures - the sensor supports gesture reporting.
+ * @has_sensitivity_adjust - the sensor supports a global sensitivity
+ * adjustment.
+ * @configurable - the sensor supports various configuration options.
+ * @num_of_x_electrodes -  the maximum number of electrodes the 2-D sensor
+ * supports on the X axis.
+ * @num_of_y_electrodes -  the maximum number of electrodes the 2-D sensor
+ * supports on the Y axis.
+ * @max_electrodes - the total number of X and Y electrodes that may be
+ * configured.
+ */
+struct f11_2d_sensor_info {
                        /* query1 */
                        u8 number_of_fingers:3;
                        u8 has_rel:1;
@@ -158,28 +167,66 @@ struct f11_2d_sensor_query {
                        u8 configurable:1;
                        /* query2 */
                        u8 num_of_x_electrodes:7;
+       u8 reserved_1:1;
                        /* query3 */
                        u8 num_of_y_electrodes:7;
+       u8 reserved_2:1;
                        /* query4 */
                        u8 max_electrodes:7;
-               };
-               u8 f11_2d_query1__4[4];
-       };
+       u8 reserved_3:1;
+} __attribute__((__packed__));
 
-       union {
-               struct {
-                       u8 abs_data_size:3;
+/** Query 5 - this is present if the has_abs bit is set.
+ *
+ * @abs_data_size - describes the format of data reported by the absolute
+ * data source.  Only one format (the kind used here) is supported at this
+ * time.
+ * @has_anchored_finger - then the sensor supports the high-precision second
+ * finger tracking provided by the manual tracking and motion sensitivity
+ * options.
+ * @has_adjust_hyst - the difference between the finger release threshold and
+ * the touch threshold.
+ * @has_dribble - the sensor supports the generation of dribble interrupts,
+ * which may be enabled or disabled with the dribble control bit.
+ * @has_bending_correction - Bending related data registers 28 and 36, and
+ * control register 52..57 are present.
+ * @has_large_object_suppression - control register 58 and data register 28
+ * exist.
+ * @has_jitter_filter - query 13 and control 73..76 exist.
+ */
+struct f11_2d_abs_info {
+       u8 abs_data_size:2;
                        u8 has_anchored_finger:1;
                        u8 has_adj_hyst:1;
                        u8 has_dribble:1;
-               };
-               u8 f11_2d_query5;
-       };
-
-       u8 f11_2d_query6;
+       u8 has_bending_correction:1;
+       u8 has_large_object_suppression:1;
+       u8 has_jitter_filter:1;
+} __attribute__((__packed__));
 
-       union {
-               struct {
+/** Gesture information queries 7 and 8 are present if has_gestures bit is set.
+ *
+ * @has_single_tap - a basic single-tap gesture is supported.
+ * @has_tap_n_hold - tap-and-hold gesture is supported.
+ * @has_double_tap - double-tap gesture is supported.
+ * @has_early_tap - early tap is supported and reported as soon as the finger
+ * lifts for any tap event that could be interpreted as either a single tap
+ * or as the first tap of a double-tap or tap-and-hold gesture.
+ * @has_flick - flick detection is supported.
+ * @has_press - press gesture reporting is supported.
+ * @has_pinch - pinch gesture detection is supported.
+ * @has_palm_det - the 2-D sensor notifies the host whenever a large conductive
+ * object such as a palm or a cheek touches the 2-D sensor.
+ * @has_rotate - rotation gesture detection is supported.
+ * @has_touch_shapes - TouchShapes are supported.  A TouchShape is a fixed
+ * rectangular area on the sensor that behaves like a capacitive button.
+ * @has_scroll_zones - scrolling areas near the sensor edges are supported.
+ * @has_individual_scroll_zones - if 1, then 4 scroll zones are supported;
+ * if 0, then only two are supported.
+ * @has_multi_finger_scroll - the multifinger_scrolling bit will be set when
+ * more than one finger is involved in a scrolling action.
+ */
+struct f11_2d_gesture_info {
                        u8 has_single_tap:1;
                        u8 has_tap_n_hold:1;
                        u8 has_double_tap:1;
@@ -187,7 +234,7 @@ struct f11_2d_sensor_query {
                        u8 has_flick:1;
                        u8 has_press:1;
                        u8 has_pinch:1;
-                       u8 padding:1;
+       u8 has_chiral:1;
 
                        u8 has_palm_det:1;
                        u8 has_rotate:1;
@@ -195,25 +242,425 @@ struct f11_2d_sensor_query {
                        u8 has_scroll_zones:1;
                        u8 has_individual_scroll_zones:1;
                        u8 has_multi_finger_scroll:1;
-               };
-               u8 f11_2d_query7__8[2];
-       };
+       u8 has_mf_edge_motion:1;
+       u8 has_mf_scroll_inertia:1;
+} __attribute__((__packed__));
 
-       /* Empty */
-       u8 f11_2d_query9;
+/** Utility for checking bytes in the gesture info registers.  This is done
+ * often enough that we put it here to declutter the conditionals.
+ */
+static bool has_gesture_bits(const struct f11_2d_gesture_info *info,
+                            const u8 byte) {
+       return ((u8 *) info)[byte] != 0;
+}
 
-       union {
-               struct {
+/**
+ * @has_pen - detection of a stylus is supported and registers F11_2D_Ctrl20
+ * and F11_2D_Ctrl21 exist.
+ * @has_proximity - detection of fingers near the sensor is supported and
+ * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist.
+ * @has_palm_det_sensitivity -  the sensor supports the palm detect sensitivity
+ * feature and register F11_2D_Ctrl27 exists.
+ * @has_two_pen_thresholds - is has_pen is also set, then F11_2D_Ctrl35 exists.
+ * @has_contact_geometry - the sensor supports the use of contact geometry to
+ * map absolute X and Y target positions and registers F11_2D_Data18.* through
+ * F11_2D_Data27 exist.
+ */
+struct f11_2d_query9 {
+       u8 has_pen:1;
+       u8 has_proximity:1;
+       u8 has_palm_det_sensitivity:1;
+       u8 has_suppress_on_palm_detect:1;
+       u8 has_two_pen_thresholds:1;
+       u8 has_contact_geometry:1;
+       u8 has_pen_hover_discrimination:1;
+       u8 has_pen_filters:1;
+} __attribute__((__packed__));
+
+/** Touch shape info (query 10) is present if has_touch_shapes is set.
+ *
+ * @nbr_touch_shapes - the total number of touch shapes supported.
+ */
+struct f11_2d_ts_info {
                        u8 nbr_touch_shapes:5;
-               };
-               u8 f11_2d_query10;
-       };
+       u8 reserved:3;
+} __attribute__((__packed__));
+
+/** Query 11 is present if the has_query11 bit is set in query 0.
+ *
+ * @has_z_tuning - if set, the sensor supports Z tuning and registers
+ * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist.
+ * @has_algorithm_selection - controls choice of noise suppression algorithm
+ * @has_w_tuning - the sensor supports Wx and Wy scaling and registers
+ * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist.
+ * @has_pitch_info - the X and Y pitches of the sensor electrodes can be
+ * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist.
+ * @has_finger_size -  the default finger width settings for the
+ * sensor can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44
+ * exist.
+ * @has_segmentation_aggressiveness - the sensor’s ability to distinguish
+ * multiple objects close together can be configured and register F11_2D_Ctrl45
+ * exists.
+ * @has_XY_clip -  the inactive outside borders of the sensor can be
+ * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist.
+ * @has_drumming_filter - the sensor can be configured to distinguish
+ * between a fast flick and a quick drumming movement and registers
+ * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist.
+ */
+struct f11_2d_query11 {
+       u8 has_z_tuning:1;
+       u8 has_algorithm_selection:1;
+       u8 has_w_tuning:1;
+       u8 has_pitch_info:1;
+       u8 has_finger_size:1;
+       u8 has_segmentation_aggressiveness:1;
+       u8 has_XY_clip:1;
+       u8 has_drumming_filter:1;
+} __attribute__((__packed__));
+
+/**
+ * @has_gapless_finger - control registers relating to gapless finger are
+ * present.
+ * @has_gapless_finger_tuning - additional control and data registers relating
+ * to gapless finger are present.
+ * @has_8bit_w - larger W value reporting is supported.
+ * @has_adjustable_mapping - TBD
+ * @has_info2 - the general info query14 is present
+ * @has_physical_props - additional queries describing the physical properties
+ * of the sensor are present.
+ * @has_finger_limit - indicates that F11 Ctrl 80 exists.
+ * @has_linear_coeff - indicates that F11 Ctrl 81 exists.
+ */
+struct f11_2d_query12 {
+       u8 has_gapless_finger:1;
+       u8 has_gapless_finger_tuning:1;
+       u8 has_8bit_w:1;
+       u8 has_adjustable_mapping:1;
+       u8 has_info2:1;
+       u8 has_physical_props:1;
+       u8 has_finger_limit:1;
+       u8 has_linear_coeff_2:1;
+} __attribute__((__packed__));
+
+/** This register is present if Query 5's has_jitter_filter bit is set.
+ * @jitter_window_size - used by Design Studio 4.
+ * @jitter_filter_type - used by Design Studio 4.
+ */
+struct f11_2d_query13 {
+       u8 jtter_window_size:5;
+       u8 jitter_filter_type:2;
+       u8 reserved:1;
+} __attribute__((__packed__));
+
+/** This register is present if query 12's has_general_info2 flag is set.
+ *
+ * @light_control - Indicates what light/led control features are present, if
+ * any.
+ * @is_clear - if set, this is a clear sensor (indicating direct pointing
+ * application), otherwise it's opaque (indicating indirect pointing).
+ * @clickpad_props - specifies if this is a clickpad, and if so what sort of
+ * mechanism it uses
+ * @mouse_buttons - specifies the number of mouse buttons present (if any).
+ * @has_advanced_gestures - advanced driver gestures are supported.
+ */
+struct f11_2d_query14 {
+       u8 light_control:2;
+       u8 is_clear:1;
+       u8 clickpad_props:2;
+       u8 mouse_buttons:2;
+       u8 has_advanced_gestures:1;
+} __attribute__((__packed__));
+
+#define F11_LIGHT_CTL_NONE 0x00
+#define F11_LUXPAD        0x01
+#define F11_DUAL_MODE      0x02
+
+#define F11_NOT_CLICKPAD     0x00
+#define F11_HINGED_CLICKPAD  0x01
+#define F11_UNIFORM_CLICKPAD 0x02
+
+/** See notes above for information about specific query register sets.
+ */
+struct f11_2d_sensor_queries {
+       struct f11_2d_sensor_info info;
+
+       struct f11_2d_abs_info abs_info;
+
+       u8 f11_2d_query6;
+
+       struct f11_2d_gesture_info gesture_info;
+
+       struct f11_2d_query9 query9;
+
+       struct f11_2d_ts_info ts_info;
+
+       struct f11_2d_query11 features_1;
+
+       struct f11_2d_query12 features_2;
+
+       struct f11_2d_query13 jitter_filter;
+
+       struct f11_2d_query14 info_2;
 };
 
-struct f11_2d_data_0 {
-       u8 finger_n;
+/**
+ * @reporting_mode - controls how often finger position data is reported.
+ * @abs_pos_filt - when set, enables various noise and jitter filtering
+ * algorithms for absolute reports.
+ * @rel_pos_filt - when set, enables various noise and jitter filtering
+ * algorithms for relative reports.
+ * @rel_ballistics - enables ballistics processing for the relative finger
+ * motion on the 2-D sensor.
+ * @dribble - enables the dribbling feature.
+ * @report_beyond_clip - when this is set, fingers outside the active area
+ * specified by the x_clip and y_clip registers will be reported, but with
+ * reported finger position clipped to the edge of the active area.
+ * @palm_detect_thresh - the threshold at which a wide finger is considered a
+ * palm. A value of 0 inhibits palm detection.
+ * @motion_sensitivity - specifies the threshold an anchored finger must move
+ * before it is considered no longer anchored.  High values mean more
+ * sensitivity.
+ * @man_track_en - for anchored finger tracking, whether the host (1) or the
+ * device (0) determines which finger is the tracked finger.
+ * @man_tracked_finger - when man_track_en is 1, specifies whether finger 0 or
+ * finger 1 is the tracked finger.
+ * @delta_x_threshold - 2-D position update interrupts are inhibited unless
+ * the finger moves more than a certain threshold distance along the X axis.
+ * @delta_y_threshold - 2-D position update interrupts are inhibited unless
+ * the finger moves more than a certain threshold distance along the Y axis.
+ * @velocity - When rel_ballistics is set, this register defines the
+ * velocity ballistic parameter applied to all relative motion events.
+ * @acceleration - When rel_ballistics is set, this register defines the
+ * acceleration ballistic parameter applied to all relative motion events.
+ * @sensor_max_x_pos - the maximum X coordinate reported by the sensor.
+ * @sensor_max_y_pos - the maximum Y coordinate reported by the sensor.
+ */
+struct f11_2d_ctrl0_9 {
+       /* F11_2D_Ctrl0 */
+       u8 reporting_mode:3;
+       u8 abs_pos_filt:1;
+       u8 rel_pos_filt:1;
+       u8 rel_ballistics:1;
+       u8 dribble:1;
+       u8 report_beyond_clip:1;
+       /* F11_2D_Ctrl1 */
+       u8 palm_detect_thres:4;
+       u8 motion_sensitivity:2;
+       u8 man_track_en:1;
+       u8 man_tracked_finger:1;
+       /* F11_2D_Ctrl2 and 3 */
+       u8 delta_x_threshold:8;
+       u8 delta_y_threshold:8;
+       /* F11_2D_Ctrl4 and 5 */
+       u8 velocity:8;
+       u8 acceleration:8;
+       /* F11_2D_Ctrl6 thru 9 */
+       u16 sensor_max_x_pos:12;
+       u8 ctrl7_reserved:4;
+       u16 sensor_max_y_pos:12;
+       u8 ctrl9_reserved:4;
+} __attribute__((__packed__));
+
+/**
+ * @single_tap_int_enable - enable tap gesture recognition.
+ * @tap_n_hold_int_enable - enable tap-and-hold gesture recognition.
+ * @double_tap_int_enable - enable double-tap gesture recognition.
+ * @early_tap_int_enable - enable early tap notification.
+ * @flick_int_enable - enable flick detection.
+ * @press_int_enable - enable press gesture recognition.
+ * @pinch_int_enable - enable pinch detection.
+ */
+struct f11_2d_ctrl10 {
+       u8 single_tap_int_enable:1;
+       u8 tap_n_hold_int_enable:1;
+       u8 double_tap_int_enable:1;
+       u8 early_tap_int_enable:1;
+       u8 flick_int_enable:1;
+       u8 press_int_enable:1;
+       u8 pinch_int_enable:1;
+       u8 reserved:1;
+} __attribute__((__packed__));
+
+/**
+ * @palm_detect_int_enable - enable palm detection feature.
+ * @rotate_int_enable - enable rotate gesture detection.
+ * @touch_shape_int_enable - enable the TouchShape feature.
+ * @scroll_zone_int_enable - enable scroll zone reporting.
+ * @multi_finger_scroll_int_enable - enable the multfinger scroll feature.
+ */
+struct f11_2d_ctrl11 {
+       u8 palm_detect_int_enable:1;
+       u8 rotate_int_enable:1;
+       u8 touch_shape_int_enable:1;
+       u8 scroll_zone_int_enable:1;
+       u8 multi_finger_scroll_int_enable:1;
+       u8 reserved:3;
+} __attribute__((__packed__));
+
+/**
+ * @sens_adjustment - allows a host to alter the overall sensitivity of a
+ * 2-D sensor. A positive value in this register will make the sensor more
+ * sensitive than the factory defaults, and a negative value will make it
+ * less sensitive.
+ * @hyst_adjustment - increase the touch/no-touch hysteresis by 2 Z-units for
+ * each one unit increment in this setting.
+ */
+struct f11_2d_ctrl14 {
+       s8 sens_adjustment:5;
+       u8 hyst_adjustment:3;
+} __attribute__((__packed__));
+
+/**
+ * @max_tap_time - the maximum duration of a tap, in 10-millisecond units.
+ */
+struct f11_2d_ctrl15 {
+       u8 max_tap_time:8;
+} __attribute__((__packed__));
+
+/**
+ * @min_press_time - The minimum duration required for stationary finger(s) to
+ * generate a press gesture, in 10-millisecond units.
+ */
+struct f11_2d_ctrl16 {
+       u8 min_press_time:8;
+} __attribute__((__packed__));
+
+/**
+ * @max_tap_distance - Determines the maximum finger movement allowed during
+ * a tap, in 0.1-millimeter units.
+ */
+struct f11_2d_ctrl17 {
+       u8 max_tap_distance:8;
+} __attribute__((__packed__));
+
+/**
+ * @min_flick_distance - the minimum finger movement for a flick gesture,
+ * in 1-millimeter units.
+ * @min_flick_speed - the minimum finger speed for a flick gesture, in
+ * 10-millimeter/second units.
+ */
+struct f11_2d_ctrl18_19 {
+       u8 min_flick_distance:8;
+       u8 min_flick_speed:8;
+} __attribute__((__packed__));
+
+/**
+ * @pen_detect_enable - enable reporting of stylus activity.
+ * @pen_jitter_filter_enable - Setting this enables the stylus anti-jitter
+ * filter.
+ * @pen_z_threshold - This is the stylus-detection lower threshold. Smaller
+ * values result in higher sensitivity.
+ */
+struct f11_2d_ctrl20_21 {
+       u8 pen_detect_enable:1;
+       u8 pen_jitter_filter_enable:1;
+       u8 ctrl20_reserved:6;
+       u8 pen_z_threshold:8;
+} __attribute__((__packed__));
+
+/**
+ * These are not accessible through sysfs yet.
+ *
+ * @proximity_detect_int_en - enable proximity detection feature.
+ * @proximity_jitter_filter_en - enables an anti-jitter filter on proximity
+ * data.
+ * @proximity_detection_z_threshold - the threshold for finger-proximity
+ * detection.
+ * @proximity_delta_x_threshold - In reduced-reporting modes, this is the
+ * threshold for proximate-finger movement in the direction parallel to the
+ * X-axis.
+ * @proximity_delta_y_threshold - In reduced-reporting modes, this is the
+ * threshold for proximate-finger movement in the direction parallel to the
+ * Y-axis.
+ * * @proximity_delta_Z_threshold - In reduced-reporting modes, this is the
+ * threshold for proximate-finger movement in the direction parallel to the
+ * Z-axis.
+ */
+struct f11_2d_ctrl22_26 {
+       /* control 22 */
+       u8 proximity_detect_int_en:1;
+       u8 proximity_jitter_filter_en:1;
+       u8 f11_2d_ctrl6_b3__7:6;
+
+       /* control 23 */
+       u8 proximity_detection_z_threshold;
+
+       /* control 24 */
+       u8 proximity_delta_x_threshold;
+
+       /* control 25 */
+       u8 proximity_delta_y_threshold;
+
+       /* control 26 */
+       u8 proximity_delta_z_threshold;
+} __attribute__((__packed__));
+
+/**
+ * @palm_detecy_sensitivity - When this value is small, smaller objects will
+ * be identified as palms; when this value is large, only larger objects will
+ * be identified as palms. 0 represents the factory default.
+ * @suppress_on_palm_detect - when set, all F11 interrupts except palm_detect
+ * are suppressed while a palm is detected.
+ */
+struct f11_2d_ctrl27 {
+       s8 palm_detect_sensitivity:4;
+       u8 suppress_on_palm_detect:1;
+       u8 f11_2d_ctrl27_b5__7:3;
+} __attribute__((__packed__));
+
+/**
+ * @multi_finger_scroll_mode - allows choice of multi-finger scroll mode and
+ * determines whether and how X or Y displacements are reported.
+ * @edge_motion_en - enables the edge_motion feature.
+ * @multi_finger_scroll_momentum - controls the length of time that scrolling
+ * continues after fingers have been lifted.
+ */
+struct f11_2d_ctrl28 {
+       u8 multi_finger_scroll_mode:2;
+       u8 edge_motion_en:1;
+       u8 f11_2d_ctrl28b_3:1;
+       u8 multi_finger_scroll_momentum:4;
+} __attribute__((__packed__));
+
+/**
+ * @z_touch_threshold - Specifies the finger-arrival Z threshold. Large values
+ * may cause smaller fingers to be rejected.
+ * @z_touch_hysteresis - Specifies the difference between the finger-arrival
+ * Z threshold and the finger-departure Z threshold.
+ */
+struct f11_2d_ctrl29_30 {
+       u8 z_touch_threshold;
+       u8 z_touch_hysteresis;
+} __attribute__((__packed__));
+
+
+struct f11_2d_ctrl {
+       struct f11_2d_ctrl0_9            *ctrl0_9;
+       u16                             ctrl0_9_address;
+       struct f11_2d_ctrl10            *ctrl10;
+       struct f11_2d_ctrl11            *ctrl11;
+       u8                              ctrl12_size;
+       struct f11_2d_ctrl14            *ctrl14;
+       struct f11_2d_ctrl15            *ctrl15;
+       struct f11_2d_ctrl16            *ctrl16;
+       struct f11_2d_ctrl17            *ctrl17;
+       struct f11_2d_ctrl18_19         *ctrl18_19;
+       struct f11_2d_ctrl20_21         *ctrl20_21;
+       struct f11_2d_ctrl22_26         *ctrl22_26;
+       struct f11_2d_ctrl27            *ctrl27;
+       struct f11_2d_ctrl28            *ctrl28;
+       struct f11_2d_ctrl29_30         *ctrl29_30;
 };
 
+/**
+ * @x_msb - top 8 bits of X finger position.
+ * @y_msb - top 8 bits of Y finger position.
+ * @x_lsb - bottom 4 bits of X finger position.
+ * @y_lsb - bottom 4 bits of Y finger position.
+ * @w_y - contact patch width along Y axis.
+ * @w_x - contact patch width along X axis.
+ * @z - finger Z value (proxy for pressure).
+ */
 struct f11_2d_data_1_5 {
        u8 x_msb;
        u8 y_msb;
@@ -222,13 +669,26 @@ struct f11_2d_data_1_5 {
        u8 w_y:4;
        u8 w_x:4;
        u8 z;
-};
+} __attribute__((__packed__));
 
+/**
+ * @delta_x - relative motion along X axis.
+ * @delta_y - relative motion along Y axis.
+ */
 struct f11_2d_data_6_7 {
        s8 delta_x;
        s8 delta_y;
-};
-
+} __attribute__((__packed__));
+
+/**
+ * @single_tap - a single tap was recognized.
+ * @tap_and_hold - a tap-and-hold gesture was recognized.
+ * @double_tap - a double tap gesture was recognized.
+ * @early_tap - a tap gesture might be happening.
+ * @flick - a flick gesture was detected.
+ * @press - a press gesture was recognized.
+ * @pinch - a pinch gesture was detected.
+ */
 struct f11_2d_data_8 {
        u8 single_tap:1;
        u8 tap_and_hold:1;
@@ -237,49 +697,87 @@ struct f11_2d_data_8 {
        u8 flick:1;
        u8 press:1;
        u8 pinch:1;
-};
-
+} __attribute__((__packed__));
+
+/**
+ * @palm_detect - a palm or other large object is in contact with the sensor.
+ * @rotate - a rotate gesture was detected.
+ * @shape - a TouchShape has been activated.
+ * @scrollzone - scrolling data is available.
+ * @finger_count - number of fingers involved in the reported gesture.
+ */
 struct f11_2d_data_9 {
        u8 palm_detect:1;
        u8 rotate:1;
        u8 shape:1;
        u8 scrollzone:1;
        u8 finger_count:3;
-};
+} __attribute__((__packed__));
 
+/**
+ * @pinch_motion - when a pinch gesture is detected, this is the change in
+ * distance between the two fingers since this register was last read.
+ */
 struct f11_2d_data_10 {
-       u8 pinch_motion;
-};
-
+       s8 pinch_motion;
+} __attribute__((__packed__));
+
+/**
+ * @x_flick_dist - when a flick gesture is detected,  the distance of flick
+ * gesture in X direction.
+ * @y_flick_dist - when a flick gesture is detected,  the distance of flick
+ * gesture in Y direction.
+ * @flick_time - the total time of the flick gesture, in 10ms units.
+ */
 struct f11_2d_data_10_12 {
-       u8 x_flick_dist;
-       u8 y_flick_dist;
+       s8 x_flick_dist;
+       s8 y_flick_dist;
        u8 flick_time;
-};
-
+} __attribute__((__packed__));
+
+/**
+ * @motion - when a rotate gesture is detected, the accumulated distance
+ * of the rotate motion. Clockwise motion is positive and counterclockwise
+ * motion is negative.
+ * @finger_separation - when a rotate gesture is detected, the distance
+ * between the fingers.
+ */
 struct f11_2d_data_11_12 {
-       u8 motion;
+       s8 motion;
        u8 finger_separation;
-};
+} __attribute__((__packed__));
 
+/**
+ * @shape_n - a bitmask of the currently activate TouchShapes (if any).
+ */
 struct f11_2d_data_13 {
        u8 shape_n;
-};
+} __attribute__((__packed__));
 
+/**
+ * @horizontal - chiral scrolling distance in the X direction.
+ * @vertical - chiral scrolling distance in the Y direction.
+ */
 struct f11_2d_data_14_15 {
-       u8 horizontal;
-       u8 vertical;
-};
-
+       s8 horizontal;
+       s8 vertical;
+} __attribute__((__packed__));
+
+/**
+ * @x_low - scroll zone motion along the lower edge of the sensor.
+ * @y_right - scroll zone motion along the right edge of the sensor.
+ * @x_upper - scroll zone motion along the upper edge of the sensor.
+ * @y_left - scroll zone motion along the left edge of the sensor.
+ */
 struct f11_2d_data_14_17 {
-       u8 x_low;
-       u8 y_right;
-       u8 x_upper;
-       u8 y_left;
-};
+       s8 x_low;
+       s8 y_right;
+       s8 x_upper;
+       s8 y_left;
+} __attribute__((__packed__));
 
 struct f11_2d_data {
-       const struct f11_2d_data_0      *f_state;
+       u8                              *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;
@@ -292,28 +790,111 @@ struct f11_2d_data {
        const struct f11_2d_data_14_17  *scroll_zones;
 };
 
+/**
+ * @axis_align - controls parameters that are useful in system prototyping
+ * and bring up.
+ * @sens_query - query registers for this particular sensor.
+ * @data - the data reported by this sensor, mapped into a collection of
+ * structs.
+ * @max_x - The maximum X coordinate that will be reported by this sensor.
+ * @max_y - The maximum Y coordinate that will be reported by this sensor.
+ * @nbr_fingers - How many fingers can this sensor report?
+ * @data_pkt - buffer for data reported by this sensor.
+ * @pkt_size - number of bytes in that buffer.
+ * @sensor_index - identifies this particular 2D touch sensor
+ * @type_a - some early RMI4 2D sensors do not reliably track the finger
+ * position when two fingers are on the device.  When this is true, we
+ * assume we have one of those sensors and report events appropriately.
+ * @sensor_type - indicates whether we're touchscreen or touchpad.
+ * @input - input device for absolute pointing stream
+ * @mouse_input - input device for relative pointing stream.
+ * @input_phys - buffer for the absolute phys name for this sensor.
+ * @input_mouse_phys - buffer for the relative phys name for this sensor.
+ * @debugfs_flip - inverts one or both axes.  Useful in prototyping new
+ * systems.
+ * @debugfs_flip - coordinate clipping range for one or both axes.  Useful in
+ * prototyping new systems.
+ * @debugfs_delta_threshold - adjusts motion sensitivity for relative reports
+ * and (in reduced reporting mode) absolute reports.  Useful in prototyping new
+ * systems.
+ * @debugfs_offset - offsets one or both axes.  Useful in prototyping new
+ * systems.
+ * @debugfs_swap - swaps X and Y axes.  Useful in prototyping new systems.
+ * @debugfs_type_a - forces type A behavior.  Useful in bringing up old systems
+ * when you're not sure if you've got a Type A or Type B sensor.
+ * @input_mode - switches between normal input from the sensor(0), and input from Direct Touch (1)
+ * @input_phys_mouse - buffer for the relative phys name for this sensor.
+ */
 struct f11_2d_sensor {
        struct rmi_f11_2d_axis_alignment axis_align;
-       struct f11_2d_sensor_query sens_query;
+       struct f11_2d_sensor_queries 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&n