public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
@ 2011-07-01  5:19 Christopher Heiny
  2011-07-01  5:19 ` [PATCH 1/9] " Christopher Heiny
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

This patch implements a driver supporting Synaptics ClearPad and other
touchscreens that use the RMI4 protocol, as defined here:

    http://www.synaptics.com/sites/default/files/511-000136-01_revD.pdf

This patch is against the v2.6.38 tag of Linus' kernel tree, commit
521cb40b0c44418a4fd36dc633f575813d59a43d.

This patch completely supersedes the previous patch of 2011/03/30.  Quite a
few changes have been included in this patch.
      
    - bug fixes and changes based on input received for the 2011/03/30
      patch.  I'm not going to list them all here, but we have resolved
      all bugs and changes suggested for that patch, except as listed
      below.  Many thanks to all the folks who took the time review that
      code and make suggestions.
      
    - major reformatting, variable renaming, and other changes to meet
      kernel coding standards.  Checkpatch.pl should run with not complaints
      at all, not even warnings.
    
    - full support for all Synaptics RMI4 SPI products.
    
    - implementation of suspend/resume behavior.
    
    - improved error handling, particularly during initialization
    
    - improved memory management
    
    - extermination of printk, switching to pr_xxx (and dev_xxx where
      appropriate).
      
    - A major reduction in the amoung of INFO level messages generated.
    
    - Fixed Makefile and Kconfig.
    
What's not in this patch?
    - the RMI bus structure still isn't where we want it to be.  There's
      a lot of ad-hoc-ery going on to match sensor drivers to devices, and
      function drivers to the sensors.  We know it's a mess, but want to get
      the core sensing functionality solid before re-arranging the guts of
      the system. In our opinion, it's better to have a working driver with
      ugly architecture than a beautiful architecture that doesn't work.
      Obviously it's best to have a driver that's beautiful and works, all
      at the same time, so after one more functional patch later in July,
      we intend to address the architectural issue in the next few
      weeks after that.
      
    - a number of people suggested moving some header files to more sensible
      locations.  That's an excellent idea, but because we may wind up
      moving them around again when we update the architecture, we decided
      not to implement that in order to reduce the confusion among those
      folks already using this code.
      
    - full documentation - we've started this, but it is not complete by
      any means.

This patch supports a system having one or more RMI sensors attached to it.
Most devices have just a single touch sensor, but some have more than one.
An example is the Fuse concept phone, which has 4 RMI sensors in it).
Each sensor implements a number of RMI4 functions, which are best represented
as devices on the bus.

I2C functionality was previously ACK'ed by Jean Delvare on 2010/05/29.

We've broken this patch into 9 parts in order to keep the individual emails
down to a manageable size.  

    1/9 - core files implementing the bus and providing global definitions
          and platform data
    	  
    2/9 - the physical device interface drivers for I2C and SPI
      
    3/9 - the sensor level implementation files
    
    4/9 - Makefile, Kconfig, and doc file.
    
    5-9/9 - Function drivers for the following RMI4 functions
    		F01 device control
    		F05 analog data (stub)
    		F11 2D sensing
    		F19 capacitive buttons
    		F34 device reflash

The driver core manages the sensors on a device via the rmi bus (/sys/bus/rmi),
handles interfunction communications (mostly IRQ notifications from F01 to
other functions), and proxies register read/write requests to the appropriate
physical layer for a given sensor.

Individual sensors are presented on the bus as /sys/bus/rmi/devices/sensor00,
/sys/bus/rmi/devices/sensor01/, and so on.
      
Functions for each sensor are presented as devices next to that sensor, for
example /sys/bus/rmi/devices/sensor00f01, /sys/bus/rmi/devices/sensor00f11,
and so on.
      
Sensor driver instances are attached to the bus using the kernel device discovery
mechanism.  As described above, a future release will do the same for
function driver instances, but for now we use an ad hoc mechanism to match
functions to sensors.  Yes, we know it's ugly.

We chose this approach because almost all RMI4 functions are independent
of one another.  The sole exception is F01, and its primary interaction
with other functions is to notify them of the need to read or write data
from or to the sensor.  In the long term, this will allow 3rd parties to
implement additional RMI functions in a modular fashion, without having
to modify the core driver implementation or the implementation of unrelated
functions.


Comments and other feedback on this driver are welcomed.

Christopher Heiny
Bill Manson
Allie Xiong
Peichen Chang

Cc: Jean Delvare <khali@linux-fr.org>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

---

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 2/9] " Christopher Heiny
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_bus.c b/drivers/input/touchscreen/rmi_bus.c
new file mode 100644
index 0000000..155cb4f
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_bus.c
@@ -0,0 +1,383 @@
+/**
+ * Synaptics Register Mapped Interface (RMI4) - RMI Bus Module.
+ * Copyright (C) 2007 - 2011, Synaptics Incorporated
+ *
+ * Implements "rmi" bus per Documentation/driver-model/bus.txt
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+static const char busname[] = "rmi";
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+
+#include "rmi_drvr.h"
+#include "rmi.h"
+#include "rmi_bus.h"
+#include "rmi_platformdata.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+
+#define PDT_START_SCAN_LOCATION 0x00E9
+#define PDT_END_SCAN_LOCATION 0x0005
+#define PDT_ENTRY_SIZE 0x0006
+
+/* definitions for rmi bus */
+struct device rmi_bus_device;
+
+struct bus_type rmi_bus_type;
+EXPORT_SYMBOL(rmi_bus_type);
+
+/*
+ * This method is called, perhaps multiple times, whenever a new device or
+ * driver is added for this bus. It should return a nonzero value if the given
+ * device can be handled by the given driver. This function must be handled at
+ * the bus level, because that is where the proper logic exists; the core
+ * kernel cannot know how to match devices and drivers for every possible bus
+ * type The match function does a comparison between the hardware ID provided
+ * by the device itself and the IDs supported by the driver.
+ *
+ */
+static int rmi_bus_match(struct device *dev, struct device_driver *driver)
+{
+	dev_dbg(dev, "%s: Matching driver %s against bus %s for rmi bus.\n",
+		 __func__, driver->name, dev->bus->name);
+	return !strcmp(dev->bus->name, driver->name);
+}
+
+/* Stub for now.
+ */
+static int rmi_bus_suspend(struct device *dev, pm_message_t state)
+{
+	dev_dbg(dev, "%s: RMI bus suspending.", __func__);
+	return 0;
+}
+
+/* Stub for now.
+ */
+static int rmi_bus_resume(struct device *dev)
+{
+	dev_dbg(dev, "%s: RMI bus resuming.", __func__);
+	return 0;
+}
+
+/*
+ * This method is called, whenever a new device is added for this bus.
+ * It will scan the devices PDT to get the function $01 query, control,
+ * command and data regsiters so that it can create a function $01 (sensor)
+ * device for the new physical device. It also caches the PDT for later use by
+ * other functions that are created for the device. For example, if a function
+ * $11 is found it will need the query, control, command and data register
+ * addresses for that function. The new function could re-scan the PDT but
+ * since it is being done here we can cache it and keep it around.
+ *
+ * TODO: If the device is reset or some action takes place that would invalidate
+ * the PDT - such as a reflash of the firmware - then the device should be
+ * re-added to the bus and the PDT re-scanned and cached.
+ *
+ */
+int rmi_register_sensor(struct rmi_phys_driver *rpd,
+			struct rmi_sensordata *sensordata)
+{
+	int i;
+	int pdt_entry_count = 0;
+	struct rmi_sensor_device *rmi_sensor_dev = NULL;
+	struct rmi_function_descriptor rmi_fd;
+	int retval;
+	static int index;
+
+	/* Make sure we have a read, write, read_multiple, write_multiple
+	   function pointers from whatever physical layer the sensor is on.
+	 */
+	if (!rpd->name) {
+		pr_err("%s: Physical driver must specify a name", __func__);
+		return -EINVAL;
+	}
+	if (!rpd->write) {
+		pr_err("%s: Physical driver %s must specify a writer.",
+		       __func__, rpd->name);
+		return -EINVAL;
+	}
+	if (!rpd->read) {
+		pr_err("%s: Physical driver %s must specify a reader.",
+		       __func__, rpd->name);
+		return -EINVAL;
+	}
+	if (!rpd->write_multiple) {
+		pr_err("%s: Physical driver %s must specify a "
+		       "multiple writer.", __func__, rpd->name);
+		return -EINVAL;
+	}
+	if (!rpd->read_multiple) {
+		pr_err("%s: Physical driver %s must specify a "
+		       "multiple reader.", __func__, rpd->name);
+		return -EINVAL;
+	}
+
+	/* Get some information from the device */
+	pr_debug("%s: Identifying sensors by presence of F01...", __func__);
+
+	/* Scan the page descriptor table until we find F01.  If we find that,
+	 * we assume that we can reliably talk to this sensor.
+	 */
+	for (i = PDT_START_SCAN_LOCATION;
+	     i >= PDT_END_SCAN_LOCATION; i -= PDT_ENTRY_SIZE) {
+		retval = rpd->read_multiple(rpd, i, (char *)&rmi_fd,
+					    sizeof(rmi_fd));
+		if (retval) {
+			/* failed to read next PDT entry - end PDT
+			   scan - this may result in an incomplete set
+			   of recognized functions - should probably
+			   return an error but the driver may still be
+			   viable for diagnostics and debugging so let's
+			   let it continue. */
+			pr_err
+			    ("%s: Read Error %d when reading next PDT entry - "
+			     "ending PDT scan.", __func__, retval);
+			break;
+		}
+
+		if (rmi_fd.function_number == 0x00
+		    || rmi_fd.function_number == 0xff) {
+			/* A zero or 0xff in the function number
+			   signals the end of the PDT */
+			pr_debug("%s:   Found End of PDT.", __func__);
+			break;
+		}
+		pdt_entry_count++;
+		if ((rmi_fd.function_number & 0xff) == 0x01) {
+			pr_debug("%s: F01 Found - RMI Device Control",
+				 __func__);
+
+			/* This appears to be a valid device, so create a sensor
+			 * device and sensor driver for it. */
+			rmi_sensor_dev =
+			    kzalloc(sizeof(*rmi_sensor_dev), GFP_KERNEL);
+			if (!rmi_sensor_dev) {
+				pr_err
+				    ("%s: Error allocating memory for "
+				     "rmi_sensor_device",
+				     __func__);
+				retval = -ENOMEM;
+				goto exit_fail;
+			}
+			rmi_sensor_dev->dev.bus = &rmi_bus_type;
+
+			retval =
+			    rmi_sensor_register_device(rmi_sensor_dev, index++);
+			if (retval < 0) {
+				pr_err
+				    ("%s: Error %d registering sensor device.",
+				     __func__, retval);
+				goto exit_fail;
+			}
+
+			rmi_sensor_dev->driver =
+			    rmi_sensor_create_driver(rmi_sensor_dev, rpd,
+						     sensordata);
+			if (!rmi_sensor_dev->driver) {
+				pr_err("%s: Failed to create sensor driver.",
+				       __func__);
+				goto exit_fail;
+			}
+
+			retval =
+			    rmi_sensor_register_driver(rmi_sensor_dev->driver);
+			if (retval < 0) {
+				pr_err
+				    ("%s: Error %d registering sensor driver.",
+				     __func__, retval);
+				goto exit_fail;
+			}
+
+			/* link the attn fn in the rpd to the sensor attn fn */
+			rpd->sensor = rmi_sensor_dev->driver;
+			rpd->attention = rmi_sensor_dev->driver->attention;
+
+			/* All done with this sensor, fall out of scan loop. */
+			break;
+		} else {
+			/* Just print out the function found for now */
+			pr_debug("%s: Found Function %02x - Ignored.\n",
+				 __func__, rmi_fd.function_number & 0xff);
+		}
+	}
+
+	/* If we actually found a sensor, keep it around. */
+	if (rmi_sensor_dev) {
+		pr_debug("%s: Registered sensor drivers.", __func__);
+		retval = 0;
+	} else {
+		pr_err("%s: Failed to find sensor. PDT contained %d entries.",
+		       __func__, pdt_entry_count);
+		retval = -ENODEV;
+		goto exit_fail;
+	}
+
+	return 0;
+
+exit_fail:
+	if (rmi_sensor_dev)
+		rmi_sensor_destroy_driver(rmi_sensor_dev->driver);
+	kfree(rmi_sensor_dev);
+	return retval;
+}
+EXPORT_SYMBOL(rmi_register_sensor);
+
+int rmi_unregister_sensors(struct rmi_phys_driver *rpd)
+{
+	if (rpd->sensor) {
+		pr_warning
+		    ("%s: WARNING: unregister of %s while %s still attached.",
+		     __func__, rpd->name, rpd->sensor->drv.name);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rmi_unregister_sensors);
+
+static void rmi_bus_dev_release(struct device *dev)
+{
+	pr_debug("rmi bus device release\n");
+}
+
+int rmi_register_bus_device(struct device *rmibusdev)
+{
+	pr_debug("%s: Registering RMI4 bus device.\n", __func__);
+
+	/* Here, we simply fill in some of the embedded device structure
+	 * fields (which individual drivers should not need to know about),
+	 * and register the device with the driver core. */
+
+	rmibusdev->bus = &rmi_bus_type;
+	rmibusdev->parent = &rmi_bus_device;
+	rmibusdev->release = rmi_bus_dev_release;
+	dev_set_name(rmibusdev, "rmi");
+
+	/* If we wanted to add bus-specific attributes to the device,
+	 * we could do so here. */
+
+	return device_register(rmibusdev);
+}
+EXPORT_SYMBOL(rmi_register_bus_device);
+
+void rmi_unregister_bus_device(struct device *rmibusdev)
+{
+	dev_dbg(rmibusdev, "%s: Unregistering bus device.", __func__);
+
+	device_unregister(rmibusdev);
+}
+EXPORT_SYMBOL(rmi_unregister_bus_device);
+
+static int __init rmi_bus_init(void)
+{
+	int status = 0;
+
+	pr_info("%s: RMI Bus Driver Init", __func__);
+
+	/* Register the rmi bus */
+	rmi_bus_type.name = busname;
+	rmi_bus_type.match = rmi_bus_match;
+	rmi_bus_type.suspend = rmi_bus_suspend;
+	rmi_bus_type.resume = rmi_bus_resume;
+	status = bus_register(&rmi_bus_type);
+	if (status < 0) {
+		pr_err("%s: Error %d registering the rmi bus.", __func__,
+		       status);
+		goto err_exit;
+	}
+	pr_debug("%s: successfully registered bus.", __func__);
+
+	return 0;
+err_exit:
+	return status;
+}
+
+static void __exit rmi_bus_exit(void)
+{
+	pr_debug("%s: RMI Bus Driver Exit.", __func__);
+
+	rmi_unregister_bus_device(&rmi_bus_device);
+	bus_unregister(&rmi_bus_type);
+}
+
+/* Utility routine to handle writes to read-only attributes.  Hopefully
+ * this will never happen, but if the user does something stupid, we don't
+ * want to accept it quietly (which is what can happen if you just put NULL
+ * for the attribute's store function).
+ */
+ssize_t rmi_store_error(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	dev_warn(dev,
+		"RMI4 WARNING: Attempt to write %d characters to read-only "
+		"attribute %s.", count, attr->attr.name);
+	return -EPERM;
+}
+
+/* Utility routine to handle reads of write-only attributes.  Hopefully
+ * this will never happen, but if the user does something stupid, we don't
+ * want to accept it quietly (which is what can happen if you just put NULL
+ * for the attribute's show function).
+ */
+ssize_t rmi_show_error(struct device *dev,
+		       struct device_attribute *attr,
+		       char *buf)
+{
+	dev_warn(dev,
+		 "RMI4 WARNING: Attempt to read from write-only attribute %s.",
+		 attr->attr.name);
+	return -EPERM;
+}
+
+/* Register a sensor driver on the bus.
+ */
+int rmi_bus_register_sensor_driver(struct rmi_sensor_driver *sensor_driver)
+{
+	int retval = 0;
+
+	sensor_driver->drv.bus = &rmi_bus_type;
+	retval = driver_register(&sensor_driver->drv);
+	return retval;
+}
+EXPORT_SYMBOL(rmi_bus_register_sensor_driver);
+
+/* Remove a sensor driver from the bus.
+ */
+void rmi_bus_unregister_sensor_driver(struct rmi_sensor_driver *sensor_driver)
+{
+	driver_unregister(&sensor_driver->drv);
+}
+EXPORT_SYMBOL(rmi_bus_unregister_sensor_driver);
+
+module_init(rmi_bus_init);
+module_exit(rmi_bus_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi_bus.h b/drivers/input/touchscreen/rmi_bus.h
new file mode 100644
index 0000000..66666ae
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_bus.h
@@ -0,0 +1,34 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) - RMI Bus Module Header.
+ * Copyright (C) 2007 - 2010, Synaptics Incorporated
+ *
+ */
+/*
+ *
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_BUS_H)
+#define _RMI_BUS_H
+
+#include "rmi_sensor.h"
+
+int rmi_bus_register_sensor_driver(struct rmi_sensor_driver *sensor_driver);
+void rmi_bus_unregister_sensor_driver(struct rmi_sensor_driver *sensor_driver);
+
+#endif
diff --git a/drivers/input/touchscreen/rmi.h b/drivers/input/touchscreen/rmi.h
new file mode 100644
index 0000000..7357819
--- /dev/null
+++ b/drivers/input/touchscreen/rmi.h
@@ -0,0 +1,72 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Header File.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_H)
+#define _RMI_H
+
+/*  RMI4 Protocol Support
+ */
+
+
+/* Every function on an RMI device is identified by a one byte function number.
+ * The hexadecimal representation of this byte is used in the function name.
+ * For example, the function identified by the byte 0x11 is referred to as
+ * F11 (or sometimes FN11).  In the extremely improbable event that F11 is no
+ * longer identified by 0x11, though, we provide these handy #defines.
+ */
+#define RMI_F01_INDEX 0x01
+#define RMI_F05_INDEX 0x05
+#define RMI_F11_INDEX 0x11
+#define RMI_F19_INDEX 0x19
+#define RMI_F34_INDEX 0x34
+#define RMI_F54_INDEX 0x54
+
+/* This byte has information about the communications protocol.  See the RMI4
+ * specification for details of what exactly is there.
+ */
+#define RMI_PROTOCOL_VERSION_ADDRESS 0xA0FD
+
+/* For each function present on the RMI device, we need to get the RMI4 Function
+ * Descriptor info from the Page Descriptor Table. This will give us the
+ * addresses for Query, Command, Control, Data and the Source Count (number
+ * of sources for this function) and the function id.
+ */
+struct rmi_function_descriptor {
+	unsigned char query_base_addr;
+	unsigned char command_base_addr;
+	unsigned char control_base_addr;
+	unsigned char data_base_addr;
+	unsigned char interrupt_source_count;
+	unsigned char function_number;
+};
+
+/* The product descriptor table starts here, and continues till we get
+ * a function ID of 0x00 or 0xFF.
+ */
+#define RMI_PDT_START_ADDRESS 0x00E9
+
+#define RMI_IS_VALID_FUNCTION_ID(id) (id != 0x00 && id != 0xFF)
+
+#endif
diff --git a/drivers/input/touchscreen/rmi_platformdata.h b/drivers/input/touchscreen/rmi_platformdata.h
new file mode 100644
index 0000000..6dcbbaf
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_platformdata.h
@@ -0,0 +1,135 @@
+/**
+ *
+ * Synaptics RMI platform data definitions for use in board files.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_PLATFORMDATA_H)
+#define _RMI_PLATFORMDATA_H
+
+#include "rmi.h"
+
+/* A couple of structs that are useful for frequently occuring constructs, such
+ * as coordinate origin offsets or coordinate clipping values.
+ */
+struct rmi_XY_pair {
+	int x;
+	int y;
+};
+
+struct rmi_range {
+	int min;
+	int max;
+};
+
+struct rmi_sensor_suspend_custom_ops {
+	/* This will be called when suspend or early_suspend is issued.
+	 * Use this for any initial setting related to IRQ (for Attention
+	 * signal) or anything else to lower power consumption. This will
+	 * be called before any internal process related to suspend mode. */
+	void (*rmi_sensor_custom_suspend) (void);
+	/* This will be called when resume or late_resume is issued. Use
+	 * this for any setting related to IRQ (for Attention signal) or
+	 * anything else to restore from low power mode. This will be called
+	 * after all internal process related to resume mode*/
+	void (*rmi_sensor_custom_resume) (void);
+	/* custom delay in millisecond waiting for stability of hardware
+	 * from low power mode */
+	int delay_resume;
+
+};
+/* This contains sensor specific data that is not specialized to I2C or SPI.
+ */
+struct rmi_sensordata {
+	/* This will be called from rmi_register_sensor().  You can use
+	 * it to set up gpios, IRQs, and other platform specific
+	 * infrastructure. */
+	int (*rmi_sensor_setup) (void);
+
+	/* This will be called when the sensor is unloaded.  Use this to release
+	 * gpios, IRQs, and other platform specific infrastructure. */
+	void (*rmi_sensor_teardown) (void);
+
+	/* Use this to customize non-default setting regarding suspend/resume */
+	struct rmi_sensor_suspend_custom_ops *custom_suspend_ops;
+	/* Use this to specify non-default settings on a per function basis. */
+	struct rmi_functiondata_list *perfunctiondata;
+};
+
+/* This contains the per-function customization for a given function.  We store
+ * the data this way in order to avoid allocating a large sparse array -
+ * typically only a few functions are present on a sensor, and even fewer
+ * will be have custom settings.  There is a very small penalty paid for
+ * doing a linear search through the list to find a given function's data,
+ * but since the list is typically very short and is searched only at system
+ * boot time, this is considered acceptable.
+ *
+ * When adding new fields to a functiondata struct, please follow these rules:
+ *     - Where possible, use 0 to indicate that the value should be defaulted.
+ *       This works pretty well for bools, ints, and chars.
+ *     - Where this is not practical (for example, in coordinate offsets or
+ *       range clipping), use a pointer.  Set that pointer to null to indicate
+ *       that the value should be defaulted.
+ */
+struct rmi_functiondata {
+	unsigned char function_index;
+	void *data;
+};
+
+/* This can be included in the platformdata for SPI or I2C RMI4 devices to
+ * customize the settings of the functions on a given sensor.
+ */
+struct rmi_functiondata_list {
+	unsigned char count;	/* Number of elements in the array */
+	struct rmi_functiondata *functiondata;
+};
+
+struct rmi_f01_functiondata {
+	/* What this does is product specific.  For most, but not all, RMI4
+	 * devices, you can set this to true in order to request the device
+	 * report data at half the usual rate.  This can be useful on slow
+	 * CPUs that don't have the resources to process data at the usual
+	 * rate.  However, the meaning of this field is product specific, and
+	 * you should consult the product spec for your sensor to find out
+	 * what this will do.
+	 */
+	bool nonstandard_report_rate;
+};
+
+struct rmi_f11_functiondata {
+	bool swap_axes;
+	bool flip_X;
+	bool flip_Y;
+	struct rmi_XY_pair *offset;
+	struct rmi_range *clip_X;
+	struct rmi_range *clip_Y;
+};
+
+struct rmi_button_map {
+	unsigned char nbuttons;
+	unsigned char *map;
+};
+
+struct rmi_f19_functiondata {
+	struct rmi_button_map *button_map;
+};
+
+#endif
diff --git a/drivers/input/touchscreen/rmi_drvr.h b/drivers/input/touchscreen/rmi_drvr.h
new file mode 100644
index 0000000..a306c01
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_drvr.h
@@ -0,0 +1,97 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) RMI Driver Header File.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_DRVR_H)
+#define _RMI_DRVR_H
+
+#include "rmi.h"
+#include "rmi_platformdata.h"
+
+/*  RMI4 Protocol Support
+ */
+
+struct rmi_phys_driver {
+	char *name;
+	int (*write) (struct rmi_phys_driver *physdrvr, unsigned short address,
+		      char data);
+	int (*read) (struct rmi_phys_driver *physdrvr, unsigned short address,
+		     char *buffer);
+	int (*write_multiple) (struct rmi_phys_driver *physdrvr,
+			       unsigned short address, char *buffer,
+			       int length);
+	int (*read_multiple) (struct rmi_phys_driver *physdrvr,
+			      unsigned short address, char *buffer, int length);
+	void (*attention) (struct rmi_phys_driver *physdrvr, int instance);
+	bool polling_required;
+	int irq;
+
+	/* Standard kernel linked list implementation.
+	 *  Documentation on how to use it can be found at
+	 *  http://isis.poly.edu/kulesh/stuff/src/klist/.
+	 */
+	struct list_head drivers;
+	struct rmi_sensor_driver *sensor;
+	struct module *module;
+};
+
+int rmi_read(struct rmi_sensor_driver *sensor, unsigned short address,
+	     char *dest);
+int rmi_write(struct rmi_sensor_driver *sensor, unsigned short address,
+	      unsigned char data);
+int rmi_read_multiple(struct rmi_sensor_driver *sensor, unsigned short address,
+		      char *dest, int length);
+int rmi_write_multiple(struct rmi_sensor_driver *sensor, unsigned short address,
+		       unsigned char *data, int length);
+int rmi_register_sensor(struct rmi_phys_driver *physdrvr,
+			struct rmi_sensordata *sensordata);
+int rmi_unregister_sensors(struct rmi_phys_driver *physdrvr);
+
+/* Utility routine to set bits in a register. */
+int rmi_set_bits(struct rmi_sensor_driver *sensor, unsigned short address,
+		 unsigned char bits);
+/* Utility routine to clear bits in a register. */
+int rmi_clear_bits(struct rmi_sensor_driver *sensor, unsigned short address,
+		   unsigned char bits);
+/* Utility routine to set the value of a bit field in a register. */
+int rmi_set_bit_field(struct rmi_sensor_driver *sensor, unsigned short address,
+		      unsigned char field_mask, unsigned char bits);
+
+/* 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.
+ */
+ssize_t rmi_store_error(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count);
+
+/* Utility routine to handle reads to write-only attributes.  Hopefully
+ * this will never happen, but if the user does something stupid, we
+ * don't want to accept it quietly.
+ */
+ssize_t rmi_show_error(struct device *dev,
+		       struct device_attribute *attr,
+		       char *buf);
+
+#endif

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
  2011-07-01  5:19 ` [PATCH 1/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 3/9] " Christopher Heiny
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_i2c.c b/drivers/input/touchscreen/rmi_i2c.c
new file mode 100644
index 0000000..c9d248d
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_i2c.c
@@ -0,0 +1,528 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include "rmi_i2c.h"
+#include "rmi_drvr.h"
+#include "rmi_platformdata.h"
+#include "rmi_sensor.h"
+
+#define DRIVER_NAME "rmi4_ts"
+#define DEVICE_NAME "rmi4_ts"
+
+static const struct i2c_device_id rmi_i2c_id_table[] = {
+	{RMI4_I2C_DEVICE_NAME, 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, rmi_i2c_id_table);
+
+/*
+ * This is the data kept on a per instance (client) basis.  This data is
+ * always accessible by using the container_of() macro of the various elements
+ * inside.
+ */
+struct instance_data {
+	int instance_no;
+	int irq;
+	struct rmi_phys_driver rmiphysdrvr;
+	struct i2c_client *i2cclient;	/* pointer to client for later use in
+					   read, write, read_multiple, etc. */
+	struct mutex page_mutex;
+	struct lock_class_key page_key;
+	int page;
+};
+
+/*
+ * RMI devices have 16-bit addressing, but some of the physical
+ * implementations (like SMBus) only have 8-bit addressing.  So RMI implements
+ * a page address at 0xff of every page so we can reliable page addresses
+ * every 256 registers.  This function sets the page.
+ *
+ * The page_mutex lock must be held when this function is entered.
+ *
+ * param[in] id - The pointer to the instance_data struct
+ * param[in] page - The new page address.
+ * returns zero on success, non-zero on failure.
+ */
+/* Writing to page select is giving errors in some configurations.  It's
+ * not needed for basic operation [see note], so we've turned it off for the
+ * moment. Once we figure out why this happening (is it a bug in our code? or
+ * in some I2C chips?  or maybe in the driver for some chips?) we'll either
+ * turn this opperation back on, move the choice to platform data, or
+ * determine whether to use it based on I2C driver capability).
+ *
+ * [NOTE: The current driver feature set doesn't require us to access
+ * addresses outside of the first page, so we're OK for the time being.
+ * Obviously this must be remedied before implementing the more advanced
+ * features that are in the pipeline.]
+ */
+#if	defined(USE_PAGESELECT)
+int rmi_set_page(struct instance_data *instancedata, unsigned int page)
+{
+	char txbuf[2];
+	int retval;
+	txbuf[0] = 0xff;
+	txbuf[1] = page;
+	retval = i2c_master_send(instancedata->i2cclient,
+				txbuf, ARRAY_SIZE(txbuf));
+	if (retval != ARRAY_SIZE(txbuf)) {
+		dev_err(&instancedata->i2cclient->dev,
+			"%s: Set page failed: %d.", __func__, retval);
+	} else {
+		retval = 0;
+		instancedata->page = page;
+	}
+	return retval;
+}
+#else
+int rmi_set_page(struct instance_data *instancedata, unsigned int page)
+{
+	return 0;
+}
+#endif
+
+/*
+ * Same as rmi_i2c_read, except that multiple bytes are allowed to be read.
+ *
+ * param[in] pd - The pointer to the rmi_phys_driver struct
+ * param[in] address - The address at which to start the data read.
+ * param[out] valp - Pointer to the buffer where the data will be stored.  This
+ *     buffer must be at least size bytes long.
+ * param[in] size - The number of bytes to be read.
+ * returns zero upon success (with the byte read in valp), non-zero upon error.
+ *
+ */
+static int
+rmi_i2c_read_multiple(struct rmi_phys_driver *physdrvr, unsigned short address,
+		      char *valp, int size)
+{
+	struct instance_data *instancedata =
+	    container_of(physdrvr, struct instance_data, rmiphysdrvr);
+
+	char txbuf[2];
+	int retval = 0;
+	int retry_count = 0;
+
+	/* Can't have anyone else changing the page behind our backs */
+	mutex_lock(&instancedata->page_mutex);
+
+	if (((address >> 8) & 0xff) != instancedata->page) {
+		/* Switch pages */
+		retval = rmi_set_page(instancedata, ((address >> 8) & 0xff));
+		if (retval)
+			goto exit;
+	}
+
+retry:
+	txbuf[0] = address & 0xff;
+	retval = i2c_master_send(instancedata->i2cclient, txbuf, 1);
+
+	if (retval != 1) {
+		dev_err(&instancedata->i2cclient->dev, "%s: Write fail: %d\n",
+			__func__, retval);
+		goto exit;
+	}
+	retval = i2c_master_recv(instancedata->i2cclient, valp, size);
+
+	if (retval != size) {
+		if (++retry_count == 5) {
+			dev_err(&instancedata->i2cclient->dev,
+				"%s: Read of 0x%04x size %d fail: %d\n",
+				__func__, address, size, retval);
+		} else {
+			mdelay(10);
+			rmi_set_page(instancedata, ((address >> 8) & 0xff));
+			goto retry;
+		}
+	} else {
+		retval = 0;
+	}
+exit:
+
+	mutex_unlock(&instancedata->page_mutex);
+	return retval;
+}
+
+/*
+ * Read a single register through i2c.
+ *
+ * param[in] pd - The pointer to the rmi_phys_driver struct
+ * param[in] address - The address at which to start the data read.
+ * param[out] valp - Pointer to the buffer where the data will be stored.
+ * returns zero upon success (with the byte read in valp), non-zero upon error.
+ */
+static int
+rmi_i2c_read(struct rmi_phys_driver *physdrvr, unsigned short address,
+	     char *valp)
+{
+	return rmi_i2c_read_multiple(physdrvr, address, valp, 1);
+}
+
+/*
+ * Write multiple registers.
+ *
+ * param[in] pd - The pointer to the rmi_phys_driver struct
+ * param[in] address - The address at which to start the write.
+ * param[in] valp - A pointer to a buffer containing the data to be written.
+ * param[in] size - The number of bytes to write.
+ * returns one upon success, something else upon error.
+ */
+static int
+rmi_i2c_write_multiple(struct rmi_phys_driver *physdrvr, unsigned short address,
+		       char *valp, int size)
+{
+	struct instance_data *instancedata =
+	    container_of(physdrvr, struct instance_data, rmiphysdrvr);
+
+	unsigned char txbuf[size+1];
+	int retval = 0;
+
+	memcpy(txbuf+1, valp, size);
+
+	/* Can't have anyone else changing the page behind our backs */
+	mutex_lock(&instancedata->page_mutex);
+
+	if (((address >> 8) & 0xff) != instancedata->page) {
+		/* Switch pages */
+		retval = rmi_set_page(instancedata, ((address >> 8) & 0xff));
+		if (retval)
+			goto exit;
+	}
+
+	txbuf[0] = address & 0xff;	/* put the address in the first byte */
+	retval = i2c_master_send(instancedata->i2cclient,
+				txbuf, ARRAY_SIZE(txbuf));
+
+	/* TODO: Add in retry on writes only in certain error return values */
+	if (retval != ARRAY_SIZE(txbuf)) {
+		dev_err(&instancedata->i2cclient->dev, "%s: Write fail: %d\n",
+			__func__, retval);
+		goto exit;
+	}
+exit:
+
+	mutex_unlock(&instancedata->page_mutex);
+	return retval;
+}
+
+/*
+ * Write a single register through i2c.
+ *
+ * param[in] pd - The pointer to the rmi_phys_driver structnew file (copy)
+ * param[in] address - The address at which to start the write.
+ * param[in] data - The data to be written.
+ * returns one upon success, something else upon error.
+ */
+static int
+rmi_i2c_write(struct rmi_phys_driver *physdrvr, unsigned short address,
+	      char data)
+{
+	return rmi_i2c_write_multiple(physdrvr, address, &data, 1);
+}
+
+/*
+ * This is the Interrupt Service Routine.  It just notifies the application
+ * layer that attention is required.
+ */
+static irqreturn_t i2c_attn_isr(int irq, void *info)
+{
+	struct instance_data *instancedata = info;
+
+	disable_irq_nosync(instancedata->irq);
+
+	if (instancedata->rmiphysdrvr.attention) {
+		instancedata->rmiphysdrvr.attention(&instancedata->rmiphysdrvr,
+						    instancedata->instance_no);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* The Driver probe function - will allocate and initialize the instance
+ * data and request the irq and set the instance data as the clients
+ * platform data then register the physical driver which will do a scan of
+ * the RMI4 Physical Device Table and enumerate any RMI4 functions that
+ * have data sources associated with them.
+ */
+static int
+rmi_i2c_probe(struct i2c_client *client, const struct i2c_device_id *dev_id)
+{
+	struct instance_data *instancedata;
+	int retval = 0;
+	struct rmi_i2c_platformdata *platformdata;
+	struct rmi_sensordata *sensordata;
+
+	if (client == NULL) {
+		pr_err("%s: Invalid NULL client received.", __func__);
+		return -EINVAL;
+	}
+
+	platformdata = client->dev.platform_data;
+	if (platformdata == NULL) {
+		dev_err(&client->dev, "%s: CONFIGURATION ERROR - "
+		"platform data is NULL.\n", __func__);
+		retval = -EINVAL;
+	}
+	sensordata = platformdata->sensordata;
+
+	dev_dbg(&client->dev, "%s: Probing i2c RMI device, addr: 0x%02x",
+		  __func__, client->addr);
+
+	/* Allocate and initialize the instance data for this client */
+	instancedata = kzalloc(sizeof(*instancedata), GFP_KERNEL);
+	if (!instancedata) {
+		dev_err(&client->dev,
+			"%s: Failed to allocate instance_data.\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	__mutex_init(&instancedata->page_mutex, "page_mutex",
+		     &instancedata->page_key);
+	instancedata->rmiphysdrvr.name = RMI4_I2C_DRIVER_NAME;
+	instancedata->rmiphysdrvr.write = rmi_i2c_write;
+	instancedata->rmiphysdrvr.read = rmi_i2c_read;
+	instancedata->rmiphysdrvr.write_multiple = rmi_i2c_write_multiple;
+	instancedata->rmiphysdrvr.read_multiple = rmi_i2c_read_multiple;
+	instancedata->rmiphysdrvr.module = THIS_MODULE;
+
+	/* Set default to polling in case no matching platform data is located
+	   for this device. We'll still work but in polling mode since we didn't
+	   find any irq info */
+	instancedata->rmiphysdrvr.polling_required = true;
+
+	instancedata->page = 0xffff;	/* Force a set page the first time */
+
+	/* Egregiously horrible delay here that seems to prevent I2C disasters
+	 * on certain broken dev systems.  In most cases, you can safely
+	 * leave this as zero.
+	 */
+	if (platformdata->delay_ms > 0)
+		mdelay(platformdata->delay_ms);
+
+	dev_dbg(&client->dev, "%s: sensor addr: 0x%02x irq: 0x%x type: %d\n",
+		 __func__, platformdata->i2c_address, platformdata->irq,
+		 platformdata->irq_type);
+	if (client->addr != platformdata->i2c_address) {
+		dev_err(&client->dev,
+			"%s: CONFIGURATION ERROR - client I2C address 0x%02x "
+			"doesn't match platform data address 0x%02x.\n",
+			__func__, client->addr, platformdata->i2c_address);
+		retval = -EINVAL;
+		goto error_exit;
+	}
+
+	instancedata->instance_no = rmi_next_sensor_id();
+
+	/* set the device name using the instance_no appended to DEVICE_NAME
+	 * to make a unique name */
+	dev_set_name(&client->dev, "%s%d", RMI4_I2C_DEVICE_NAME,
+		     instancedata->instance_no);
+
+	/* Determine if we need to poll (inefficient) or use interrupts.
+	 */
+	if (platformdata->irq) {
+		instancedata->irq = platformdata->irq;
+		switch (platformdata->irq_type) {
+		case IRQF_TRIGGER_NONE:
+			dev_warn(&client->dev, "%s: Touchscreen ATTN IRQ was "
+				"specified as IRQF_TRIGGER_NONE. IRQ trigger "
+				"configuration will be defaulted.", __func__);
+			break;
+		case IRQF_TRIGGER_RISING:
+		case IRQF_TRIGGER_FALLING:
+		case IRQF_TRIGGER_HIGH:
+		case IRQF_TRIGGER_LOW:
+			break;
+		default:
+			dev_warn(&client->dev,
+				 "%s: Invalid IRQ flags in platform data.\n",
+				 __func__);
+			retval = -ENXIO;
+			goto error_exit;
+		}
+
+		instancedata->rmiphysdrvr.polling_required = false;
+		instancedata->rmiphysdrvr.irq = instancedata->irq;
+
+	} else {
+		instancedata->rmiphysdrvr.polling_required = true;
+		dev_info(&client->dev,
+			 "%s: No IRQ info given. Polling required.\n",
+			 __func__);
+	}
+
+	/* Store the instance data in the i2c_client - we need to do this prior
+	 * to calling register_physical_driver since it may use the read, write
+	 * functions. If nothing was found then the id fields will be set to 0
+	 * for the irq and the default  will be set to polling required so we
+	 * will still work but in polling mode. */
+	i2c_set_clientdata(client, instancedata);
+
+	/* Copy i2c_client pointer into instance_data's i2c_client pointer for
+	   later use in rmi4_read, rmi4_write, etc. */
+	instancedata->i2cclient = client;
+
+	/* Call the platform setup routine, to do any setup that is required
+	 * before interacting with the device.  When we refined the bus
+	 * architecture, this will be done elsewhere.
+	 */
+	if (sensordata && sensordata->rmi_sensor_setup) {
+		retval = sensordata->rmi_sensor_setup();
+		if (retval) {
+			dev_err(&client->dev,
+				"%s: sensor setup failed with code %d.",
+			       __func__, retval);
+			goto error_exit;
+		}
+	}
+
+	/* Register sensor drivers - this will call the detect function that
+	 * will then scan the device and determine the supported RMI4 sensors
+	 * and functions.
+	 */
+	retval =
+	    rmi_register_sensor(&instancedata->rmiphysdrvr,
+				platformdata->sensordata);
+	if (retval) {
+		dev_err(&client->dev,
+			"%s: Failed to Register %s sensor drivers\n", __func__,
+			instancedata->rmiphysdrvr.name);
+		goto error_exit;
+	}
+
+	if (instancedata->rmiphysdrvr.polling_required == false) {
+		retval = request_irq(instancedata->irq, i2c_attn_isr,
+				platformdata->irq_type, "rmi_i2c",
+				instancedata);
+		if (retval) {
+			dev_err(&client->dev,
+				"%s: failed to obtain IRQ %d. Result: %d.",
+				__func__, instancedata->irq, retval);
+			dev_info(&client->dev, "%s: Reverting to polling.\n",
+				 __func__);
+			instancedata->rmiphysdrvr.polling_required = true;
+			/* TODO: Need to revert back to polling - create and
+			 * start timer. */
+		} else {
+			dev_dbg(&client->dev, "%s: got irq.\n", __func__);
+		}
+	}
+
+	dev_dbg(&client->dev, "%s: Successfully registered %s sensor driver.\n",
+		__func__, instancedata->rmiphysdrvr.name);
+
+	pr_info("%s: Successfully registered %s sensor driver.\n", __func__,
+		instancedata->rmiphysdrvr.name);
+
+	return retval;
+
+error_exit:
+	kfree(instancedata);
+	/* return error for clean-up*/
+	return retval;
+}
+
+static int rmi_i2c_remove(struct i2c_client *client)
+{
+	struct instance_data *instancedata = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s: Unregistering phys driver %s\n", __func__,
+		instancedata->rmiphysdrvr.name);
+
+	rmi_unregister_sensors(&instancedata->rmiphysdrvr);
+
+	dev_dbg(&client->dev, "%s: Unregistered phys driver %s\n",
+		__func__, instancedata->rmiphysdrvr.name);
+
+	/* only free irq if we have an irq - otherwise the instance_data
+	   will be 0 for that field */
+	if (instancedata->irq)
+		free_irq(instancedata->irq, instancedata);
+
+	kfree(instancedata);
+	dev_dbg(&client->dev, "%s: Remove successful\n", __func__);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rmi_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	/* Touch sleep mode */
+	return 0;
+}
+
+static int rmi_i2c_resume(struct i2c_client *client)
+{
+	/* Re-initialize upon resume */
+	return 0;
+}
+#else
+#define rmi_i2c_suspend	NULL
+#define rmi_i2c_resume	NULL
+#endif
+
+/*
+ * This structure tells the i2c subsystem about us.
+ *
+ * TODO: we should add .suspend and .resume fns.
+ *
+ */
+static struct i2c_driver rmi_i2c_driver = {
+	.probe = rmi_i2c_probe,
+	.remove = rmi_i2c_remove,
+	.suspend = rmi_i2c_suspend,
+	.resume = rmi_i2c_resume,
+	.driver = {
+		   .name = RMI4_I2C_DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   },
+	.id_table = rmi_i2c_id_table,
+};
+
+static int __init rmi_phys_i2c_init(void)
+{
+	return i2c_add_driver(&rmi_i2c_driver);
+}
+
+static void __exit rmi_phys_i2c_exit(void)
+{
+	i2c_del_driver(&rmi_i2c_driver);
+}
+
+module_init(rmi_phys_i2c_init);
+module_exit(rmi_phys_i2c_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Driver I2C Physical Layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi_i2c.h b/drivers/input/touchscreen/rmi_i2c.h
new file mode 100644
index 0000000..66bc48c
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_i2c.h
@@ -0,0 +1,67 @@
+/**
+ *
+ * Synaptics RMI over I2C Physical Layer Driver Header File.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_I2C_H)
+#define _RMI_I2C_H
+
+#include "rmi_platformdata.h"
+
+/* In the future, we may change the device name.  If so, defining it here
+ * makes life easier.
+ */
+#define RMI4_I2C_DRIVER_NAME "rmi4_ts"
+#define RMI4_I2C_DEVICE_NAME "rmi4_ts"
+
+/* Sensor-specific configuration data, to be included as the platform data
+ * for the relevant i2c_board_info entry.
+ *
+ * This describes a single RMI4 sensor on an I2C bus, including:
+ * its I2C address, IRQ (if any), the type of IRQ (if applicable), and an
+ * optional list of any non-default settings (on a per function basis)
+ * to be applied at start up.
+ */
+struct rmi_i2c_platformdata {
+	/* The seven-bit i2c address of the sensor. */
+	int i2c_address;
+	/* The number of the irq.  Set to zero if polling is required. */
+	int irq;
+	/* The type of the irq.  This should be one of IRQF_TRIGGER_RISING,
+	 * IRQF_TRIGGER_FALLING, IRQF_TRIGGER_HIGH, IRQF_TRIGGER_LOW.
+	 * Recommended value is IRQF_TRIGGER_LOW, but may be different for
+	 * specially configured sensors.
+	 * Only valid if irq != 0 */
+	int irq_type;
+
+	/* If >0, the driver will delay this many milliseconds before attempting
+	 * I2C communications.  This is necessary because some horribly broken
+	 * development systems don't bring their I2C up very fast after system
+	 * power on or reboot.  In most cases, you can safely ignore this.
+	 */
+	int delay_ms;
+
+	/* Use this to specify platformdata that is not I2C specific. */
+	struct rmi_sensordata *sensordata;
+};
+
+#endif
diff --git a/drivers/input/touchscreen/rmi_spi.c b/drivers/input/touchscreen/rmi_spi.c
new file mode 100644
index 0000000..0d2453a
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_spi.c
@@ -0,0 +1,711 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) SPI Physical Layer Driver.
+ * Copyright (C) 2008-2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+#include "rmi_spi.h"
+#include "rmi_platformdata.h"
+#include "rmi_drvr.h"
+#include "rmi_sensor.h"
+
+#define COMM_DEBUG  0		/* Set to 1 to dump transfers. */
+
+/* For V1 protocol, the high bit in the address is set to indicate reads. */
+#define SPI_V1_READ_FLAG 0x80
+
+/* For V2 protocol, first byte of transmission indicates what operation is
+ * to be performed.
+ */
+#define SPI_V2_UNIFIED_READ       0xC0
+#define SPI_V2_WRITE              0x40
+#define SPI_V2_PREPARE_SPLIT_READ 0xC8
+#define SPI_V2_EXECUTE_SPLIT_READ 0xCA
+
+/* Once the sensor has prepared a V2 split read, we always send the same
+ * bytes to tell it to execute the read. For convenience, we keep a static
+ * copy of those bytes around.
+ */
+static unsigned char execute_split_read[] = { SPI_V2_EXECUTE_SPLIT_READ, 0x00 };
+
+/* This is the data kept on a per instance (client) basis.  This data is
+ * always accessible by using the container_of() macro of the various elements
+ * inside.
+ */
+struct spi_device_instance_data {
+	int instance_no;
+	int irq;
+	unsigned int byte_delay_us;
+	unsigned int block_delay_us;
+	unsigned int split_read_byte_delay_us;
+	unsigned int split_read_block_delay_us;
+	unsigned int buffer_size;
+	unsigned char spi_version;
+	int v2_transaction_size;
+	wait_queue_head_t attn_event;
+	bool attn_seen;
+	bool split_read_pending;
+	struct rmi_phys_driver rpd;
+	struct spi_device *spidev;
+	struct rmi_spi_platformdata *platformdata;
+};
+
+static int spi_xfer(struct spi_device_instance_data *instance_data,
+		    const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx)
+{
+	struct spi_device *spi = instance_data->spidev;
+#if COMM_DEBUG
+	int i;
+#endif
+	int status;
+	struct spi_message message;
+	struct spi_transfer *xfer_list;
+	const int total_bytes = n_tx + n_rx;
+	u8 local_buf[total_bytes];
+	int xfers_in_message = 0;
+	int xfer_index = 0;
+	int block_delay = n_rx > 0 ? instance_data->block_delay_us : 0;
+	int byte_delay = n_tx > 1 ? instance_data->byte_delay_us : 0;
+	if (instance_data->split_read_pending) {
+		block_delay =
+		    n_rx > 0 ? instance_data->split_read_block_delay_us : 0;
+		byte_delay =
+		    n_tx > 1 ? instance_data->split_read_byte_delay_us : 0;
+	}
+
+	if (n_tx)
+		xfers_in_message += 1;
+	if (n_rx) {
+		if (byte_delay)
+			xfers_in_message += n_rx;
+		else
+			xfers_in_message += 1;
+	}
+
+	xfer_list = kcalloc(xfers_in_message,
+			    sizeof(struct spi_transfer), GFP_KERNEL);
+	if (!xfer_list)
+		return -ENOMEM;
+
+	spi_message_init(&message);
+
+	if (n_tx) {
+		memset(&xfer_list[0], 0, sizeof(struct spi_transfer));
+		xfer_list[0].len = n_tx;
+		xfer_list[0].delay_usecs = block_delay;
+		spi_message_add_tail(&xfer_list[0], &message);
+		memcpy(local_buf, txbuf, n_tx);
+		xfer_list[0].tx_buf = local_buf;
+		xfer_index++;
+	}
+	if (n_rx) {
+		if (byte_delay) {
+			int buffer_offset = n_tx;
+			for (; xfer_index < xfers_in_message; xfer_index++) {
+				memset(&xfer_list[xfer_index], 0,
+				       sizeof(struct spi_transfer));
+				xfer_list[xfer_index].len = 1;
+				xfer_list[xfer_index].delay_usecs = byte_delay;
+				xfer_list[xfer_index].rx_buf =
+				    local_buf + buffer_offset;
+				buffer_offset++;
+				spi_message_add_tail(&xfer_list[xfer_index],
+						     &message);
+			}
+		} else {
+			memset(&xfer_list[xfer_index], 0,
+			       sizeof(struct spi_transfer));
+			xfer_list[xfer_index].len = n_rx;
+			xfer_list[xfer_index].rx_buf = local_buf + n_tx;
+			spi_message_add_tail(&xfer_list[xfer_index], &message);
+			xfer_index++;
+		}
+	}
+#if COMM_DEBUG
+	pr_info("%s: SPI transmits %d bytes...", __func__, n_tx);
+	for (i = 0; i < n_tx; i++)
+		pr_info("    0x%02X", local_buf[i]);
+#endif
+
+	/* do the i/o */
+	if (instance_data->platformdata->cs_assert) {
+		status = instance_data->platformdata->cs_assert(
+			instance_data->platformdata->cs_assert_data, true);
+		if (!status) {
+			pr_err("%s: Failed to assert CS.", __func__);
+			goto error_exit;
+		}
+	}
+	status = spi_sync(spi, &message);
+	if (instance_data->platformdata->cs_assert) {
+		status = instance_data->platformdata->cs_assert(
+			instance_data->platformdata->cs_assert_data, false);
+		if (!status) {
+			pr_err("%s: Failed to deassert CS.", __func__);
+			goto error_exit;
+		}
+	}
+	if (status == 0) {
+		memcpy(rxbuf, local_buf + n_tx, n_rx);
+		status = message.status;
+#if COMM_DEBUG
+		if (n_rx) {
+			pr_info("%s: SPI received %d bytes...", __func__, n_rx);
+			for (i = 0; i < n_rx; i++)
+				pr_info("    0x%02X", rxbuf[i]);
+		}
+#endif
+	} else {
+		pr_err("%s: spi_sync failed with error code %d.",
+		       __func__, status);
+	}
+
+error_exit:
+	kfree(xfer_list);
+	return status;
+}
+
+/* Same as rmi_spi_read_v1, except that multiple bytes are allowed to be read.
+ * \param[in] pd
+ * \param[in] address The address at which to start the data read.
+ * \param[out] valp Pointer to the buffer where the data will be stored.  This
+ * buffer must be at least size bytes long.
+ * \param[in] size The number of bytes to be read.
+ * \return zero upon success (with the byte read in valp), non-zero upon error.
+ */
+static int
+rmi_spi_read_multiple_v1(struct rmi_phys_driver *pd, unsigned short address,
+			 char *valp, int size)
+{
+	struct spi_device_instance_data *instance_data =
+	    container_of(pd, struct spi_device_instance_data, rpd);
+	int retval;
+	unsigned char txbuf[2];
+
+	txbuf[1] = address;
+	txbuf[0] = address >> 8;
+	txbuf[0] |= SPI_V1_READ_FLAG;
+
+	retval = spi_xfer(instance_data, txbuf, ARRAY_SIZE(txbuf), valp, size);
+
+	return retval;
+}
+
+/*
+ * Read a single register through SPI, V1 protocol.
+ * \param[in] pd
+ * \param[in] address The address at which to start the data read.
+ * \param[out] valp Pointer to the buffer where the data will be stored.
+ * \return zero upon success (with the byte read in valp), non-zero upon error.
+ */
+static int
+rmi_spi_read_v1(struct rmi_phys_driver *pd, unsigned short address, char *valp)
+{
+	return rmi_spi_read_multiple_v1(pd, address, valp, 1);
+}
+
+/* Write multiple registers using version 1 of the RMI4 SPI interface.
+ * \param[in] pd
+ * \param[in] address The address at which to start the write.
+ * \param[in] valp A pointer to a buffer containing the data to be written.
+ * \param[in] size The number of bytes to write.
+ * \return one upon success, something else upon error.
+ */
+static int
+rmi_spi_write_multiple_v1(struct rmi_phys_driver *pd, unsigned short address,
+			  char *valp, int size)
+{
+	struct spi_device_instance_data *id =
+	    container_of(pd, struct spi_device_instance_data, rpd);
+	int buffer_size = size + 2;
+	unsigned char txbuf[buffer_size];
+	int retval;
+	int i;
+
+	txbuf[1] = address;
+	txbuf[0] = address >> 8;
+
+	for (i = 0; i < size; i++)
+		txbuf[i + 2] = valp[i];
+
+	retval = spi_xfer(id, txbuf, buffer_size, NULL, 0);
+
+	return retval ? 0 : 1;
+}
+
+/* Write a single register through SPI using version 1 of the interface.
+ * You can write multiple registers at once, but I made the functions for that
+ * seperate for performance reasons.  Writing multiple requires allocation and
+ * freeing.
+ * \param[in] pd
+ * \param[in] address The address at which to start the write.
+ * \param[in] data The data to be written.
+ * \return one upon success, something else upon error.
+ */
+static int
+rmi_spi_write_v1(struct rmi_phys_driver *pd, unsigned short address, char data)
+{
+	return rmi_spi_write_multiple_v1(pd, address, &data, 1);
+}
+
+/* Read multiple bytes using version 2 of the RMI4 SPI interface.
+ *
+ * \param[in] pd
+ * \param[in] address The address at which to start the data read.
+ * \param[out] valp Pointer to the buffer where the data will be stored.  This
+ * buffer must be at least size bytes long.
+ * \param[in] size The number of bytes to be read.
+ * \return zero upon success (with the byte read in valp), non-zero upon error.
+ */
+static int
+rmi_spi_read_multiple_v2(struct rmi_phys_driver *pd, unsigned short address,
+			 char *valp, int size)
+{
+	struct spi_device_instance_data *instance_data =
+	    container_of(pd, struct spi_device_instance_data, rpd);
+	int retval;
+	char header_buf[4];
+
+	header_buf[0] = SPI_V2_UNIFIED_READ;
+	header_buf[1] = (address >> 8) & 0x00FF;
+	header_buf[2] = address & 0x00ff;
+	header_buf[3] = size;
+
+	retval = spi_xfer(instance_data, header_buf, ARRAY_SIZE(header_buf),
+			  valp, size);
+
+	return retval;
+}
+
+/* Read a single register (one byte) from the device, using version 2 of the
+ * RMI4 SPI interface.
+ * \param[in] pd
+ * \param[in] address The address at which to start the data read.
+ * \param[out] valp Pointer to the buffer where the data will be stored.
+ * \return zero upon success (with the byte read in valp), non-zero upon error.
+ */
+static int
+rmi_spi_read_v2(struct rmi_phys_driver *pd, unsigned short address, char *valp)
+{
+	return rmi_spi_read_multiple_v2(pd, address, valp, 1);
+}
+
+/* Read multiple bytes using version 2 of the RMI4 SPI interface.
+ *
+ * \param[in] pd
+ * \param[in] address The address at which to start the data read.
+ * \param[out] valp Pointer to the buffer where the data will be stored.  This
+ * buffer must be at least size bytes long.
+ * \param[in] size The number of bytes to be read.
+ * \return zero upon success (with the byte read in valp), non-zero upon error.
+ */
+static int
+rmi_spi_split_read_v2(struct rmi_phys_driver *pd, unsigned short address,
+		      char *valp, int size)
+{
+	struct spi_device_instance_data *instance_data =
+	    container_of(pd, struct spi_device_instance_data, rpd);
+	int retval;
+	char header_buf[4];
+	int read_size = size + 1; /* Add a byte for dummy byte at start. */
+	char read_buf[read_size];
+
+	header_buf[0] = SPI_V2_PREPARE_SPLIT_READ;
+	header_buf[1] = (address >> 8) & 0x00FF;
+	header_buf[2] = address & 0x00ff;
+	header_buf[3] = size;
+
+	instance_data->attn_seen = false;
+	instance_data->split_read_pending = true;
+
+	retval = spi_xfer(instance_data, header_buf, ARRAY_SIZE(header_buf),
+			  NULL, 0);
+	if (retval) {
+		instance_data->split_read_pending = false;
+		return retval;
+	}
+
+	enable_irq(pd->irq);
+	wait_event_interruptible((instance_data->attn_event),
+				 (instance_data->attn_seen == true));
+
+	retval = spi_xfer(instance_data,
+			  execute_split_read, ARRAY_SIZE(execute_split_read),
+			  read_buf, read_size);
+	instance_data->split_read_pending = false;
+	if (retval)
+		return retval;
+	if (read_buf[0] != size)
+		return -EIO;
+	memcpy(valp, &read_buf[1], size);
+
+	return retval;
+}
+
+/* Write multiple registers using version 2 of the RMI4 SPI interface.
+ *
+ * \param[in] pd
+ * \param[in] address The address at which to start the write.
+ * \param[in] valp A pointer to a buffer containing the data to be written.
+ * \param[in] size The number of bytes to write.
+ * \return one upon success, something else upon error.
+ */
+static int
+rmi_spi_write_multiple_v2(struct rmi_phys_driver *pd, unsigned short address,
+			  char *valp, int size)
+{
+	struct spi_device_instance_data *id =
+	    container_of(pd, struct spi_device_instance_data, rpd);
+	unsigned char txbuf[size + 4];
+	int retval;
+
+	txbuf[0] = SPI_V2_WRITE;
+	txbuf[1] = (address >> 8) & 0x00FF;
+	txbuf[2] = address & 0x00FF;
+	txbuf[3] = size;
+
+	memcpy(&txbuf[4], valp, size);
+
+	retval = spi_xfer(id, txbuf, size + 4, NULL, 0);
+
+	return retval ? 0 : 1;
+}
+
+/* Write a single byte/register using version 2 of the RMI4 SPI interface.
+ *
+ * \param[in] pd
+ * \param[in] address The address at which to start the write.
+ * \param[in] data The data to be written.
+ * \return one upon success, something else upon error.
+ */
+static int
+rmi_spi_write_v2(struct rmi_phys_driver *pd, unsigned short address, char data)
+{
+	return rmi_spi_write_multiple_v2(pd, address, &data, 1);
+}
+
+/* This is the Interrupt Service Routine.  It just notifies the physical device
+ * that attention is required.
+ */
+static irqreturn_t spi_attn_isr(int irq, void *info)
+{
+	struct spi_device_instance_data *instance_data = info;
+	disable_irq_nosync(instance_data->irq);
+	if (instance_data->spi_version == 2 &&
+	    instance_data->split_read_pending) {
+		instance_data->attn_seen = true;
+		wake_up(&instance_data->attn_event);
+		return IRQ_HANDLED;
+	}
+	if (instance_data->rpd.attention)
+		instance_data->rpd.attention(&instance_data->rpd,
+					     instance_data->instance_no);
+	return IRQ_HANDLED;
+}
+
+static int __devinit rmi_spi_probe(struct spi_device *spi)
+{
+	struct spi_device_instance_data *instance_data;
+	int retval;
+	struct rmi_spi_platformdata *platformdata;
+	struct rmi_sensordata *sensordata;
+	char buf[6];
+
+	dev_info(&spi->dev, "%s: Probing RMI4 SPI device", __func__);
+
+	platformdata = spi->dev.platform_data;
+	if (platformdata == NULL) {
+		dev_err(&spi->dev,
+			"%s: CONFIGURATION ERROR - platform data is NULL.",
+		       __func__);
+		return -EINVAL;
+	}
+
+	spi->bits_per_word = 8;
+	/* This should have already been set up in the board file,
+	 * shouldn't it? */
+	spi->mode = SPI_MODE_3;
+
+	retval = spi_setup(spi);
+	if (retval < 0) {
+		dev_err(&spi->dev,
+			"%s: spi_setup failed with %d.", __func__, retval);
+		return retval;
+	}
+
+	instance_data = kzalloc(sizeof(*instance_data), GFP_KERNEL);
+	if (!instance_data) {
+		dev_err(&spi->dev,
+			"%s: Failed to allocate memory for instance data.",
+		       __func__);
+		kfree(platformdata);
+		return -ENOMEM;
+	}
+
+	instance_data->platformdata = platformdata;
+	sensordata = platformdata->sensordata;
+	instance_data->block_delay_us =
+	    platformdata->block_delay_us ? platformdata->
+	    block_delay_us : RMI_DEFAULT_BLOCK_DELAY_US;
+	instance_data->byte_delay_us =
+	    platformdata->byte_delay_us ? platformdata->
+	    byte_delay_us : RMI_DEFAULT_BYTE_DELAY_US;
+	instance_data->split_read_block_delay_us =
+	    platformdata->split_read_block_delay_us;
+	instance_data->split_read_byte_delay_us =
+	    platformdata->split_read_byte_delay_us;
+
+	instance_data->spidev = spi;
+	instance_data->rpd.name = RMI4_SPI_DRIVER_NAME;
+	instance_data->rpd.write = rmi_spi_write_v1;
+	instance_data->rpd.read = rmi_spi_read_v1;
+	instance_data->rpd.write_multiple = rmi_spi_write_multiple_v1;
+	instance_data->rpd.read_multiple = rmi_spi_read_multiple_v1;
+	instance_data->rpd.module = THIS_MODULE;
+		/* default to polling if irq not used */
+	instance_data->rpd.polling_required = true;
+
+	/* Call the platform setup routine, to do any setup that is
+	 * required before interacting with the device.
+	 */
+	if (sensordata && sensordata->rmi_sensor_setup) {
+		retval = sensordata->rmi_sensor_setup();
+		if (retval) {
+			dev_err(&spi->dev,
+				"%s: sensor setup failed with code %d.",
+			       __func__, retval);
+			kfree(instance_data);
+			return retval;
+		}
+	}
+
+	instance_data->instance_no = rmi_next_sensor_id();
+	dev_set_name(&spi->dev, "%s%d", RMI4_SPI_DEVICE_NAME,
+			instance_data->instance_no);
+
+	/* Determine if we need to poll (inefficient) or use interrupts.
+	 */
+	if (platformdata->irq) {
+		instance_data->irq = platformdata->irq;
+		switch (platformdata->irq_type) {
+		case IRQF_TRIGGER_NONE:
+			dev_warn(&spi->dev, "%s: Touchscreen ATTN IRQ was "
+				"specified as IRQF_TRIGGER_NONE. IRQ trigger "
+				"configuration will be defaulted.", __func__);
+			break;
+		case IRQF_TRIGGER_RISING:
+		case IRQF_TRIGGER_FALLING:
+		case IRQF_TRIGGER_HIGH:
+		case IRQF_TRIGGER_LOW:
+			break;
+		default:
+			dev_warn(&spi->dev,
+				"%s: Invalid IRQ flags in platform data.\n",
+				__func__);
+			retval = -ENXIO;
+			goto error_exit;
+		}
+
+		instance_data->rpd.polling_required = false;
+		instance_data->rpd.irq = instance_data->irq;
+	} else {
+		instance_data->rpd.polling_required = true;
+		dev_info(&spi->dev,
+			 "%s: No IRQ info given. Polling required.\n",
+	   __func__);
+	}
+
+	/* Store instance data for later access. */
+	if (instance_data)
+		spi_set_drvdata(spi, instance_data);
+
+#if	defined(CONFIG_MACH_OMAP3_BEAGLE)
+	/* Fixes an issue on Beagleboard - first time read is all 0's,
+	 * brief wait required afterwards. */
+	retval = instance_data->rpd.read_multiple(&(instance_data->rpd),
+					RMI_PDT_START_ADDRESS, (char *)buf,
+					6);
+	msleep(20);
+#endif
+
+	retval = instance_data->rpd.read_multiple(&(instance_data->rpd),
+					RMI_PROTOCOL_VERSION_ADDRESS, buf,
+					2);
+	if (retval < 0) {
+		dev_err(&spi->dev,
+			"%s: Protocol discovery for SPI V2 failed with %d.",
+			__func__, retval);
+		goto error_exit;
+	}
+#if	COMM_DEBUG
+	dev_info(&spi->dev,
+		 "%s: SPI V2 probe got %02X %02X.", __func__, buf[0], buf[1]);
+#endif
+
+	/* buf[0] is equal to SPI proto version - 1. */
+	instance_data->spi_version = buf[0] + 1;
+	switch (instance_data->spi_version) {
+	case 1:
+		break;
+	case 2:
+		instance_data->v2_transaction_size = (unsigned char)buf[1];
+		instance_data->rpd.write = rmi_spi_write_v2;
+		instance_data->rpd.write_multiple = rmi_spi_write_multiple_v2;
+		instance_data->rpd.read = rmi_spi_read_v2;
+		instance_data->rpd.read_multiple = rmi_spi_read_multiple_v2;
+		dev_info(&spi->dev,
+				"%s: Identified SPI V2, transaction size=%d.",
+				__func__, instance_data->v2_transaction_size);
+		break;
+	default:
+		instance_data->spi_version = 1;
+		dev_warn(&spi->dev,
+		    "%s: Unknown SPI version %d encountered. Assuming SPI V1.",
+		     __func__, instance_data->spi_version);
+	}
+
+	/* Register the sensor driver - which will trigger a scan of the PDT. */
+	retval =
+	    rmi_register_sensor(&instance_data->rpd, platformdata->sensordata);
+	if (retval) {
+		dev_err(&spi->dev,
+			"%s: sensor registration failed with code %d.",
+			__func__, retval);
+		goto error_exit;
+	}
+
+	if (instance_data->rpd.polling_required == false) {
+		instance_data->irq = platformdata->irq;
+		retval = request_irq(platformdata->irq, spi_attn_isr,
+				platformdata->irq_type, dev_name(&spi->dev),
+				instance_data);
+		if (retval) {
+			dev_err(&spi->dev,
+				"%s: failed to obtain IRQ %d. Result: %d.",
+				__func__, platformdata->irq, retval);
+			dev_info(&spi->dev, "%s: Reverting to polling.\n",
+				 __func__);
+			instance_data->rpd.polling_required = true;
+			instance_data->irq = 0;
+			/* TODO: Need to revert back to polling -
+			 * create and start timer. */
+		} else {
+			dev_dbg(&spi->dev, "%s: got irq.\n", __func__);
+			instance_data->rpd.irq = instance_data->irq;
+			if (instance_data->spi_version == 2) {
+				init_waitqueue_head(&instance_data->attn_event);
+				instance_data->rpd.read_multiple =
+				    rmi_spi_split_read_v2;
+			}
+		}
+	}
+
+	dev_info(&spi->dev, "%s: Successfully registered %s.", __func__,
+		instance_data->rpd.name);
+
+	return 0;
+
+error_exit:
+	if (sensordata && sensordata->rmi_sensor_teardown)
+		sensordata->rmi_sensor_teardown();
+	if (instance_data->irq)
+		free_irq(instance_data->irq, instance_data);
+	kfree(instance_data);
+	return retval;
+}
+
+static int rmi_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	pr_info("%s: Suspending...", __func__);
+	return 0;
+}
+
+static int rmi_spi_resume(struct spi_device *spi)
+{
+	pr_info("%s: Resuming...", __func__);
+	return 0;
+}
+
+static int __devexit rmi_spi_remove(struct spi_device *spi)
+{
+	struct spi_device_instance_data *instance_data = spi_get_drvdata(spi);
+	pr_info("%s: RMI SPI device removed.", __func__);
+
+	rmi_spi_suspend(spi, PMSG_SUSPEND);
+
+	rmi_unregister_sensors(&instance_data->rpd);
+
+	if (instance_data) {
+		if (instance_data->irq)
+			free_irq(instance_data->irq, instance_data);
+		kfree(instance_data);
+	}
+
+	return 0;
+}
+
+static struct spi_driver rmi_spi_driver = {
+	.driver = {
+		.name = RMI4_SPI_DRIVER_NAME,
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+		},
+	.probe = rmi_spi_probe,
+	.remove = __devexit_p(rmi_spi_remove),
+	.suspend = rmi_spi_suspend,
+	.resume = rmi_spi_resume,
+};
+
+static int __init rmi_spi_init(void)
+{
+	int retval;
+	pr_info("%s: RMI SPI physical layer initialization.", __func__);
+	retval = spi_register_driver(&rmi_spi_driver);
+	if (retval < 0) {
+		pr_err("%s: Failed to register spi driver, code = %d.",
+		       __func__, retval);
+		return retval;
+	}
+	pr_debug("%s: SPI initialization complete.", __func__);
+	return retval;
+}
+
+module_init(rmi_spi_init);
+
+static void __exit rmi_spi_exit(void)
+{
+	pr_info("%s: RMI SPI physical layer exits.", __func__);
+	spi_unregister_driver(&rmi_spi_driver);
+}
+
+module_exit(rmi_spi_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Driver SPI Physical Layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi_spi.h b/drivers/input/touchscreen/rmi_spi.h
new file mode 100644
index 0000000..f650f0b
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_spi.h
@@ -0,0 +1,114 @@
+/**
+ *
+ * Register Mapped Interface SPI Physical Layer Driver Header File.
+ * Copyright (C) 2008-2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_SPI_H)
+#define _RMI_SPI_H
+
+#include "rmi_platformdata.h"
+
+#define RMI4_SPI_DRIVER_NAME "rmi4_ts"
+#define RMI4_SPI_DEVICE_NAME "rmi4_ts"
+
+/* Some RMI4 SPI devices require a delay between writing the address and
+ * starting the read.  A subset of those required a delay between each
+ * byte transferred during the read.
+ */
+
+/* microseconds between header and start of read operation. */
+#define RMI_DEFAULT_BLOCK_DELAY_US	65
+
+/* microseconds inter-byte delay between bytes during read. */
+#define RMI_DEFAULT_BYTE_DELAY_US	65
+
+/* Use this to specify SPI interface dependent parameters on a per device basis.
+ *
+ * Interface independent data is given in the sensor_data field of this struct.
+ */
+struct rmi_spi_platformdata {
+	/* The number of the irq.  Set to zero if polling is required. */
+	int irq;
+
+	/* The type of the irq.  This should be one of IRQF_TRIGGER_RISING,
+	 * IRQF_TRIGGER_FALLING, IRQF_TRIGGER_HIGH, IRQF_TRIGGER_LOW.
+	 * Recommended value is IRQF_TRIGGER_LOW, but may be different for
+	 * specially configured sensors.
+	 * Only valid if irq != 0 */
+	int irq_type;
+
+	/* RMI4 devices implement two different ways of talking to the
+	 * device over SPI.  These are called SPIv1 and SPIv2.  Due to
+	 * resource constraints on some ASICs, delays may be required when
+	 * reading data from the chip.
+	 *
+	 * The block delay specifies the number of microseconds the
+	 * driver should delay between sending the read request and
+	 * the start of reading data from the ASIC.  If you don't know
+	 * what value to use here, you should specify
+	 * RMI_DEFAULT_BLOCK_DELAY_US.
+	 *
+	 * The byte delay specifies the number of microseconds the driver should
+	 * delay between each byte of a read request.  If don't know what value
+	 * to use here, you should specify RMI_DEFAULT_BLOCK_DELAY_US.
+	 *
+	 * Usually these two values should be the same, but in some cases
+	 * it may be desirable to use different values.
+	 */
+	unsigned int block_delay_us;
+	unsigned int byte_delay_us;
+
+	/* SPIv2 supports a special "split read" operation, which can permit the
+	 * SPI interface to run at full speed (subject to product specific
+	 * limitations) with no delay between blocks and bytes.  In almost all
+	 * cases, it is permissible to default these values to zero.
+	 */
+	unsigned int split_read_block_delay_us;
+	unsigned int split_read_byte_delay_us;
+
+	/* Some SPI hardware and/or drivers do not manage the SSB/CS line in a
+	 * reasonable way.  In particular, the problem is that SSB/CS will be
+	 * deasserted in between every spi_transfer in an spi_message (despite
+	 * whatever you might have set the spi_transfer.cs_change flag to),
+	 * rather than asserting it at the start of the spi_message and leaving
+	 * it asserted until all transfers are completed.  In this case, we
+	 * have to manage the SSB/CS line manually, and you need to provide
+	 * the cs_assert callback here.
+	 *
+	 * If the cs_assert function is non-null, it will be called before
+	 * the driver submits an spi_message in order to assert the line (the
+	 * assert parameter will be TRUE), and afterwards to clear it (the
+	 * assert parameter will be FALSE).  cs_assert should return 0 for
+	 * success, or a negative error code if it fails.
+	 *
+	 * You can provide any needed context data in the cs_assert_data
+	 * variable, which will be passed into all cs_assert calls.
+	 */
+	void *cs_assert_data;
+	int (*cs_assert) (const void *cs_assert_data, const bool assert);
+
+
+	/* Use this to specify platformdata that is not SPI specific. */
+	struct rmi_sensordata *sensordata;
+};
+
+#endif

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
  2011-07-01  5:19 ` [PATCH 1/9] " Christopher Heiny
  2011-07-01  5:19 ` [PATCH 2/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 4/9] " Christopher Heiny
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_function.c b/drivers/input/touchscreen/rmi_function.c
new file mode 100644
index 0000000..e0f0bb1
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_function.c
@@ -0,0 +1,289 @@
+/**
+ * Synaptics Register Mapped Interface (RMI4) - RMI Function Module.
+ * Copyright (C) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+
+#include "rmi_drvr.h"
+#include "rmi_function.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_f01.h"
+#include "rmi_f05.h"
+#include "rmi_f11.h"
+#include "rmi_f19.h"
+#include "rmi_f34.h"
+
+
+#define FUNCTION_NAME_SIZE 10
+
+static int rmi_function_suspendable(struct rmi_function_info *rmifninfo);
+
+
+/* NOTE: Developer - add in any new RMI4 fn data info - function number
+ * and ptrs to report, config, init and detect functions.  This data is
+ * used to point to the functions that need to be called to config, init,
+ * detect and report data for the new RMI4 function. Refer to the RMI4
+ * specification for information on RMI4 functions.
+ */
+/* TODO: This will eventually be built dynamically, as individual function
+ * implementations registered.  For now, though we create it statically. */
+static struct rmi_function_ops supported_functions[] = {
+	/* Fn $01 - device control */
+	{
+		.function_number = RMI_F01_INDEX,
+		.inthandler = FN_01_inthandler,
+		.config = FN_01_config,
+		.init = FN_01_init,
+		.detect = FN_01_detect,
+		.attention = FN_01_attention,
+		.suspend = FN_01_suspend,
+		.resume = FN_01_resume,
+		.suspendable = rmi_function_suspendable},
+	/* Fn $05 - analog report */
+	{
+		.function_number = RMI_F05_INDEX,
+		.inthandler = FN_05_inthandler,
+		.config = FN_05_config,
+		.init = FN_05_init,
+		.detect = FN_05_detect,
+		.attention = NULL,
+		.suspend = NULL,
+		.resume = NULL,
+		.suspendable = rmi_function_suspendable},
+	 /* Fn $11 - 2D sensing */
+	 {
+		 .function_number = RMI_F11_INDEX,
+		 .inthandler = FN_11_inthandler,
+		 .config = FN_11_config,
+		 .init = FN_11_init,
+		 .detect = FN_11_detect,
+		 .attention = NULL,
+		 .suspend = NULL,
+		 .resume = NULL,
+		 .suspendable = rmi_function_suspendable},
+	/* Fn $19 - buttons */
+	{
+		.function_number = RMI_F19_INDEX,
+		.inthandler = FN_19_inthandler,
+		.config = FN_19_config,
+		.init = FN_19_init,
+		.detect = FN_19_detect,
+		.attention = NULL,
+		.suspend = NULL,
+		.resume = NULL,
+		.suspendable = rmi_function_suspendable},
+	/* Fn $34 - firmware reflash */
+	{
+		.function_number = RMI_F34_INDEX,
+		.inthandler = FN_34_inthandler,
+		.config = FN_34_config,
+		.init = FN_34_init,
+		.detect = FN_34_detect,
+		.attention = FN_34_attention,
+		.suspend = NULL,
+		.resume = NULL,
+		.suspendable = rmi_function_suspendable},
+};
+
+/* This function is here to provide a way for external modules to access the
+ * functions list.  It will try to find a matching function base on the passed
+ * in RMI4 function number and return  the pointer to the struct rmi_functions
+ * if a match is found or NULL if not found.
+ */
+struct rmi_function_ops *rmi_find_function(int function_number)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(supported_functions); i++) {
+		if (function_number == supported_functions[i].function_number)
+			return &supported_functions[i];
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(rmi_find_function);
+
+static int rmi_function_suspendable(struct rmi_function_info *rmifninfo)
+{
+	return 1;
+}
+
+static void rmi_function_config(struct rmi_function_device *function)
+{
+	pr_debug("%s: rmi_function_config", __func__);
+}
+
+/* Just a stub for now.
+ */
+static int rmi_function_suspend(struct device *dev, pm_message_t state)
+{
+	pr_info("%s: function suspend called.", __func__);
+	return 0;
+}
+
+/* Just a stub for now.
+ */
+static int rmi_function_resume(struct device *dev)
+{
+	pr_info("%s: function resume called.", __func__);
+	return 0;
+}
+
+int rmi_function_register_driver(struct rmi_function_driver *drv,
+				int function_number)
+{
+	int retval = 0;
+	char *driver_name;
+
+	pr_info("%s: Registering function driver for F%02x.\n", __func__,
+		function_number);
+
+
+	/* Create a function device and function driver for this Fn */
+	driver_name = kzalloc(FUNCTION_NAME_SIZE, GFP_KERNEL);
+	if (!driver_name) {
+		pr_err("%s: Error allocating memory for "
+		     "rmi_function_driver name.", __func__);
+		return -ENOMEM;
+	}
+	snprintf(driver_name, FUNCTION_NAME_SIZE, "fn%02x", function_number);
+
+	drv->drv.name = driver_name;
+	drv->module = drv->drv.owner;
+
+	drv->drv.suspend = rmi_function_suspend;
+	drv->drv.resume = rmi_function_resume;
+
+	/* register the sensor driver */
+	retval = driver_register(&drv->drv);
+	if (retval) {
+		pr_err("%s: Failed driver_register %d\n", __func__, retval);
+		drv->drv.name = NULL;
+		kfree(driver_name);
+	}
+
+	return retval;
+}
+EXPORT_SYMBOL(rmi_function_register_driver);
+
+void rmi_function_unregister_driver(struct rmi_function_driver *drv)
+{
+	char *driver_name =  (char *) drv->drv.name;
+
+	pr_info("%s: Unregistering function driver.\n", __func__);
+
+	/* TODO: Unregister the devices first. */
+	driver_unregister(&drv->drv);
+	kfree(driver_name);
+}
+EXPORT_SYMBOL(rmi_function_unregister_driver);
+
+int rmi_function_register_device(struct rmi_function_device *function_device,
+				 int fnNumber)
+{
+	struct input_dev *input;
+	int retval = 0;
+
+	pr_info("%s: Registering function device for F%02x.\n", __func__,
+		fnNumber);
+
+	/* make name - fn11, fn19, etc. */
+	dev_set_name(&function_device->dev, "%sfn%02x",
+		     function_device->sensor->drv.name, fnNumber);
+	dev_set_drvdata(&function_device->dev, function_device);
+	retval = device_register(&function_device->dev);
+	if (retval) {
+		pr_err("%s:  Failed device_register for function device.\n",
+		       __func__);
+		return retval;
+	}
+
+	input = input_allocate_device();
+	if (input == NULL) {
+		pr_err("%s:  Failed to allocate memory for a "
+		       "new input device.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+
+	input->name = dev_name(&function_device->dev);
+	input->phys = "rmi_function";
+	function_device->input = input;
+
+	/* init any input specific params for this function */
+	function_device->rmi_funcs->init(function_device);
+
+	retval = input_register_device(input);
+	if (retval) {
+		pr_err("%s:  Failed input_register_device.\n", __func__);
+		goto error_exit;
+	}
+
+	rmi_function_config(function_device);
+
+	return retval;
+
+error_exit:
+	kfree(input);
+	return retval;
+}
+EXPORT_SYMBOL(rmi_function_register_device);
+
+void rmi_function_unregister_device(struct rmi_function_device *dev)
+{
+	pr_info("%s: Unregistering function device.n", __func__);
+
+	input_unregister_device(dev->input);
+	device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL(rmi_function_unregister_device);
+
+static int __init rmi_function_init(void)
+{
+	pr_debug("%s: RMI Function Init\n", __func__);
+
+	return 0;
+}
+
+static void __exit rmi_function_exit(void)
+{
+	pr_debug("%s: RMI Function Exit\n", __func__);
+}
+
+module_init(rmi_function_init);
+module_exit(rmi_function_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Function Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi_function.h b/drivers/input/touchscreen/rmi_function.h
new file mode 100644
index 0000000..029f935
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_function.h
@@ -0,0 +1,175 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function Device Header File.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_FUNCTION_H)
+#define _RMI_FUNCTION_H
+
+#include <linux/input.h>
+#include <linux/device.h>
+
+/* For each function present on the RMI device, there will be a corresponding
+ * entry in the functions list of the rmi_sensor_driver structure.  This entry
+ * gives information about the number of data sources and the number of data
+ * registers associated with the function.
+ */
+struct rmi_function_info {
+	/* The sensor this function belongs to.
+	 */
+	struct rmi_sensor_driver *sensor;
+
+	/* A device associated with this function.
+	 */
+	struct rmi_function_device *function_device;
+
+	unsigned char function_number;
+
+	/* This is the number of data sources associated with the function. */
+	unsigned char num_data_sources;
+
+	/* This is the interrupt register and mask - needed for enabling the
+	 *  interrupts and for checking what source had caused the attention
+	 * line interrupt.
+	 */
+	unsigned char interrupt_register;
+	unsigned char interrupt_mask;
+
+	/* This is the RMI function descriptor associated with this function.
+	 *  It contains the Base addresses for the functions query, command,
+	 *  control, and data registers.
+	 */
+	struct rmi_function_descriptor function_descriptor;
+
+	/* pointer to data specific to a functions implementation. */
+	void *fndata;
+
+	/* A list of the function information.
+	 *  This list uses the standard kernel linked list implementation.
+	 *  Documentation on on how to use it can be found at
+	 *  http://isis.poly.edu/kulesh/stuff/src/klist/.
+	 */
+	struct list_head link;
+};
+
+/* This struct is for creating a list of RMI4 functions that have data sources
+associated with them. This is to facilitate adding new support for other
+data sources besides 2D sensors.
+To add a new data source support, the developer will create a new file
+and add these 4 functions below with FN$## in front of the names - where
+## is the hex number for the function taken from the RMI4 specification.
+
+The function number will be associated with this and later will be used to
+match the RMI4 function to the 4 functions for that RMI4 function number.
+The user will also have to add code that adds the new rmi_functions item
+to the global list of RMI4 functions and stores the pointers to the 4
+functions in the function pointers.
+ */
+struct rmi_function_ops {
+	unsigned char function_number;
+
+	/* Pointers to function specific functions for interruptHandler,
+	 * config, init, detect and attention. These ptrs. need to be filled
+	 * in for every RMI4 function that has data source(s) associated with
+	 * it - like fn $11 (2D sensors), fn $19 (buttons), etc. Each RMI4
+	 * function that has data sources will be added into a list that is
+	 * used to match the function number against the number stored here.
+	 *
+	 * The sensor implementation will call this whenever and IRQ is
+	 * dispatched that this function is interested in.
+	 */
+	void (*inthandler) (struct rmi_function_info *rfi,
+			    unsigned int asserted_IRQs);
+
+	int (*config) (struct rmi_function_info *rmifninfo);
+	int (*init) (struct rmi_function_device *function_device);
+	int (*detect) (struct rmi_function_info *rmifninfo);
+	/* If this is non-null, the sensor implementation will call this
+	 * whenever the ATTN line is asserted.
+	 */
+	void (*attention) (struct rmi_function_info *rmifninfo);
+	/**
+	 *  suspend/resume provided from each function
+	 */
+	int (*suspend) (struct rmi_function_info *rmifninfo);
+	void (*resume) (struct rmi_function_info *rmifninfo);
+	/**
+	 *  suspendable
+	 *  return zero if the function cannot be suspended at the moment
+	 *  nonzero if the function can be suspended
+	 */
+	int (*suspendable)(struct rmi_function_info *rmifninfo);
+};
+
+struct rmi_function_ops *rmi_find_function(int function_number);
+int rmi_functions_init(struct input_dev *inputdev);
+
+struct rmi_function_driver {
+	struct module *module;
+	struct device_driver drv;
+
+	/* Probe Function
+	 *  This function is called to give the function driver layer an
+	 *  opportunity to claim an RMI function.
+	 */
+	int (*probe) (struct rmi_function_driver *function);
+	/* Config Function
+	 *  This function is called after a successful probe.  It gives the
+	 *  function driver an opportunity to query and/or configure an RMI
+	 *  function before data starts flowing.
+	 */
+	void (*config) (struct rmi_function_driver *function);
+
+	unsigned short query_base_address;
+	unsigned short control_base_address;
+	unsigned short command_base_address;
+	unsigned short data_base_address;
+	/* offset from start of interrupt registers */
+	unsigned int interrupt_register_offset;
+	unsigned int interrupt_mask;
+
+	/* Pointer to the corresponding phys driver info for this sensor.
+	 * The phys driver has the pointers to read, write, etc.  Probably
+	 * don't need it here - used down in bus driver and sensor driver. */
+	struct rmi_phys_driver *rpd;
+
+	struct list_head function_drivers;
+};
+
+struct rmi_function_device {
+	struct rmi_function_driver *function;
+	struct device dev;
+	struct input_dev *input;
+	/* need this to be bound to phys driver layer */
+	struct rmi_sensor_driver *sensor;
+
+	/* The function ptrs to the config, init, detect and
+	 * report functions for this rmi function device. */
+	struct rmi_function_ops *rmi_funcs;
+	struct rmi_function_info *rfi;
+	struct list_head functions;	/* link functions into list */
+};
+
+int rmi_function_register_device(struct rmi_function_device *dev,
+				 int function_number);
+#endif
diff --git a/drivers/input/touchscreen/rmi_sensor.c b/drivers/input/touchscreen/rmi_sensor.c
new file mode 100644
index 0000000..c40ba37
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_sensor.c
@@ -0,0 +1,1059 @@
+/**
+ * Synaptics Register Mapped Interface (RMI4) - RMI Sensor Module.
+ * Copyright (C) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_function.h"
+#include "rmi_sensor.h"
+
+/* Context data for each sensor.
+ */
+struct sensor_instance_data {
+	unsigned char pdt_props;
+	unsigned char bsr;
+};
+
+#define HAS_BSR_MASK 0x20
+#define HAS_NONSTANDARD_PDT_MASK 0x40
+
+static bool has_bsr(struct sensor_instance_data *instance_data)
+{
+	return (instance_data->pdt_props & HAS_BSR_MASK) != 0;
+}
+
+long polltime = 25000000;	/* Shared with rmi_function.c. */
+EXPORT_SYMBOL(polltime);
+module_param(polltime, long, 0644);
+MODULE_PARM_DESC(polltime, "How long to wait between polls (in nano seconds).");
+
+#define PDT_START_SCAN_LOCATION 0x00E9
+#define PDT_END_SCAN_LOCATION 0x0005
+#define PDT_ENTRY_SIZE 0x0006
+#define PDT_PROPERTIES_LOCATION 0x00EF
+#define BSR_LOCATION 0x00FE
+
+static DEFINE_MUTEX(rfi_mutex);
+
+struct rmi_function_ops *rmi_find_function(int function_number);
+
+/* sysfs files for sensor attributes for BSR register value. */
+static ssize_t rmi_sensor_hasbsr_show(struct device *dev,
+				      struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_sensor_bsr_show(struct device *dev,
+				   struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_sensor_bsr_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count);
+
+static struct device_attribute attrs[] = {
+	__ATTR(hasbsr, 0444,
+	       rmi_sensor_hasbsr_show, rmi_store_error),	/* RO attr */
+	__ATTR(bsr, 0666,
+	       rmi_sensor_bsr_show, rmi_sensor_bsr_store)	/* RW attr */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void rmi_sensor_early_suspend(struct early_suspend *h);
+static void rmi_sensor_late_resume(struct early_suspend *h);
+#endif
+
+int rmi_read(struct rmi_sensor_driver *sensor, unsigned short address,
+	     char *dest)
+{
+	struct rmi_phys_driver *rpd = sensor->rpd;
+	if (!rpd)
+		return -ENODEV;
+	return rpd->read(rpd, address, dest);
+}
+EXPORT_SYMBOL(rmi_read);
+
+int rmi_write(struct rmi_sensor_driver *sensor, unsigned short address,
+	      unsigned char data)
+{
+	struct rmi_phys_driver *rpd = sensor->rpd;
+	if (!rpd)
+		return -ENODEV;
+	return rpd->write(rpd, address, data);
+}
+EXPORT_SYMBOL(rmi_write);
+
+int rmi_read_multiple(struct rmi_sensor_driver *sensor, unsigned short address,
+		      char *dest, int length)
+{
+	struct rmi_phys_driver *rpd = sensor->rpd;
+	if (!rpd)
+		return -ENODEV;
+	return rpd->read_multiple(rpd, address, dest, length);
+}
+EXPORT_SYMBOL(rmi_read_multiple);
+
+int rmi_write_multiple(struct rmi_sensor_driver *sensor, unsigned short address,
+		       unsigned char *data, int length)
+{
+	struct rmi_phys_driver *rpd = sensor->rpd;
+	if (!rpd)
+		return -ENODEV;
+	return rpd->write_multiple(rpd, address, data, length);
+}
+EXPORT_SYMBOL(rmi_write_multiple);
+
+/* Utility routine to set bits in a register. */
+int rmi_set_bits(struct rmi_sensor_driver *sensor, unsigned short address,
+		 unsigned char bits)
+{
+	unsigned char reg_contents;
+	int retval;
+
+	retval = rmi_read(sensor, address, &reg_contents);
+	if (retval)
+		return retval;
+	reg_contents = reg_contents | bits;
+	retval = rmi_write(sensor, address, reg_contents);
+	if (retval == 1)
+		return 0;
+	else if (retval == 0)
+		return -EINVAL;	/* TODO: What should this be? */
+	return retval;
+}
+EXPORT_SYMBOL(rmi_set_bits);
+
+/* Utility routine to clear bits in a register. */
+int rmi_clear_bits(struct rmi_sensor_driver *sensor, unsigned short address,
+		   unsigned char bits)
+{
+	unsigned char reg_contents;
+	int retval;
+
+	retval = rmi_read(sensor, address, &reg_contents);
+	if (retval)
+		return retval;
+	reg_contents = reg_contents & ~bits;
+	retval = rmi_write(sensor, address, reg_contents);
+	if (retval == 1)
+		return 0;
+	else if (retval == 0)
+		return -EINVAL;	/* TODO: What should this be? */
+	return retval;
+}
+EXPORT_SYMBOL(rmi_clear_bits);
+
+/* Utility routine to set the value of a bit field in a register. */
+int rmi_set_bit_field(struct rmi_sensor_driver *sensor, unsigned short address,
+		      unsigned char field_mask, unsigned char bits)
+{
+	unsigned char reg_contents;
+	int retval;
+
+	retval = rmi_read(sensor, address, &reg_contents);
+	if (retval)
+		return retval;
+	reg_contents = (reg_contents & ~field_mask) | bits;
+	retval = rmi_write(sensor, address, reg_contents);
+	if (retval == 1)
+		return 0;
+	else if (retval == 0)
+		return -EINVAL;	/* TODO: What should this be? */
+	return retval;
+}
+EXPORT_SYMBOL(rmi_set_bit_field);
+
+bool rmi_polling_required(struct rmi_sensor_driver *sensor)
+{
+	return sensor->polling_required;
+}
+EXPORT_SYMBOL(rmi_polling_required);
+
+/* Keeps track of how many sensors we've seen so far.  TODO: What happens
+ * if we disconnect from a sensor?  Does it sensor number get recycled?
+ */
+static int sensor_count;
+
+/* Sensors are identified starting at 0 and working up.  This will retrieve
+ * the current sensor number, and increment the sensor_count.
+ */
+int rmi_next_sensor_id()
+{
+	int id = sensor_count;
+	sensor_count++;
+	return id;
+}
+EXPORT_SYMBOL(rmi_next_sensor_id);
+
+/* Functions can call this in order to dispatch IRQs. */
+void dispatchIRQs(struct rmi_sensor_driver *sensor, unsigned int irq_status)
+{
+	struct rmi_function_info *function_info;
+
+	list_for_each_entry(function_info, &sensor->functions, link) {
+		if ((function_info->interrupt_mask & irq_status) &&
+				function_info->function_device->rmi_funcs->
+				inthandler) {
+			/* Call the function's interrupt handler. */
+			function_info->function_device->rmi_funcs->
+				inthandler(function_info,
+					(function_info->
+					interrupt_mask & irq_status));
+		}
+	}
+}
+
+/*
+ * This is the function we pass to the RMI4 subsystem so we can be notified
+ * when attention is required.  It may be called in interrupt context.
+ */
+static void attention(struct rmi_phys_driver *physdrvr, int instance)
+{
+	/* All we have to do is schedule work. */
+	schedule_work(&(physdrvr->sensor->work));
+}
+
+/* This notifies any interested functions that there is an Attention interrupt.
+ * The interested functions should take appropriate actions (such as reading
+ * the interrupt status register and dispatching any appropriate RMI4
+ * interrupts).
+ */
+void attn_notify(struct rmi_sensor_driver *sensor)
+{
+	struct rmi_function_info *function_info;
+
+	list_for_each_entry(function_info, &sensor->functions, link) {
+		if (function_info->function_device
+		    && function_info->function_device->rmi_funcs->attention) {
+			function_info->function_device->rmi_funcs->
+			    attention(function_info);
+		}
+	}
+}
+
+/* This is the worker function - for now it simply has to call attn_notify.
+ * This work should be scheduled whenever an ATTN interrupt is asserted by
+ * the touch sensor.  We then call attn_notify to dispatch notification of
+ * the ATTN interrupt to all interested functions. After all the attention
+ * handling functions have returned, it is presumed safe to re-enable the
+ * Attention interrupt.
+ */
+static void sensor_work_func(struct work_struct *work)
+{
+	struct rmi_sensor_driver *sensor =
+			container_of(work, struct rmi_sensor_driver, work);
+	struct rmi_sensor_device *sensor_dev = sensor->sensor_device;
+
+	mutex_lock(&sensor->work_lock);
+	attn_notify(sensor);
+
+	/* we only need to enable the irq if doing interrupts */
+	/*
+	 * if suspend operation occurs and this is the function during execution
+	 * we cannot enable irq again
+	 */
+	if (!rmi_polling_required(sensor) && !sensor_dev->device_is_suspended)
+		enable_irq(sensor->rpd->irq);
+	mutex_unlock(&sensor->work_lock);
+}
+
+/* This is the timer function for polling - it simply has to schedule work
+ * and restart the timer. */
+static enum hrtimer_restart sensor_poll_timer_func(struct hrtimer *timer)
+{
+	struct rmi_sensor_driver *sensor =
+			container_of(timer, struct rmi_sensor_driver, timer);
+
+	if (!work_pending(&sensor->work))
+		schedule_work(&sensor->work);
+	hrtimer_start(&sensor->timer, ktime_set(0, polltime), HRTIMER_MODE_REL);
+	return HRTIMER_NORESTART;
+}
+
+/* This is the probe function passed to the RMI4 subsystem that gives us a
+ * chance to recognize an RMI4 device.  In this case, we're looking for
+ * Synaptics devices that have data sources - such as touch screens, buttons,
+ * etc.
+ *
+ * TODO: Well, it used to do this.  I'm not sure it's required any more.
+ */
+static int probe(struct rmi_sensor_driver *sensor)
+{
+	struct rmi_phys_driver *rpd = sensor->rpd;
+	pr_debug("%s: PROBE CALLED", __func__);
+
+	if (!rpd) {
+		pr_err("%s: Invalid rmi physical driver - null ptr: %p\n",
+		       __func__, rpd);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void config(struct rmi_sensor_driver *sensor)
+{
+	/* For each data source we had detected print info and set up interrupts
+	   or polling. */
+	struct rmi_function_info *function_info;
+	struct rmi_phys_driver *rpd = sensor->rpd;
+	struct sensor_instance_data *instance_data =
+			sensor->sensor_device->sensordata;
+	int attr_count = 0;
+
+	int retval;
+
+	dev_dbg(&sensor->sensor_device->dev, "%s: CONFIG CALLED", __func__);
+
+	list_for_each_entry(function_info, &sensor->functions, link) {
+		/* Get and print some info about the data sources... */
+		struct rmi_function_ops *fn;
+		/* check if function number matches - if so call that
+		   config function */
+		fn = rmi_find_function(function_info->function_number);
+		if (fn) {
+			if (fn->config) {
+				fn->config(function_info);
+			} else {
+				dev_warn(&sensor->sensor_device->dev,
+					"%s: no config function for "
+					"function 0x%02x.\n", __func__,
+					function_info->function_number);
+			}
+		} else {
+			/* if no support found for this RMI4 function
+			   it means the developer did not add the
+			   appropriate function pointer list into the
+			   rmi4_supported_data_src_functions array and/or
+			   did not bump up the number of supported RMI4
+			   functions in rmi.h as required */
+			dev_err(&sensor->sensor_device->dev,
+			       "%s: no support found for function 0x%02x.\n",
+			       __func__, function_info->function_number);
+		}
+	}
+
+	retval = rpd->read(rpd, PDT_PROPERTIES_LOCATION,
+			   (char *) &instance_data->pdt_props);
+	if (retval) {
+		dev_warn(&sensor->sensor_device->dev,
+			"%s: Could not read PDT propertys from 0x%04x. "
+			"Assuming 0x00.\n",
+		       __func__, PDT_PROPERTIES_LOCATION);
+	}
+
+
+	dev_dbg(&sensor->sensor_device->dev, "%s: Creating sysfs files.",
+		__func__);
+	/* Set up sysfs device attributes. */
+	for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+		if (device_create_file(&sensor->sensor_device->dev,
+					&attrs[attr_count]) < 0) {
+			dev_err(&sensor->sensor_device->dev,
+				"%s: Failed to create sysfs file for %s.\n",
+				__func__, attrs[attr_count].attr.name);
+			goto error_exit;
+		}
+	}
+
+	if (rmi_polling_required(sensor)) {
+		/* We're polling driven, so set up the polling timer
+		   and timer function. */
+		hrtimer_init(&sensor->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		sensor->timer.function = sensor_poll_timer_func;
+		hrtimer_start(&sensor->timer, ktime_set(1, 0),
+			      HRTIMER_MODE_REL);
+	}
+
+error_exit:
+	for (attr_count--; attr_count >= 0; attr_count--)
+		device_remove_file(&sensor->sensor_device->dev,
+				   &attrs[attr_count]);
+	/* If you alloc anything, free it here. */
+}
+void *rmi_sensor_get_functiondata(struct rmi_sensor_driver *driver,
+				  unsigned char function_index)
+{
+	int i;
+
+	if (!driver->perfunctiondata)
+		return NULL;
+
+	for (i = 0; i < driver->perfunctiondata->count; i++) {
+		if (driver->perfunctiondata->functiondata[i].function_index ==
+		    function_index)
+			return driver->perfunctiondata->functiondata[i].data;
+	}
+
+	return NULL;
+}
+
+/*
+ *  final implementation of suspend/early_suspend function
+ */
+static int rmi_sensor_suspend(struct device *dev, pm_message_t state)
+{
+	struct rmi_sensor_device *sensor_device =
+	    container_of(dev, struct rmi_sensor_device, dev);
+	struct rmi_phys_driver *phys_drvr = sensor_device->driver->rpd;
+	struct rmi_sensor_driver *sensor_drvr = sensor_device->driver;
+	struct rmi_sensor_suspend_custom_ops *custom_ops =
+	    sensor_drvr->custom_suspend_ops;
+	int retval;
+	struct rmi_function_info *function_info;
+	bool canSuspend = true;
+
+	mutex_lock(&sensor_drvr->sensor_device->setup_suspend_flag);
+
+	if (sensor_device->device_is_suspended) {
+		mutex_unlock(&sensor_drvr->sensor_device->setup_suspend_flag);
+		return 0;
+	}
+
+	/* iterates all of the functions to make sure that we
+	 * can enter suspend mode. */
+	list_for_each_entry(function_info, &sensor_drvr->functions, link) {
+		if (function_info->function_device
+			&& function_info->function_device->
+				rmi_funcs->suspendable) {
+
+			if (!(function_info->function_device->rmi_funcs->
+			    suspendable(function_info))) {
+				canSuspend = false;
+				dev_err(dev, "%s: suspend fails, F0x%02X is "
+					"not suspendable", __func__,
+					function_info->function_number);
+				break;
+			}
+
+		}
+	}
+
+	if (!canSuspend) {
+		mutex_unlock(&sensor_drvr->sensor_device->setup_suspend_flag);
+		return -1;
+	}
+
+	/* set flag before disabling irq */
+	sensor_device->device_is_suspended = 1;
+
+	if (rmi_polling_required(sensor_drvr)) {
+		hrtimer_cancel(&(sensor_drvr->timer));
+	} else {
+		if (phys_drvr)
+			disable_irq(phys_drvr->irq);
+	}
+	retval = cancel_work_sync(&sensor_drvr->work);
+	if (retval && !(rmi_polling_required(sensor_drvr))) {
+		/* if work is pending ,suspend fail */
+		if (phys_drvr)
+			enable_irq(phys_drvr->irq);
+		/* reset suspend flag */
+		sensor_device->device_is_suspended = 0;
+		dev_err(dev, "%s: suspend fails, work pending", __func__);
+		retval = -1;
+		goto exit;
+	}
+
+	/* invoke the suspend handler of each functions of this sensor */
+	/* ex. we will call suspend of F01 in the loop*/
+	list_for_each_entry(function_info, &sensor_drvr->functions, link) {
+		if (function_info->function_device
+			&& function_info->function_device->rmi_funcs->suspend) {
+
+			retval = function_info->function_device->rmi_funcs->
+				suspend(function_info);
+			if (retval) {
+				/* reset suspend flag */
+				sensor_device->device_is_suspended = 0;
+
+				if (rmi_polling_required(sensor_drvr)) {
+					/* restart polling timer*/
+					hrtimer_start(&(sensor_drvr->timer),
+							ktime_set(1, 0),
+							HRTIMER_MODE_REL);
+				} else {
+					if (phys_drvr) {
+						/* re-enalbe irq*/
+						enable_irq(phys_drvr->irq);
+					}
+				}
+				dev_err(dev, "%s: failed to suspend F0x%02x.",
+					__func__,
+					function_info->function_number);
+				retval = -1;
+				goto exit;
+			}
+		}
+	}
+
+	/* apply customized settings */
+	if (custom_ops->rmi_sensor_custom_suspend)
+		custom_ops->rmi_sensor_custom_suspend();
+
+exit:
+	mutex_unlock(&sensor_drvr->sensor_device->setup_suspend_flag);
+	return retval;
+}
+
+/*
+ *  final implementation of resume/late_resume function
+ */
+static int rmi_sensor_resume(struct device *dev)
+{
+	struct rmi_sensor_device *sensor_device =
+	    container_of(dev, struct rmi_sensor_device, dev);
+	struct rmi_phys_driver *phys_drvr = sensor_device->driver->rpd;
+	struct rmi_sensor_driver *sensor_drvr = sensor_device->driver;
+	struct rmi_sensor_suspend_custom_ops *custom_ops =
+	    sensor_drvr->custom_suspend_ops;
+	struct rmi_function_info *function_info;
+
+	mutex_lock(&sensor_drvr->sensor_device->setup_suspend_flag);
+	if (sensor_device->device_is_suspended) {
+		/* reset suspend flag reenable irq */
+		sensor_device->device_is_suspended = 0;
+		/* apply customized settings */
+		if (custom_ops->rmi_sensor_custom_resume)
+			custom_ops->rmi_sensor_custom_resume();
+
+		/* invoke the resume handler of each functions of this sensor */
+		/* ex. we will call resume of F01 in the loop*/
+		list_for_each_entry(function_info,
+				&sensor_drvr->functions, link) {
+			if (function_info->function_device
+				&& function_info->function_device->
+					rmi_funcs->resume)
+				function_info->function_device->rmi_funcs->
+				    resume(function_info);
+		}
+
+		/* apply delay after setup hardware */
+		if (custom_ops->delay_resume)
+			mdelay(custom_ops->delay_resume);
+
+		if (rmi_polling_required(sensor_drvr)) {
+			hrtimer_start(&(sensor_drvr->timer), ktime_set(1, 0),
+				      HRTIMER_MODE_REL);
+		} else {
+			if (phys_drvr)
+				enable_irq(phys_drvr->irq);
+		}
+	}
+	mutex_unlock(&sensor_drvr->sensor_device->setup_suspend_flag);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/*
+ * Handler for early suspend
+ */
+static void rmi_sensor_early_suspend(struct early_suspend *h)
+{
+	struct rmi_sensor_device *sensor_device =
+	    container_of(h, struct rmi_sensor_device, early_suspend_handler);
+	pm_message_t state;
+	state.event = PM_EVENT_SUSPEND;
+	(void)rmi_sensor_suspend(&(sensor_device->dev), state);
+}
+
+/*
+ * Handler for late resume
+ */
+static void rmi_sensor_late_resume(struct early_suspend *h)
+{
+	struct rmi_sensor_device *sensor_device =
+	    container_of(h, struct rmi_sensor_device, early_suspend_handler);
+	(void)rmi_sensor_resume(&(sensor_device->dev));
+}
+#endif
+/*
+ * This method is called, whenever a new sensor device is added for the rmi
+ * bus.
+ *
+ * It will scan the devices PDT to determine the supported functions
+ * and create a new function device for each of these. It will read
+ * the query, control, command and data regsiters for the function
+ * to be used for each newly created function device.
+ *
+ * The sensor device is then bound to every function it supports.
+ *
+ */
+static int rmi_sensor_register_functions(struct rmi_sensor_driver *sensor)
+{
+	struct rmi_function_device *function;
+	unsigned int interrupt_register_count = 0;
+	struct rmi_phys_driver *rpd = sensor->rpd;
+	int i;
+	int j;
+	int interrupt_offset;
+	unsigned char interrupt_count = 0;
+	struct rmi_function_descriptor rmi_fd;
+	struct rmi_function_ops *fn;
+	int retval = 0;
+	struct device *dev = &sensor->sensor_device->dev;
+	struct rmi_function_info *function_info = NULL;
+
+	/* Read the Page Descriptor Table to determine what functions
+	 * are present */
+	dev_dbg(dev, "%s: Scanning page descriptors.", __func__);
+	for (i = PDT_START_SCAN_LOCATION;
+	     i >= PDT_END_SCAN_LOCATION; i -= PDT_ENTRY_SIZE) {
+
+		dev_dbg(dev, "%s: Reading page descriptor 0x%02x", __func__, i);
+		retval = rpd->read_multiple(rpd, i, (char *)&rmi_fd,
+					    sizeof(rmi_fd));
+		if (retval) {
+			/* failed to read next PDT entry - end PDT
+			   scan - this may result in an incomplete set
+			   of recognized functions - we could return
+			   an error here but the driver may still be
+			   viable for diagnostics and debugging so let's
+			   let it continue. */
+			dev_err(dev,
+			    "%s: Read error %d at PDT entry 0x%02x, "
+			     "ending scan.\n", __func__, retval, i);
+			break;
+		}
+
+		if (!RMI_IS_VALID_FUNCTION_ID(rmi_fd.function_number)) {
+			/* A zero or 0xff in the function number
+			   signals the end of the PDT */
+			dev_dbg(dev, "%s: Found end of PDT\n", __func__);
+			break;
+		}
+
+		dev_dbg(dev,
+			"%s: F%02x - queries %02x commands %02x control %02x "
+			"data %02x ints %02x",
+			__func__,
+			rmi_fd.function_number, rmi_fd.query_base_addr,
+			rmi_fd.command_base_addr, rmi_fd.control_base_addr,
+			rmi_fd.data_base_addr, rmi_fd.interrupt_source_count);
+
+		/* determine if the function is supported and if so
+		 * then bind this function device to the sensor */
+		function_info = kzalloc(sizeof(*function_info), GFP_KERNEL);
+		if (!function_info) {
+			dev_err(dev,
+			    "%s: out of memory for function F%02x.",
+			     __func__, rmi_fd.function_number);
+			retval = -ENOMEM;
+			goto exit_fail;
+		}
+		function_info->sensor = sensor;
+		function_info->function_number = rmi_fd.function_number & 0xff;
+		memcpy(&function_info->function_descriptor, &rmi_fd,
+				sizeof(rmi_fd));
+		function_info->num_data_sources =
+				rmi_fd.interrupt_source_count;
+		function_info->interrupt_register = interrupt_count / 8;
+		/* loop through interrupts for each source and or in a bit
+		 * to the interrupt mask for each. */
+		interrupt_offset = interrupt_count % 8;
+
+		for (j = interrupt_offset;
+				j < ((rmi_fd.interrupt_source_count & 0x7)
+					+ interrupt_offset);
+				j++) {
+			function_info->interrupt_mask |= 1 << j;
+		}
+		INIT_LIST_HEAD(&function_info->link);
+
+		/* Get the ptr to the detect function based on
+		 * the function number */
+		dev_dbg(dev, "%s: Checking for RMI function F%02x.", __func__,
+			rmi_fd.function_number);
+		fn = rmi_find_function(rmi_fd.function_number);
+		if (!fn) {
+			dev_err(dev,
+				"%s: couldn't find support for F%02X.",
+				__func__, rmi_fd.function_number);
+		} else {
+			retval = fn->detect(function_info);
+			if (retval)
+				dev_err(dev,
+				    "%s: Function detect for F%02x failed "
+				     "with %d.",
+				     __func__, rmi_fd.function_number, retval);
+
+			/* Create a function device and function driver. */
+			function = kzalloc(sizeof(*function), GFP_KERNEL);
+			if (!function) {
+				dev_err(dev,
+				    "%s: Error allocating memory for "
+				     "rmi_function_device.",
+				     __func__);
+				retval = -ENOMEM;
+				goto exit_fail;
+			}
+
+			function->dev.parent = &sensor->sensor_device->dev;
+			function->dev.bus = sensor->sensor_device->dev.bus;
+			function->rmi_funcs = fn;
+			function->sensor = sensor;
+			function->rfi = function_info;
+			function_info->function_device = function;
+
+			/* Check if we have an interrupt mask of 0 and a
+			 * non-NULL interrupt handler function and print a
+			 * debug message since we should never have this.
+			 */
+			if (function_info->interrupt_mask == 0
+			    && fn->inthandler != NULL) {
+				dev_warn(dev,
+				    "%s: Can't have a zero interrupt mask "
+				     "for function F%02x (which requires an "
+				     "interrupt handler).",
+				     __func__, rmi_fd.function_number);
+			}
+
+			/* Check if we have a non-zero interrupt mask and
+			 * a NULL interrupt handler function and print a debug
+			 * message since we should never have this.
+			 */
+			if (function_info->interrupt_mask != 0
+			    && fn->inthandler == NULL) {
+				dev_warn(dev,
+				    "%s: Can't have a non-zero interrupt "
+				     "mask %d for function F%02x with a NULL "
+				     "inthandler fn.\n",
+				     __func__, function_info->interrupt_mask,
+				     rmi_fd.function_number);
+			}
+
+			/* Register the rmi function device */
+			retval = rmi_function_register_device(function,
+						rmi_fd.function_number);
+			if (retval) {
+				dev_err(dev,
+				    "%s: Failed rmi_function_register_device.",
+				     __func__);
+				goto exit_fail;
+			}
+		}
+
+		/* bump interrupt count for next iteration. NOTE: The value 7
+		 * is reserved - for now, only bump up one for an interrupt
+		 * count of 7. */
+		if ((rmi_fd.interrupt_source_count & 0x7) == 0x7) {
+			interrupt_count += 1;
+		} else {
+			interrupt_count +=
+			    (rmi_fd.interrupt_source_count & 0x7);
+		}
+
+		/* link this function info to the RMI module infos list
+		 * of functions. */
+		if (function_info == NULL) {
+			dev_dbg(dev, "%s: WTF? function_info is null here.",
+				 __func__);
+		} else {
+			dev_dbg(dev, "%s: Adding F%02x with %d sources.",
+				 __func__, function_info->function_number,
+				 function_info->num_data_sources);
+
+			mutex_lock(&rfi_mutex);
+			list_add_tail(&function_info->link, &sensor->functions);
+			mutex_unlock(&rfi_mutex);
+		}
+		function_info = NULL;
+	}
+
+	dev_dbg(dev, "%s: Done scanning.", __func__);
+
+	/* calculate the interrupt register count - used in the
+	 * ISR to read the correct number of interrupt registers */
+	interrupt_register_count = (interrupt_count + 7) / 8;
+	/* TODO: Is interrupt_register_count needed by the sensor anymore? */
+	sensor->interrupt_register_count = interrupt_register_count;
+
+	return 0;
+
+exit_fail:
+	kfree(function_info);
+	return retval;
+}
+
+/* sysfs show and store fns for sensor dev */
+static ssize_t rmi_sensor_hasbsr_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_sensor_device *sensor = dev_get_drvdata(dev);
+	struct sensor_instance_data *instance_data =
+	    (struct sensor_instance_data *)sensor->sensordata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", has_bsr(instance_data));
+}
+
+static ssize_t rmi_sensor_bsr_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct rmi_sensor_device *sensor = dev_get_drvdata(dev);
+	struct sensor_instance_data *instance_data =
+	    (struct sensor_instance_data *)sensor->sensordata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->bsr);
+}
+
+static ssize_t rmi_sensor_bsr_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int retval;
+	struct rmi_sensor_device *sensor = dev_get_drvdata(dev);
+	struct sensor_instance_data *instance_data =
+	    (struct sensor_instance_data *)sensor->sensordata;
+	unsigned long val;
+
+	/* need to convert the string data to an actual value */
+	strict_strtoul(buf, 10, &val);
+
+	retval = rmi_write(sensor->driver, BSR_LOCATION, (unsigned char)val);
+	if (retval) {
+		dev_err(dev, "%s : failed to write bsr %u to 0x%x\n",
+		       __func__, (unsigned int)val, BSR_LOCATION);
+		return -EIO;
+	}
+
+	instance_data->bsr = val;
+
+	return count;
+}
+
+/* Call this to instantiate a new sensor driver.
+ */
+struct rmi_sensor_driver *rmi_sensor_create_driver(
+				struct rmi_sensor_device *sensor_device,
+				struct rmi_phys_driver *physical_driver,
+				struct rmi_sensordata *sensor_data)
+{
+	struct rmi_sensor_driver *driver =
+	    kzalloc(sizeof(struct rmi_sensor_driver), GFP_KERNEL);
+	if (!driver) {
+		dev_err(&sensor_device->dev,
+			"%s: Out of memory for rmi_sensor_driver\n",
+		       __func__);
+		goto error_exit;
+	}
+	driver->sensor_device = sensor_device;
+	driver->polling_required = physical_driver->polling_required;
+	driver->rpd = physical_driver;
+
+	mutex_init(&driver->work_lock);
+
+	if (sensor_data) {
+		driver->perfunctiondata = sensor_data->perfunctiondata;
+		/* pass reference to customized operations for suspend/resume */
+		driver->custom_suspend_ops = sensor_data->custom_suspend_ops;
+	}
+	INIT_LIST_HEAD(&driver->functions);
+
+	/* This will handle interrupts on the ATTN line (interrupt driven)
+	 * or will be called every poll interval (when we're not interrupt
+	 * driven).
+	 */
+	INIT_WORK(&driver->work, sensor_work_func);
+
+	return driver;
+
+error_exit:
+	rmi_sensor_destroy_driver(driver);
+	return NULL;
+}
+
+/* Call this when you're done with the sensor driver.  This will clean up any
+ * pending actions, cancel any running threads or works, and release all
+ * storage.
+ */
+void rmi_sensor_destroy_driver(struct rmi_sensor_driver *driver)
+{
+	kfree(driver);
+}
+
+int rmi_sensor_register_device(struct rmi_sensor_device *dev, int index)
+{
+	int status;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend *early_suspend_handler;
+#endif
+
+	pr_debug("%s: Registering sensor device.\n", __func__);
+
+	/* make name - sensor00, sensor01, etc. */
+	dev_set_name(&dev->dev, "sensor%02d", index);
+
+	dev->sensordata =
+	    kzalloc(sizeof(struct sensor_instance_data), GFP_KERNEL);
+	if (!dev->sensordata) {
+		dev_err(&dev->dev,
+		    "%s: Out of memory for sensor instance data.\n", __func__);
+		return -ENOMEM;
+	}
+
+	status = device_register(&dev->dev);
+
+	if (status < 0) {
+		dev_err(&dev->dev, "%s: device register failed with %d.",
+			__func__, status);
+		goto error_exit;
+	}
+
+	mutex_init(&dev->setup_suspend_flag);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	/* register early_suspend handler after device is registered
+	 */
+	early_suspend_handler = &(dev->early_suspend_handler);
+	early_suspend_handler->level =
+		EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	early_suspend_handler->suspend = rmi_sensor_early_suspend;
+	early_suspend_handler->resume = rmi_sensor_late_resume;
+	register_early_suspend(early_suspend_handler);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+error_exit:
+	kfree(dev->sensordata);
+	return status;
+}
+EXPORT_SYMBOL(rmi_sensor_register_device);
+
+static void rmi_sensor_unregister_device(struct rmi_sensor_device *rmisensordev)
+{
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend *early_suspend_handler;
+
+	/* unregister early_suspend handler before driver is unregistered
+	 */
+	early_suspend_handler =
+		    &(rmisensordev->early_suspend_handler);
+	unregister_early_suspend(early_suspend_handler);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+	dev_dbg(&rmisensordev->dev,
+		"%s: Unregistering sensor device.\n", __func__);
+
+	device_unregister(&rmisensordev->dev);
+}
+EXPORT_SYMBOL(rmi_sensor_unregister_device);
+
+#define DRIVER_NAME_CHARS	16
+
+int rmi_sensor_register_driver(struct rmi_sensor_driver *driver)
+{
+	static int index;
+	int ret;
+	char *drvrname;
+
+	pr_info("%s: Registering sensor driver.\n", __func__);
+	driver->dispatchIRQs = dispatchIRQs;
+	driver->attention = attention;
+	driver->config = config;
+	driver->probe = probe;
+
+	driver->drv.suspend = rmi_sensor_suspend;
+	driver->drv.resume = rmi_sensor_resume;
+	/* Create a function device and function driver for this Fn */
+	drvrname = kzalloc(DRIVER_NAME_CHARS, GFP_KERNEL);
+	if (!drvrname) {
+		pr_err
+		    ("%s: Error allocating memory for rmi_sensor_driver name.",
+		     __func__);
+		return -ENOMEM;
+	}
+	snprintf(drvrname, DRIVER_NAME_CHARS, "sensor%02d", index++);
+
+	driver->drv.name = drvrname;
+	driver->module = driver->drv.owner;
+
+	/* Register the sensor driver on the bus. */
+	ret = rmi_bus_register_sensor_driver(driver);
+	if (ret) {
+		pr_err("%s: Failed to register driver on bus, error = %d",
+		       __func__, ret);
+		goto exit_fail;
+	}
+
+	/* register the functions on the sensor */
+	ret = rmi_sensor_register_functions(driver);
+	if (ret) {
+		pr_err("%s: Failed rmi_sensor_register_functions %d",
+		       __func__, ret);
+		goto exit_fail;
+	}
+
+	/* configure the sensor - enable interrupts for each function,
+	 * init work, set polling timer or adjust report rate, etc. */
+	config(driver);
+
+	pr_debug("%s: sensor driver registration completed.", __func__);
+
+exit_fail:
+	kfree(drvrname);
+	return ret;
+}
+EXPORT_SYMBOL(rmi_sensor_register_driver);
+
+static void rmi_sensor_unregister_driver(struct rmi_sensor_driver *driver)
+{
+	pr_debug("%s: Unregistering sensor driver.\n", __func__);
+
+	/* Stop the polling timer if doing polling */
+	if (rmi_polling_required(driver))
+		hrtimer_cancel(&driver->timer);
+
+	flush_scheduled_work();	/* Make sure all scheduled work is stopped */
+
+	rmi_bus_register_sensor_driver(driver);
+}
+EXPORT_SYMBOL(rmi_sensor_unregister_driver);
+
+static int __init rmi_sensor_init(void)
+{
+	pr_debug("%s: RMI Sensor Init\n", __func__);
+	return 0;
+}
+
+static void __exit rmi_sensor_exit(void)
+{
+	pr_debug("%s: RMI Sensor Driver Exit\n", __func__);
+	flush_scheduled_work();	/* Make sure all scheduled work is stopped */
+}
+
+module_init(rmi_sensor_init);
+module_exit(rmi_sensor_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Sensor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rmi_sensor.h b/drivers/input/touchscreen/rmi_sensor.h
new file mode 100644
index 0000000..9adc698
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_sensor.h
@@ -0,0 +1,128 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) - RMI Sensor Module Header.
+ * Copyright (C) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ *
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_SENSOR_H)
+#define _RMI_SENSOR_H
+
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include "rmi_platformdata.h"
+
+struct rmi_sensor_driver {
+	struct module *module;
+	struct device_driver drv;
+	struct rmi_sensor_device *sensor_device;
+
+	/* Attention Function
+	 *  This function is called by the low level isr in the physical
+	 * driver. It merely schedules work to be done.
+	 */
+	void (*attention) (struct rmi_phys_driver *physdrvr, int instance);
+	/* Probe Function
+	 *  This function is called to give the sensor driver layer an
+	 *  opportunity to claim an RMI device.  The sensor layer cannot
+	 *  read RMI registers at this point since the rmi physical driver
+	 *  has not been bound to it yet.  Defer that to the config
+	 *  function call which occurs immediately after a successful probe.
+	 */
+	int (*probe) (struct rmi_sensor_driver *sensor);
+	/* Config Function
+	 *  This function is called after a successful probe.  It gives the
+	 *  sensor driver an opportunity to query and/or configure an RMI
+	 *  device before data starts flowing.
+	 */
+	void (*config) (struct rmi_sensor_driver *sensor);
+
+	/* Functions can call this in order to dispatch IRQs. */
+	void (*dispatchIRQs) (struct rmi_sensor_driver *sensor,
+			      unsigned int irq_status);
+
+	unsigned int interrupt_register_count;
+
+	bool polling_required;
+
+	/* pointer to the corresponding phys driver info for this sensor */
+	/* The phys driver has the pointers to read, write, etc. */
+	struct rmi_phys_driver *rpd;
+
+	struct hrtimer timer;
+	struct work_struct work;
+	struct mutex work_lock;
+
+	struct list_head functions;	/* List of rmi_function_infos */
+		/* Per function initialization data. */
+	struct rmi_functiondata_list *perfunctiondata;
+		/* non-default operation for suspend/resume */
+	struct rmi_sensor_suspend_custom_ops *custom_suspend_ops;
+};
+
+/* macro to get the pointer to the device_driver struct from the sensor */
+#define to_rmi_sensor_driver(drv) \
+	container_of(drv, struct rmi_sensor_driver, drv);
+
+struct rmi_sensor_device {
+	struct rmi_sensor_driver *driver;
+	struct device dev;
+
+	/* mutex for setting device_is_supended flag*/
+	struct mutex setup_suspend_flag;
+	int device_is_suspended;	/*it will be initialized to false(0) */
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	/* handler to handle early_suspend and late_resume */
+	struct early_suspend early_suspend_handler;
+#endif
+	/* pointer to data specific to a sensor implementation. */
+	void *sensordata;
+
+	struct list_head sensors;	/* link sensors into list */
+};
+
+int rmi_sensor_register_device(struct rmi_sensor_device *dev, int index);
+int rmi_sensor_register_driver(struct rmi_sensor_driver *driver);
+bool rmi_polling_required(struct rmi_sensor_driver *sensor);
+int rmi_next_sensor_id(void);
+
+void *rmi_sensor_get_functiondata(struct rmi_sensor_driver *driver,
+				  unsigned char function_index);
+
+
+/* Call this to instantiate a new sensor driver.
+ */
+struct rmi_sensor_driver *rmi_sensor_create_driver(
+			struct rmi_sensor_device *sensor_device,
+			struct rmi_phys_driver *physical_driver,
+			struct rmi_sensordata *sensor_data);
+
+/* Call this when you're done with the sensor driver.  This will clean up any
+ * pending actions, cancel any running threads or works, and release all
+ * storage.
+ */
+void rmi_sensor_destroy_driver(struct rmi_sensor_driver *driver);
+#endif

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
                   ` (2 preceding siblings ...)
  2011-07-01  5:19 ` [PATCH 3/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 5/9] " Christopher Heiny
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 718bcc8..8a517a4 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -41,6 +41,8 @@ obj-$(CONFIG_TOUCHSCREEN_QT602240)	+= qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C)	+=  rmi_bus.o rmi_sensor.o rmi_function.o rmi_f01.o rmi_f05.o rmi_f11.o rmi_f19.o rmi_f34.o rmi_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_SPI)	+=  rmi_bus.o rmi_sensor.o rmi_function.o rmi_f01.o rmi_f05.o rmi_f11.o rmi_f19.o rmi_f34.o rmi_spi.o
 obj-$(CONFIG_TOUCHSCREEN_TNETV107X)	+= tnetv107x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 61834ae..2b2f6dc 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -362,6 +362,36 @@ config TOUCHSCREEN_MIGOR
 	  To compile this driver as a module, choose M here: the
 	  module will be called migor_ts.
 
+config TOUCHSCREEN_SYNAPTICS_RMI4_I2C
+	tristate "Synaptics RMI4 I2C touchscreens"
+	depends on I2C
+	help
+	  Say Y here if you have a Synaptics RMI4 I2C touchscreen connected to
+	  your system. This enables support for Synaptics RMI4 over I2C based
+	  touchscreens.
+
+	  If unsure, say N.
+
+	  To compile this driver as a set of modules, choose M here: the
+	  modules will be called rmi_core, rmi_app_touchpad, rmi_phys_i2c.
+
+config TOUCHSCREEN_SYNAPTICS_RMI4_SPI
+	tristate "Synaptics RMI4 SPI touchscreens"
+	depends on SPI
+	help
+	  Say Y here if you have a Synaptics RMI4 SPI touchscreen connected to
+	  your system. This enables support for Synaptics RMI4 over SPI based
+	  touchscreens.
+
+	  If unsure, say N.
+
+	  To compile this driver as a set of modules, choose M here: the
+	  modules will be called rmi_core, rmi_app_touchpad, rmi_phys_spi.
+
+config SYNA_MULTI_TOUCH
+	bool "Synaptics pointing using multi-touch events"
+	depends on TOUCHSCREEN_SYNAPTICS_RMI4_I2C || TOUCHSCREEN_SYNAPTICS_RMI4_SPI
+
 config TOUCHSCREEN_TNETV107X
 	tristate "TI TNETV107X touchscreen support"
 	depends on ARCH_DAVINCI_TNETV107X
diff --git a/Documentation/input/synaptics-rmi4.txt b/Documentation/input/synaptics-rmi4.txt
new file mode 100644
index 0000000..80bbdcd
--- /dev/null
+++ b/Documentation/input/synaptics-rmi4.txt
@@ -0,0 +1,172 @@
+RMI4 Touchscreen Driver (rmi-ts)
+--------------------------------
+     Copyright (c) 2007 - 2011, Synaptics Incorporated
+
+This driver adds support for touchscreens and touchpads that use the RMI4
+register based protocol as documented here:
+    http://www.synaptics.com/sites/default/files/511-000136-01_revD.pdf
+
+Currently supported RMI4 functions are
+    F01 - Device Control
+    F11 - 2D multifinger
+    F19 - Capacitive Buttons
+    F34 - Reflash
+
+Physical protocols supported are I2C and SPI.
+
+///////////////////////////////////////////////////
+
+Structure of the driver
+
+   +-------+ +-------+    +-------+ +--------+
+   | Fn34  | | Fn11  |    |  Fn19 | |  Fn11  |   RMI4 Functions
+   *---|---+ +--|----+    +----|--+ +----|---*
+       |        |              |         |
+       |        |              |         |
+   +----------------+      +----------------+
+   | Sensor0        |      |  Sensor1       |    Sensors
+   +----------------+      +----------------+
+           |                      |
+           |                      |
+   +----------------------------------------+
+   |                RMI4 Bus                |    RMI Bus
+   *--|-----|------|--------------|---------*
+      |     |      |              |
+      |     |      |              |
+   +-----+-----+-------+--------------------+
+   | I2C | SPI | SMBus |         etc.       |    Physical Layer
+   +-----+-----+-------+--------------------+
+
+As seen in the ASCII art above, the driver is broken into four layers.
+
+The lowest layer (Physical Layer) provides access to the hardware bus for
+communications with the RMI4 devices themselves.  Implemented by modules
+such as rmi_i2c.c and rmi_spi.c, this layer provides a uniform API for
+reading and writing data to and from the RMI4 device(s).  Future support
+for additional hardware such as SMBus or CanBus is anticipated, but not
+currently scheduled.
+
+The RMI4 devices are presented as devices on the RMI bus (/sys/bus/rmi).  This
+allows us to use standard kernel driver mechanisms to match sensor drivers to
+physical devices, rather than having to write and maintain our own matching
+mechanism.  The RMI bus is implemented in rmi_bus.c.
+
+The sensor driver layer implements those operations that are associated with
+the RMI4 device, but not associated with any specific RMI4 function.  For
+example, it handles interrupts on the ATTN line, controls polling of the
+devices (when the ATTN line is not present), dispatches IRQ notifications
+between function drivers, and so on.  Sensor instances are matched to the
+devices on the RMI bus using standard kernel driver discovery and pairing
+mechanisms.  The sensor driver is implemented in rmi_sensor.c.
+
+At the top layer, RMI4 functions are handled as individual modules (rmi_f01.c,
+rmi_f11.c, and so on), in keeping with the overall RMI4 philosophy that
+the operation specific functions (aside from things such as IRQ notification)
+should be independent of one another.  This simplifies maintenance of
+individual functions, as well as making it much easier to add new function
+implementations.
+
+NOTE: At this time the function drivers are matched to sensor devices using
+a custom ad hoc mechanism in rmi_sensor.c.  A future rev of the driver will
+use standard kernel mechanisms for this, at which point a number of header
+files and public symbols will be retired.  It is strongly recommended that
+you DO NOT write code that depends on symbols defined in the individual
+function header files (rmi_f01.h, rmi_f11.h, and so on).
+
+
+///////////////////////////////////////////////////
+
+Supported functions
+
+RMI Function 01
+---------------
+
+TODO: Write this.
+
+
+RMI Function 11
+---------------
+
+TODO: Write more.
+
+F11 provides a number of built in transformation on the reported coordinates.
+These can be configured at build time via platform_data, or at run time via sysfs.
+The available transformations are:
+    swap - exchange X & Y axes
+    flip - invert X and/or Y axes
+    offset - adjust X and/or Y axis coordinates by a fix value
+    clip - constrain reported coordinates to a specified range
+Any specified transformations are applied in the same order as they are listed
+above: swap is done first, then flip, the offset, then clip.
+
+swap - this is a boolean parameter.  If set to true, the X and Y coordinates will
+be swapped before reporting. Swapping is done before any other transformation,
+which lets you specify the remaining transformations in a way that is compatible
+with the position of the sensor in the device in its default orientation.
+
+flip - this is a pair of boolean parameters that indicate whether the position
+or motion along either axis (or both) should be "flipped" before being passed to
+the input subsystem.  For relative motion, flipping is done by reversing the
+sign on the reported delta and clipping the resulting value to fit in a signed
+byte.  For absolute positions, the flipped value is computed as follows for X
+(Y is computed similarly):
+    Xflipped = Xmax - Xreported
+The flip transformation (if present) is applied after swap, but before offset
+or clip.
+
+offset - this is a pair of signed integer values (offsetX, offsetY) that will
+be added to the reported position before it is passed to the input subsystem.
+This can be used to translate the reported finger position with respect to the
+device touch suface.  An example of a situation where offset is used would be
+a touchscreen where the touch sensor is larger than the display, and the origin
+of the touch sensor is not coincident with the origin of the display.  Offset
+is applied after swap and flip transformations, but before clip.
+
+clip - this is a 4-tuple of unsigned integer values, indicating the minimum and
+maximum values that should be reported on each axis respectively, specified as
+    minX maxX minY maxY
+If a reported coordinate lies outside the [min..max] range, it will be clipped
+to the nearest boundary.  For example:
+    newX = max(min(maxX, reportedX), minX);
+Note that finger positions outside the clipping region are still reported as
+present - the position is merely clipped to the nearest boundary of the clipping
+region.
+
+
+
+RMI Function 19
+---------------
+
+TODO: Write this.
+
+
+RMI Function 34
+---------------
+
+TODO: Write this.
+
+
+///////////////////////////////////////////////////
+
+Configuring the driver
+
+General Configuration
+---------------------
+
+TODO: Describe how to configure when built as a kernel module.
+
+TODO: Describe how to configure when built as a loadable module.
+
+TODO: Describe how to manipulate configuration via /sys/bus/rmi.
+
+
+Configuring I2C
+---------------
+
+TODO: Write this.
+
+
+Configuring SPI
+---------------
+
+TODO: Write this.

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
                   ` (3 preceding siblings ...)
  2011-07-01  5:19 ` [PATCH 4/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 6/9] " Christopher Heiny
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_f01.h b/drivers/input/touchscreen/rmi_f01.h
new file mode 100644
index 0000000..dad5615
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f01.h
@@ -0,0 +1,121 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $01 header.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ * There is only one function $01 for each RMI4 sensor. This will be
+ * the function that is used to set sensor control and configurations
+ * and check the interrupts to find the source function that is interrupting.
+ *
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_F01_H)
+#define _RMI_F01_H
+
+/*  This encapsulates the information found using the RMI4 Function $01
+ *  query registers. There is only one Function $01 per device.
+ *
+ *  Assuming appropriate endian-ness, you can populate most of this
+ *  structure by reading query registers starting at the query base address
+ *  that was obtained from RMI4 function 0x01 function descriptor info read
+ *  from the Page Descriptor Table.
+ *
+ *  Specific register information is provided in the comments for each field.
+ *  For further reference, please see the "Synaptics RMI 4 Interfacing
+ *  Guide" document : go to http://www.synaptics.com/developers/manuals - and
+ *  select "Synaptics RMI 4 Interfacting Guide".
+ */
+#define F01_PRODUCT_INFO_LENGTH 2
+#define F01_DATE_CODE_LENGTH 3
+#define F01_PRODUCT_ID_LENGTH 10
+struct rmi_F01_query {
+	/* The manufacturer identification byte. */
+	unsigned char mfgid;
+
+	/* The Product Properties information. */
+	unsigned char properties;
+
+	/* The product info bytes. */
+	unsigned char prod_info[F01_PRODUCT_INFO_LENGTH];
+
+	/* Date Code - Year, Month, Day. */
+	unsigned char date_code[F01_DATE_CODE_LENGTH];
+
+	/* Tester ID (14 bits). */
+	unsigned short tester_id;
+
+	/* Serial Number (14 bits). */
+	unsigned short serial_num;
+
+	/* A null-terminated string that identifies this particular product. */
+	char prod_id[F01_PRODUCT_ID_LENGTH];
+};
+
+/* This encapsulates the F01 Device Control control registers.
+ * TODO: This isn't right.  The number of interrupt enables needs to be
+ * determined dynamically as the sensor is initialized.  Fix this.
+ */
+struct rmi_F01_control {
+	unsigned char device_control;
+	unsigned char interrupt_enable[1];
+};
+
+
+/* This encapsulates the F01 Device Control data registers.
+ * TODO: This isn't right.  The number of irqs needs to be determined
+ * dynamically as the sensor is initialized.  Fix this.
+ */
+struct rmi_F01_data {
+	unsigned char device_status;
+	unsigned char irqs[1];
+};
+
+
+void FN_01_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs);
+int FN_01_config(struct rmi_function_info *rmifninfo);
+int FN_01_init(struct rmi_function_device *function_device);
+int FN_01_detect(struct rmi_function_info *rmifninfo);
+void FN_01_attention(struct rmi_function_info *rmifninfo);
+int FN_01_suspend(struct rmi_function_info *rmifninfo);
+void FN_01_resume(struct rmi_function_info *rmifninfo);
+
+#define RMI_F01_SLEEP_MODE_MASK 0x03
+/* Position of bits in control register. */
+#define RMI_F01_SLEEP_MODE_OFFSET 0
+
+#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)
+
+/* This bit is used to disable current sleep mode. */
+#define RMI_F01_NO_SLEEP_MASK 0x04
+/* Position of bits in control register. */
+#define RMI_F01_NO_SLEEP_OFFSET 2
+
+#define RMI_NO_SLEEP_ENABLE (0x01)
+#define RMI_NO_SLEEP_DISABLE (0x00)
+
+#endif
diff --git a/drivers/input/touchscreen/rmi_f01.c b/drivers/input/touchscreen/rmi_f01.c
new file mode 100644
index 0000000..48395e4
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f01.c
@@ -0,0 +1,825 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $01 support for sensor
+ * control and configuration.
+ *
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/param.h>
+#include <linux/stat.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_platformdata.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f01.h"
+
+/* Query register field positions. */
+#define F01_MFG_ID_POS 0
+#define F01_PROPERTIES_POS 1
+#define F01_PRODUCT_INFO_POS 2
+#define F01_DATE_CODE_POS 4
+#define F01_TESTER_ID_POS 7
+#define F01_SERIAL_NUMBER_POS 9
+#define F01_PRODUCT_ID_POS 11
+#define F01_DATE_CODE_YEAR 0
+#define F01_DATE_CODE_MONTH 1
+#define F01_DATE_CODE_DAY 2
+
+/* Control register bits. */
+#define F01_CONFIGURED (1 << 7)
+#define NONSTANDARD_REPORT_RATE (1 << 6)
+
+/* Command register bits. */
+#define F01_RESET 1
+#define F01_SHUTDOWN (1 << 1)
+
+/* Data register 0 bits. */
+#define F01_UNCONFIGURED (1 << 7)
+#define F01_FLASH_PROGRAMMING_MODE (1 << 6)
+#define F01_STATUS_MASK 0x0F
+
+/** Context data for each F01 we find.
+ */
+struct f01_instance_data {
+	struct rmi_F01_control *control_registers;
+	struct rmi_F01_data *data_registers;
+	struct rmi_F01_query *query_registers;
+
+	bool nonstandard_report_rate;
+	/* original mode before suspend */
+	unsigned char original_sleepmode;
+	/* original no sleep setting */
+	unsigned char original_nosleep;
+};
+static void set_sensor_sleepmode(struct rmi_function_info *functionInfo,
+			unsigned char sleepmode, unsigned char nosleep);
+
+static ssize_t rmi_fn_01_productinfo_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf);
+
+static ssize_t rmi_fn_01_productid_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+
+static ssize_t rmi_fn_01_manufacturer_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf);
+
+static ssize_t rmi_fn_01_datecode_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf);
+
+static ssize_t rmi_fn_01_reportrate_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf);
+
+static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count);
+
+static ssize_t rmi_fn_01_reset_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count);
+
+static ssize_t rmi_fn_01_testerid_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf);
+
+static ssize_t rmi_fn_01_serialnumber_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf);
+
+static ssize_t rmi_fn_01_sleepmode_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+
+static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count);
+static ssize_t rmi_fn_01_nosleep_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+
+static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count);
+
+static struct device_attribute attrs[] = {
+	__ATTR(productinfo, 0444,
+	       rmi_fn_01_productinfo_show, rmi_store_error),	/* RO attr */
+	__ATTR(productid, 0444,
+	       rmi_fn_01_productid_show, rmi_store_error),	/* RO attr */
+	__ATTR(manufacturer, 0444,
+	       rmi_fn_01_manufacturer_show, rmi_store_error),	/* RO attr */
+	__ATTR(datecode, 0444,
+	       rmi_fn_01_datecode_show, rmi_store_error),	/* RO attr */
+	__ATTR(reportrate, 0644,
+	       rmi_fn_01_reportrate_show, rmi_fn_01_reportrate_store),	/* RW */
+	__ATTR(reset, 0200,
+	       rmi_show_error, rmi_fn_01_reset_store),	/* WO attr */
+	__ATTR(testerid, 0444,
+	       rmi_fn_01_testerid_show, rmi_store_error),	/* RO attr */
+	__ATTR(serialnumber, 0444,
+	       rmi_fn_01_serialnumber_show, rmi_store_error),	/* RO attr */
+	__ATTR(sleepmode, (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH),
+	       rmi_fn_01_sleepmode_show, rmi_fn_01_sleepmode_store),	/* RW */
+	__ATTR(nosleep, (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH),
+			rmi_fn_01_nosleep_show, rmi_fn_01_nosleep_store) /*RW*/
+};
+
+static int set_report_rate(struct rmi_function_info *function_info,
+			   bool nonstandard)
+{
+	if (nonstandard) {
+		return rmi_set_bits(function_info->sensor,
+			function_info->function_descriptor.control_base_addr,
+			NONSTANDARD_REPORT_RATE);
+	} else {
+		return rmi_clear_bits(function_info->sensor,
+			function_info->function_descriptor.control_base_addr,
+			NONSTANDARD_REPORT_RATE);
+	}
+}
+
+static void read_query_registers(struct rmi_function_info *rmifninfo)
+{
+	unsigned char query_buffer[21];
+	int retval;
+	struct f01_instance_data *instance_data = rmifninfo->fndata;
+	struct rmi_F01_query *query_registers = instance_data->query_registers;
+
+	/* Read the query info and unpack it. */
+	retval = rmi_read_multiple(rmifninfo->sensor,
+			  rmifninfo->function_descriptor.query_base_addr,
+		   query_buffer, ARRAY_SIZE(query_buffer));
+	if (retval) {
+		pr_err("%s : Could not read F01 query registers at "
+			"0x%02x. Error %d.\n", __func__,
+			rmifninfo->function_descriptor.query_base_addr,
+			retval);
+		/* Presumably if the read fails, the buffer should be all
+		 * zeros, so we're OK to continue. */
+	}
+	query_registers->mfgid = query_buffer[F01_MFG_ID_POS];
+	query_registers->properties = query_buffer[F01_PROPERTIES_POS];
+	query_registers->prod_info[0] =
+		query_buffer[F01_PRODUCT_INFO_POS] & 0x7F;
+	query_registers->prod_info[1] =
+		query_buffer[F01_PRODUCT_INFO_POS + 1] & 0x7F;
+	query_registers->date_code[F01_DATE_CODE_YEAR] =
+		query_buffer[F01_DATE_CODE_POS] & 0x1F;
+	query_registers->date_code[F01_DATE_CODE_MONTH] =
+		query_buffer[F01_DATE_CODE_POS + 1] & 0x0F;
+	query_registers->date_code[F01_DATE_CODE_DAY] =
+		query_buffer[F01_DATE_CODE_POS + 2] & 0x1F;
+	query_registers->tester_id =
+		(((unsigned short)query_buffer[F01_TESTER_ID_POS] & 0x7F) << 7)
+		| (query_buffer[F01_TESTER_ID_POS + 1] & 0x7F);
+	query_registers->serial_num =
+		(((unsigned short)query_buffer[F01_SERIAL_NUMBER_POS] & 0x7F)
+			<< 7)
+		| (query_buffer[F01_SERIAL_NUMBER_POS + 1] & 0x7F);
+	memcpy(query_registers->prod_id, &query_buffer[F01_PRODUCT_ID_POS],
+		F01_PRODUCT_ID_LENGTH);
+
+	pr_debug("%s: RMI4 Protocol Function $01 Query information\n",
+		__func__);
+	pr_debug("%s: Manufacturer ID: %d %s\n", __func__,
+		query_registers->mfgid,
+		query_registers->mfgid == 1 ? "(Synaptics)" : "");
+	pr_debug("%s: Product Properties: 0x%x\n", __func__,
+		query_registers->properties);
+	pr_debug("%s: Product Info: 0x%x 0x%x\n", __func__,
+		query_registers->prod_info[0], query_registers->prod_info[1]);
+	pr_debug("%s: Date Code: Year : %d Month: %d Day: %d\n", __func__,
+		query_registers->date_code[F01_DATE_CODE_YEAR],
+		query_registers->date_code[F01_DATE_CODE_MONTH],
+		query_registers->date_code[F01_DATE_CODE_DAY]);
+	pr_debug("%s: Tester ID: %d\n", __func__, query_registers->tester_id);
+	pr_debug("%s: Serial Number: 0x%x\n",
+		__func__, query_registers->serial_num);
+	pr_debug("%s: Product ID: %s\n", __func__, query_registers->prod_id);
+}
+
+
+void FN_01_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs)
+{
+	struct f01_instance_data *instance_data = rmifninfo->fndata;
+
+	pr_debug("%s: Read device status.", __func__);
+
+	if (rmi_read
+	    (rmifninfo->sensor, rmifninfo->function_descriptor.data_base_addr,
+	     &instance_data->data_registers->device_status)) {
+		pr_err("%s : Could not read F01 device status.\n", __func__);
+	}
+	pr_info("%s: read device status register.  Value 0x%02X.", __func__,
+		instance_data->data_registers->device_status);
+
+	if (instance_data->data_registers->device_status & F01_UNCONFIGURED) {
+		pr_info("%s: ++++ Device reset detected.", __func__);
+		/* TODO: Handle device reset appropriately.
+		 */
+	}
+}
+EXPORT_SYMBOL(FN_01_inthandler);
+
+/*
+ * This reads in the function $01 source data.
+ *
+ */
+void FN_01_attention(struct rmi_function_info *rmifninfo)
+{
+	struct f01_instance_data *instance_data = rmifninfo->fndata;
+	int retval;
+
+	/* TODO: Compute size to read and number of IRQ registers to processors
+	 * dynamically.  See comments in rmi.h. */
+	retval =
+	    rmi_read_multiple(rmifninfo->sensor,
+			    rmifninfo->function_descriptor.data_base_addr + 1,
+			    instance_data->data_registers->irqs, 1);
+	if (retval) {
+		pr_err("%s: Could not read interrupt status registers "
+			"at 0x%02x; code=%d.", __func__,
+			rmifninfo->function_descriptor.data_base_addr + 1,
+			retval);
+		return;
+	}
+
+	if (instance_data->data_registers->irqs[0] &
+		instance_data->control_registers->interrupt_enable[0]) {
+		/* call down to the sensors irq dispatcher to dispatch
+		 * all enabled IRQs */
+		rmifninfo->sensor->dispatchIRQs(rmifninfo->sensor,
+						instance_data->data_registers->
+						irqs[0]);
+	}
+
+}
+EXPORT_SYMBOL(FN_01_attention);
+
+int FN_01_config(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+	struct f01_instance_data *instance_data = rmifninfo->fndata;
+
+	pr_debug("%s: RMI4 function $01 config\n", __func__);
+
+	/* First thing to do is set the configuration bit.  We'll check this at
+	 * the end to determine if the device has reset during the config
+	 * process.
+	 */
+	retval = rmi_set_bits(rmifninfo->sensor,
+			 rmifninfo->function_descriptor.control_base_addr,
+			 F01_CONFIGURED);
+	if (retval)
+		pr_warning("%s: failed to set configured bit, errno = %d.",
+			   __func__, retval);
+
+	/* At config time, the device is presumably in its default state, so we
+	 * only need to write non-default configuration settings.
+	 */
+	if (instance_data->nonstandard_report_rate) {
+		retval = set_report_rate(rmifninfo, true);
+		if (!retval)
+			pr_warning
+			    ("%s: failed to configure report rate, errno = %d.",
+			     __func__, retval);
+	}
+
+	/* TODO: Check for reset! */
+
+	return retval;
+}
+EXPORT_SYMBOL(FN_01_config);
+
+/* Initialize any function $01 specific params and settings - input
+ * settings, device settings, etc.
+ */
+int FN_01_init(struct rmi_function_device *function_device)
+{
+	int retval;
+	int attr_count = 0;
+	struct rmi_f01_functiondata *functiondata =
+	    rmi_sensor_get_functiondata(function_device->sensor, RMI_F01_INDEX);
+	struct f01_instance_data *instance_data = function_device->rfi->fndata;
+
+	pr_debug("%s: RMI4 function $01 init\n", __func__);
+
+	if (functiondata)
+		instance_data->nonstandard_report_rate =
+		    functiondata->nonstandard_report_rate;
+
+	pr_debug("%s: Creating sysfs files.", __func__);
+	/* Set up sysfs device attributes. */
+	for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+		if (sysfs_create_file
+		    (&function_device->dev.kobj, &attrs[attr_count].attr) < 0) {
+			pr_err
+			    ("%s: Failed to create sysfs file for %s.",
+			     __func__, attrs[attr_count].attr.name);
+			retval = -ENODEV;
+			goto error_exit;
+		}
+	}
+
+	return 0;
+
+error_exit:
+	for (attr_count--; attr_count >= 0; attr_count--)
+		sysfs_remove_file(&function_device->dev.kobj,
+				  &attrs[attr_count].attr);
+	/* If you've allocated anything, free it here. */
+	return retval;
+}
+EXPORT_SYMBOL(FN_01_init);
+
+int FN_01_detect(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+	struct f01_instance_data *instance_data = NULL;
+	struct rmi_F01_control *control_registers = NULL;
+	struct rmi_F01_data *data_registers = NULL;
+	struct rmi_F01_query *query_registers = NULL;
+
+	pr_debug("%s: RMI4 function $01 detect\n", __func__);
+
+	/* Set up context data. */
+	if (rmifninfo->fndata) {
+		/* detect routine should only ever be called once
+		 * per rmifninfo. */
+		pr_err("%s: WTF?!? F01 instance data is already present!",
+		       __func__);
+		return -EINVAL;
+	}
+	instance_data = kzalloc(sizeof(*instance_data), GFP_KERNEL);
+	if (!instance_data) {
+		pr_err("%s: Error allocating memory for F01 context data.\n",
+		       __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	rmifninfo->fndata = instance_data;
+
+	query_registers = kzalloc(sizeof(*query_registers), GFP_KERNEL);
+	if (!query_registers) {
+		pr_err("%s: Error allocating memory for F01 query registers.",
+		       __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	instance_data->query_registers = query_registers;
+	read_query_registers(rmifninfo);
+
+	/* TODO: size of control registers needs to be computed dynamically.
+	 * See comment in rmi.h. */
+	control_registers = kzalloc(sizeof(*control_registers), GFP_KERNEL);
+	if (!control_registers) {
+		pr_err
+		    ("%s: Error allocating memory for F01 control registers.\n",
+		     __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	instance_data->control_registers = control_registers;
+	retval =
+	    rmi_read_multiple(rmifninfo->sensor,
+			      rmifninfo->function_descriptor.control_base_addr,
+			      (char *)instance_data->control_registers,
+			      sizeof(struct rmi_F01_control));
+	if (retval) {
+		pr_err
+		    ("%s: Could not read F01 control registers at 0x%02x. "
+		     "Error %d.\n", __func__,
+		     rmifninfo->function_descriptor.control_base_addr,
+		     retval);
+	}
+
+	/* TODO: size of data registers needs to be computed dynamically.
+	 * See comment in rmi.h. */
+	data_registers = kzalloc(sizeof(*data_registers), GFP_KERNEL);
+	if (!data_registers) {
+		pr_err("%s: Error allocating memory for F01 data registers.\n",
+		       __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	instance_data->data_registers = data_registers;
+
+	/* initialize original_sleepmode */
+	instance_data->original_sleepmode = RMI_SLEEP_MODE_NORMAL;
+	/* initialize of original_nosleep */
+	instance_data->original_nosleep = RMI_NO_SLEEP_DISABLE;
+
+	return retval;
+
+error_exit:
+	kfree(instance_data);
+	kfree(query_registers);
+	kfree(control_registers);
+	kfree(data_registers);
+	rmifninfo->fndata = NULL;
+	return retval;
+}
+EXPORT_SYMBOL(FN_01_detect);
+
+/**
+ *  suspend handler for F01, this will be invoked in
+ *  suspend routine from sensor
+ */
+int FN_01_suspend(struct rmi_function_info *rmifninfo)
+{
+	struct f01_instance_data *instance = rmifninfo->fndata;
+	/*store original sleep mode */
+	instance->original_sleepmode =
+			instance->control_registers->
+			device_control & RMI_F01_SLEEP_MODE_MASK;
+	/*store original no sleep setting */
+	instance->original_nosleep =
+			(instance->control_registers->
+				device_control & RMI_F01_NO_SLEEP_MASK) >> 2;
+	/*sleep:1 normal:0 */
+	set_sensor_sleepmode(rmifninfo, RMI_SLEEP_MODE_SENSOR_SLEEP,
+			RMI_NO_SLEEP_DISABLE);
+	return 0;
+}
+EXPORT_SYMBOL(FN_01_suspend);
+
+/*
+ *  resume handler for F01, this will be invoked in
+ *  resume routine from sensor
+ */
+void FN_01_resume(struct rmi_function_info *rmifninfo)
+{
+	struct f01_instance_data *instance = rmifninfo->fndata;
+	/*sleep:1 normal:0 */
+	set_sensor_sleepmode(rmifninfo, instance->original_sleepmode,
+			instance->original_nosleep);
+}
+EXPORT_SYMBOL(FN_01_resume);
+
+
+static ssize_t rmi_fn_01_productinfo_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+
+	if (instance_data && instance_data->query_registers
+			&& instance_data->query_registers->prod_info)
+		return snprintf(buf, PAGE_SIZE, "0x%02X 0x%02X\n",
+			       instance_data->query_registers->prod_info[0],
+			       instance_data->query_registers->prod_info[1]);
+
+	return snprintf(buf, PAGE_SIZE, "unknown\n");
+}
+
+static ssize_t rmi_fn_01_productid_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+
+	if (instance_data && instance_data->query_registers
+			&& instance_data->query_registers->prod_id)
+		return snprintf(buf, PAGE_SIZE, "%s\n",
+			instance_data->query_registers->prod_id);
+
+	return snprintf(buf, PAGE_SIZE, "unknown\n");
+}
+
+static ssize_t rmi_fn_01_manufacturer_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+
+	if (instance_data && instance_data->query_registers)
+		return snprintf(buf, PAGE_SIZE, "0x%02X\n",
+			instance_data->query_registers->mfgid);
+
+	return snprintf(buf, PAGE_SIZE, "unknown\n");
+}
+
+static ssize_t rmi_fn_01_datecode_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+
+	if (instance_data && instance_data->query_registers
+	    && instance_data->query_registers->date_code)
+		return snprintf(buf, PAGE_SIZE, "20%02u-%02u-%02u\n",
+			       instance_data->query_registers->date_code[0],
+			       instance_data->query_registers->date_code[1],
+			       instance_data->query_registers->date_code[2]);
+
+	return snprintf(buf, PAGE_SIZE, "unknown\n");
+}
+
+static ssize_t rmi_fn_01_reportrate_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+
+	if (instance_data && instance_data->query_registers
+			&& instance_data->query_registers->date_code)
+		return snprintf(buf, PAGE_SIZE, "%d\n",
+			instance_data->nonstandard_report_rate);
+
+	return snprintf(buf, PAGE_SIZE, "unknown\n");
+}
+
+static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+	unsigned int new_rate;
+	int retval;
+
+	if (sscanf(buf, "%u", &new_rate) != 1)
+		return -EINVAL;
+	if (new_rate < 0 || new_rate > 1)
+		return -EINVAL;
+	instance_data->nonstandard_report_rate = new_rate;
+
+	retval = set_report_rate(fn->rfi, new_rate);
+	if (retval < 0) {
+		pr_err("%s: failed to set report rate bit, error = %d.",
+		       __func__, retval);
+		return retval;
+	}
+
+	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_device *fn = dev_get_drvdata(dev);
+	unsigned int reset;
+	int retval;
+
+	if (sscanf(buf, "%u", &reset) != 1)
+		return -EINVAL;
+	if (reset < 0 || reset > 1)
+		return -EINVAL;
+
+	/* Per spec, 0 has no effect, so we skip it entirely. */
+	if (reset) {
+		retval = rmi_set_bits(fn->sensor,
+				fn->rfi->function_descriptor.command_base_addr,
+				F01_RESET);
+		if (retval < 0) {
+			dev_err(dev, "%s: failed to issue reset command, "
+				"error = %d.", __func__, retval);
+			return retval;
+		}
+	}
+
+	return count;
+}
+
+static ssize_t rmi_fn_01_serialnumber_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+
+	if (instance_data && instance_data->query_registers)
+		return snprintf(buf, PAGE_SIZE, "%u\n",
+			       instance_data->query_registers->serial_num);
+
+	return snprintf(buf, PAGE_SIZE, "unknown\n");
+}
+
+static ssize_t rmi_fn_01_testerid_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+
+	if (instance_data && instance_data->query_registers)
+		return snprintf(buf, PAGE_SIZE, "%u\n",
+			       instance_data->query_registers->tester_id);
+
+	return snprintf(buf, PAGE_SIZE, "unknown\n");
+}
+
+/*
+ *  update content of device control into hardware and sync the status
+ *  @param control_base_address base address for F01 device control
+ *  @param mask mask of the field that will be changed
+ *  @param field_target_value target value for the field
+ */
+static int update_device_control(struct rmi_sensor_driver *sensor,
+			struct rmi_F01_control *control_register,
+			unsigned char control_base_address,
+			unsigned char mask,
+			unsigned char field_target_value)
+{
+
+	unsigned char control_target_value =
+			control_register->device_control & (~mask);
+	field_target_value &= mask;
+	control_target_value |= field_target_value;
+	if (control_register->device_control != control_target_value) {
+		/* update device_control*/
+		control_register->device_control = control_target_value;
+		return rmi_set_bit_field(sensor, control_base_address,
+					mask, field_target_value);
+	}
+	return 0;
+}
+
+/*
+ *  shows the status bit provided by device_control
+ *  @param mask mask to retrieve the information ex. 0x3 for bit 0 and bit 1
+ *  @param offset the offset of the information ex. 0: bit 0 1: bit 1
+ */
+static ssize_t device_control_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf,
+				unsigned char mask,
+				unsigned char offset)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+	unsigned char controlRegister = 0;
+
+	if (!instance_data || !instance_data->control_registers)
+		return snprintf(buf, PAGE_SIZE, "unknown\n");
+
+	controlRegister =
+		(instance_data->control_registers->device_control & mask)
+			>> offset;
+	return snprintf(buf, PAGE_SIZE, "%u\n", controlRegister);
+}
+
+/*
+ *  store the value into device_control
+ *  @param mask mask to retrieve the information ex. 0x3 for bit 1 and bit 1
+ *  @param offset the offset of the information ex. 0: bit 0 1: bit 1
+ */
+static ssize_t device_control_store(struct device *dev,
+				struct device_attribute *attr,
+				unsigned int new_value,
+				unsigned char mask,
+				unsigned char offset)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f01_instance_data *instance_data = fn->rfi->fndata;
+	unsigned char target_setting;
+	int retval;
+
+	target_setting = (unsigned char) new_value;
+	if (!instance_data || !instance_data->control_registers)
+		return -EINVAL;
+
+	/*update hardware and device_control status*/
+	retval = update_device_control(fn->sensor,
+			instance_data->control_registers,
+			fn->rfi->function_descriptor.control_base_addr,
+			mask, (target_setting<<offset));
+
+	if (retval < 0)
+		dev_err(dev, "%s: failed to write control register, "
+			"error = %d.", __func__, retval);
+
+	return retval;
+}
+
+/*
+ * show status for sleep 0:normal 1:sleep 2,3: reserved
+ */
+static ssize_t rmi_fn_01_sleepmode_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return device_control_show(dev, attr, buf,
+			RMI_F01_SLEEP_MODE_MASK, RMI_F01_SLEEP_MODE_OFFSET);
+}
+
+/*
+ * setup status for sleep mode 0:normal 1:sleep 2,3: reserved
+ */
+static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf,
+					 size_t count)
+{
+	unsigned long new_value;
+	int retval;
+
+	retval = strict_strtoul(buf, 10, &new_value);
+	if (retval < 0 || !RMI_IS_VALID_SLEEPMODE(new_value)) {
+		dev_err(dev, "%s: Invalid sleep mode %s.", __func__, buf);
+		return -EINVAL;
+	}
+
+	retval = device_control_store(dev, attr, (unsigned int) new_value,
+			RMI_F01_SLEEP_MODE_MASK, RMI_F01_SLEEP_MODE_OFFSET);
+	if (!retval)
+		retval = count;
+	return retval;
+}
+
+/*
+ * show current setting of no sleep, 0:disable 1:enable
+ */
+static ssize_t rmi_fn_01_nosleep_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return device_control_show(dev, attr, buf,
+			RMI_F01_NO_SLEEP_MASK, RMI_F01_NO_SLEEP_OFFSET);
+}
+
+/*
+ * setup no sleep, 0:disable 1:enable
+ */
+static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t count)
+{
+	unsigned long new_value;
+	int retval;
+
+	retval = strict_strtoul(buf, 10, &new_value);
+	if (retval < 0 || new_value < 0 || new_value > 1) {
+		dev_err(dev, "%s: Invalid no sleep setting %s.", __func__, buf);
+		return -EINVAL;
+	}
+
+	retval = (device_control_store(dev, attr, (int) new_value,
+			RMI_F01_NO_SLEEP_MASK, RMI_F01_NO_SLEEP_OFFSET));
+	if (!retval)
+		retval = count;
+	return retval;
+}
+
+/* setup sleep mode via F01. we will store original_mode before sleepmode
+ * and nosleep setting is changed.
+ */
+static void set_sensor_sleepmode(struct rmi_function_info *functionInfo,
+			unsigned char sleepmode,
+			unsigned char nosleep)
+{
+	struct f01_instance_data *instance_data =
+			functionInfo->function_device->rfi->fndata;
+
+	if (instance_data && instance_data->control_registers) {
+		/*update hardware and device_control status*/
+		update_device_control(functionInfo->sensor,
+			instance_data->control_registers,
+			functionInfo->function_descriptor.control_base_addr,
+			(RMI_F01_SLEEP_MODE_MASK | RMI_F01_NO_SLEEP_MASK),
+			(sleepmode | (nosleep << 2))
+		);
+	}
+}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
                   ` (4 preceding siblings ...)
  2011-07-01  5:19 ` [PATCH 5/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 7/9] " Christopher Heiny
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_f05.h b/drivers/input/touchscreen/rmi_f05.h
new file mode 100644
index 0000000..10e4df4
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f05.h
@@ -0,0 +1,42 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $11 header.
+ * Copyright (c) 2007 - 2010, Synaptics Incorporated
+ *
+ * For every RMI4 function that has a data source - like 2D sensors,
+ * buttons, LEDs, GPIOs, etc. - the user will create a new rmi_function_xx.c
+ * file and add these functions to perform the config(), init(), report()
+ * and detect() functionality. The function pointers are then srored under
+ * the RMI function info and these functions will automatically be called by
+ * the global config(), init(), report() and detect() functions that will
+ * loop through all data sources and call the data sources functions using
+ * these functions pointed to by the function ptrs.
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_F05_H)
+#define _RMI_F05_H
+
+void FN_05_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs);
+int FN_05_config(struct rmi_function_info *rmifninfo);
+int FN_05_init(struct rmi_function_device *function_device);
+int FN_05_detect(struct rmi_function_info *rmifninfo);
+/* No attention function for F05 */
+#endif
diff --git a/drivers/input/touchscreen/rmi_f05.c b/drivers/input/touchscreen/rmi_f05.c
new file mode 100644
index 0000000..2446216
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f05.c
@@ -0,0 +1,123 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $11 support for 2D.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f05.h"
+#include "rmi_platformdata.h"
+
+struct f05_instance_data {
+	int dummy;		/* TODO: Write this */
+};
+
+/*
+ * There is no attention function for F05 - it is left NULL
+ * in the function table so it is not called.
+ *
+ */
+
+/*
+ * This reads in a sample and reports the F05 source data to the
+ * input subsystem. It is used for both polling and interrupt driven
+ * operation. This is called a lot so don't put in any informational
+ * printks since they will slow things way down!
+ *
+ * This is a stub for now, and will be fleshed out when the implementation
+ * is completed.
+ */
+void FN_05_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs)
+{
+}
+EXPORT_SYMBOL(FN_05_inthandler);
+
+/* This is a stub for now, and will be fleshed out when the implementation
+ * is completed.
+ */
+int FN_05_config(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+
+	pr_debug("%s: RMI4 F05 config\n", __func__);
+
+	/* TODO: Perform configuration.  In particular, write any cached control
+	 * register values to the device. */
+
+	return retval;
+}
+EXPORT_SYMBOL(FN_05_config);
+
+/* This is a stub for now, and will be fleshed out when the implementation
+ * is completed.
+ */
+int FN_05_init(struct rmi_function_device *function_device)
+{
+	int retval = 0;
+/*
+	struct f05_instance_data *instance_data = function_device->rfi->fndata;
+	struct rmi_f05_functiondata *functiondata =
+	    rmi_sensor_get_functiondata(function_device->sensor, RMI_F05_INDEX);
+*/
+
+	pr_debug("%s: RMI4 F05 init\n", __func__);
+
+	return retval;
+}
+EXPORT_SYMBOL(FN_05_init);
+
+int FN_05_detect(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+	struct f05_instance_data *instance_data;
+
+	pr_debug("%s: RMI4 F05 detect\n", __func__);
+
+	if (rmifninfo->fndata) {
+		/* detect routine should only ever be called once
+		 * per rmifninfo. */
+		pr_err("%s: WTF?!? F05 instance data is already present!",
+		       __func__);
+		return -EINVAL;
+	}
+	instance_data = kzalloc(sizeof(struct f05_instance_data), GFP_KERNEL);
+	if (!instance_data) {
+		pr_err("%s: Error allocating F05 instance data.\n", __func__);
+		return -ENOMEM;
+	}
+	rmifninfo->fndata = instance_data;
+
+	return retval;
+}
+EXPORT_SYMBOL(FN_05_detect);

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
                   ` (5 preceding siblings ...)
  2011-07-01  5:19 ` [PATCH 6/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 8/9] " Christopher Heiny
  2011-07-01  5:19 ` [PATCH 9/9] " Christopher Heiny
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_f11.h b/drivers/input/touchscreen/rmi_f11.h
new file mode 100644
index 0000000..7750ed4
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f11.h
@@ -0,0 +1,80 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $11 header.
+ * Copyright (c) 2007 - 2010, Synaptics Incorporated
+ *
+ * For every RMI4 function that has a data source - like 2D sensors,
+ * buttons, LEDs, GPIOs, etc. - the user will create a new rmi_function_xx.c
+ * file and add these functions to perform the config(), init(), report()
+ * and detect() functionality. The function pointers are then srored under
+ * the RMI function info and these functions will automatically be called by
+ * the global config(), init(), report() and detect() functions that will
+ * loop through all data sources and call the data sources functions using
+ * these functions pointed to by the function ptrs.
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_F11_H)
+#define _RMI_F11_H
+
+/* This is the data read from the F11 query registers.
+ */
+struct rmi_F11_device_query {
+	bool has_query_9;
+	unsigned char number_of_sensors;
+};
+
+struct rmi_F11_sensor_query {
+	bool configurable;
+	bool has_sensitivity_adjust;
+	bool has_gestures;
+	bool has_absolute;
+	bool has_relative;
+	unsigned char number_of_fingers;
+	unsigned char number_of_X_electrodes;
+	unsigned char number_of_Y_electrodes;
+	unsigned char maximum_electrodes;
+	bool has_anchored_finger;
+	unsigned char abs_data_size;
+};
+
+struct rmi_F11_control {
+	bool relative_ballistics;
+	bool relative_position_filter;
+	bool absolute_position_filter;
+	unsigned char reporting_mode;
+	bool manually_tracked_finger;
+	bool manually_tracked_finger_enable;
+	unsigned char motion_sensitivity;
+	unsigned char palm_detect_threshold;
+	unsigned char delta_X_pos_threshold;
+	unsigned char delta_Y_pos_threshold;
+	unsigned char velocity;
+	unsigned char acceleration;
+	unsigned short sensor_max_X_pos;
+	unsigned short sensor_max_Y_pos;
+};
+
+void FN_11_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs);
+int FN_11_config(struct rmi_function_info *rmifninfo);
+int FN_11_init(struct rmi_function_device *function_device);
+int FN_11_detect(struct rmi_function_info *rmifninfo);
+/* No attention function for Fn $11 */
+#endif
diff --git a/drivers/input/touchscreen/rmi_f11.c b/drivers/input/touchscreen/rmi_f11.c
new file mode 100644
index 0000000..0e28cdc
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f11.c
@@ -0,0 +1,962 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $11 support for 2D.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f11.h"
+#include "rmi_platformdata.h"
+
+/* 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
+
+struct f11_instance_data {
+	struct rmi_F11_device_query *device_info;
+	struct rmi_F11_sensor_query *sensor_info;
+	struct rmi_F11_control *control_registers;
+	unsigned char finger_data_buffer_size;
+	unsigned char abs_data_offset;
+	unsigned char abs_data_size;
+	unsigned char rel_data_offset;
+	unsigned char gesture_data_offset;
+	unsigned char *finger_data_buffer;
+	/* Last X & Y seen, needed at finger lift.  Was down indicates
+	 * at least one finger was here. TODO: Eventually we'll need to
+	 * track this info on a per finger basis. */
+	bool wasdown;
+	unsigned int old_X;
+	unsigned int old_Y;
+	/* Transformations to be applied to coordinates before reporting. */
+	bool flip_X;
+	bool flip_Y;
+	int offset_X;
+	int offset_Y;
+	int clip_X_low;
+	int clip_X_high;
+	int clip_Y_low;
+	int clip_Y_high;
+	bool swap_axes;
+	bool rel_report_enabled;
+};
+
+enum f11_finger_state {
+	F11_NO_FINGER = 0,
+	F11_PRESENT = 1,
+	F11_INACCURATE = 2,
+	F11_RESERVED = 3
+};
+
+static ssize_t rmi_fn_11_flip_show(struct device *dev,
+				   struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_flip_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_clip_show(struct device *dev,
+				   struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_clip_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_offset_show(struct device *dev,
+				     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_offset_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_swap_show(struct device *dev,
+				   struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_11_swap_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_relreport_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+
+static ssize_t rmi_fn_11_relreport_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count);
+
+static ssize_t rmi_fn_11_maxPos_show(struct device *dev,
+				     struct device_attribute *attr, char *buf);
+
+static struct device_attribute attrs[] = {
+	__ATTR(flip, 0664,
+	       rmi_fn_11_flip_show, rmi_fn_11_flip_store),	/* RW attr */
+	__ATTR(clip, 0664,
+	       rmi_fn_11_clip_show, rmi_fn_11_clip_store),	/* RW attr */
+	__ATTR(offset, 0664,
+	       rmi_fn_11_offset_show, rmi_fn_11_offset_store),	/* RW attr */
+	__ATTR(swap, 0664,
+	       rmi_fn_11_swap_show, rmi_fn_11_swap_store),	/* RW attr */
+	__ATTR(relreport, 0664,
+	       rmi_fn_11_relreport_show, rmi_fn_11_relreport_store),	/* RW */
+	__ATTR(maxPos, 0444,
+	       rmi_fn_11_maxPos_show, rmi_store_error)	/* R0 attr */
+};
+
+static void FN_11_relreport(struct rmi_function_info *rmifninfo);
+
+
+/* Reading and parsing the F11 query registers is a big hairy wad.  There's a
+ * lot of stuff that is dependent on the presence or absence of other stuff,
+ * and there's really no tidy way to deal with it.
+ *
+ * TODO: Use more computed and #def'ed offset values.
+ */
+static int read_query_registers(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+	struct f11_instance_data *instance_data = rmifninfo->fndata;
+	unsigned char query_buffer[12];	/* TODO: Compute size correctly. */
+	unsigned char abs_data_size;
+	int has_pinch, has_flick, has_tap;
+	int has_tap_and_hold, has_double_tap;
+	int has_early_tap, has_press;
+	int has_palm_detect, has_rotate;
+	int has_relative;
+	unsigned char f11_egr_0, f11_egr_1;
+	unsigned int all_data_block_size;
+
+	/* need to get number of fingers supported, data size, etc. -
+	 * to be used when getting data since the number of registers to
+	 * read depends on the number of fingers supported and data size. */
+	retval = rmi_read_multiple(rmifninfo->sensor,
+			  rmifninfo->function_descriptor.query_base_addr,
+			  query_buffer, sizeof(query_buffer));
+	if (retval) {
+		pr_err("%s:Could not read F11 query registers 0x%04x\n",
+			__func__,
+			rmifninfo->function_descriptor.query_base_addr);
+		return retval;
+	}
+
+	/* Extract device data. */
+	instance_data->device_info->has_query_9 = (query_buffer[0] & 0x04) != 0;
+	instance_data->device_info->number_of_sensors =
+	(query_buffer[0] & 0x07) + 1;
+	pr_debug("%s: F11 device - %d sensors.  Query 9? %d.", __func__,
+		 instance_data->device_info->number_of_sensors,
+		 instance_data->device_info->has_query_9);
+
+	/* Extract sensor data. */
+	/* 2D data sources have only 3 bits for the number of fingers
+	 * supported - so the encoding is a bit wierd. */
+	instance_data->sensor_info->number_of_fingers = DEFAULT_NR_OF_FINGERS;
+	if ((query_buffer[1] & 0x7) <= 4)
+		/* add 1 since zero based */
+		instance_data->sensor_info->number_of_fingers =
+		(query_buffer[1] & 0x7) + 1;
+	else {
+		/* a value of 5 is up to 10 fingers - 6 and 7 are reserved
+		 (shouldn't get these in a normal 2D source). */
+		if ((query_buffer[1] & 0x7) == 5)
+			instance_data->sensor_info->number_of_fingers = 10;
+	}
+	instance_data->sensor_info->configurable =
+			(query_buffer[1] & 0x80) != 0;
+	instance_data->sensor_info->has_sensitivity_adjust =
+			(query_buffer[1] & 0x40) != 0;
+	instance_data->sensor_info->has_gestures =
+			(query_buffer[1] & 0x20) != 0;
+	instance_data->sensor_info->has_absolute =
+			(query_buffer[1] & 0x10) != 0;
+	instance_data->sensor_info->has_relative =
+			(query_buffer[1] & 0x08) != 0;
+	instance_data->sensor_info->abs_data_size = query_buffer[5] & 0x03;
+	pr_debug("%s: Number of fingers: %d.", __func__,
+		 instance_data->sensor_info->number_of_fingers);
+
+	/* Figure out just how much data we'll need to read. */
+	instance_data->finger_data_buffer_size =
+			(instance_data->sensor_info->number_of_fingers + 3) / 4;
+	/* One each for X and Y, one for LSB for X & Y, one for W, one for Z */
+	abs_data_size = 5;
+	if (instance_data->sensor_info->abs_data_size != 0)
+		pr_warning("%s: Unrecognized abs data size %d ignored.",
+			__func__, instance_data->sensor_info->abs_data_size);
+	if (instance_data->sensor_info->has_absolute) {
+		instance_data->abs_data_size = abs_data_size;
+		instance_data->abs_data_offset =
+			instance_data->finger_data_buffer_size;
+		instance_data->finger_data_buffer_size +=
+			instance_data->sensor_info->number_of_fingers *
+			abs_data_size;
+	}
+	if (instance_data->sensor_info->has_relative) {
+		instance_data->rel_data_offset =
+			((instance_data->sensor_info->number_of_fingers + 3)
+				/ 4) +
+			/* absolute data, per finger times number of fingers */
+			(abs_data_size *
+			instance_data->sensor_info->number_of_fingers);
+		instance_data->finger_data_buffer_size +=
+			instance_data->sensor_info->number_of_fingers * 2;
+	}
+	if (instance_data->sensor_info->has_gestures) {
+		instance_data->gesture_data_offset =
+			instance_data->finger_data_buffer_size;
+		pr_warning("%s: WARNING Need to correctly compute gesture "
+			"data location.", __func__);
+	}
+
+	/* need to determine the size of data to read - this depends on
+	 * conditions such as whether Relative data is reported and if Gesture
+	 * data is reported. */
+	f11_egr_0 = query_buffer[7];
+	f11_egr_1 = query_buffer[8];
+
+	/* Get info about what EGR data is supported, whether it has
+	 * Relative data suppo*rted, etc. */
+	has_pinch = f11_egr_0 & 0x40;
+	has_flick = f11_egr_0 & 0x10;
+	has_tap = f11_egr_0 & 0x01;
+	has_tap_and_hold = f11_egr_0 & 0x02;
+	has_double_tap = f11_egr_0 & 0x04;
+	has_early_tap = f11_egr_0 & 0x08;
+	has_press = f11_egr_0 & 0x20;
+	has_palm_detect = f11_egr_1 & 0x01;
+	has_rotate = f11_egr_1 & 0x02;
+	has_relative = query_buffer[1] & 0x08;
+
+	/* Size of all data including finger status, absolute data for each
+	 * finger, relative data and EGR data */
+	all_data_block_size =
+		/* finger status, four fingers per register */
+		((instance_data->sensor_info->number_of_fingers + 3) / 4) +
+		/* absolute data, per finger times number of fingers */
+		(abs_data_size *
+		instance_data->sensor_info->number_of_fingers) +
+		/* two relative registers (if relative is being reported) */
+		2 * has_relative +
+		/* F11_2D_Data8 is only present if the egr_0
+		 * register is non-zero. */
+		!!(f11_egr_0) +
+		/* F11_2D_Data9 is only present if either egr_0 or
+		 * egr_1 registers are non-zero. */
+		(f11_egr_0 || f11_egr_1) +
+		/* F11_2D_Data10 is only present if EGR_PINCH or EGR_FLICK of
+		 * egr_0 reports as 1. */
+		!!(has_pinch | has_flick) +
+		/* F11_2D_Data11 and F11_2D_Data12 are only present if
+		 * EGR_FLICK of egr_0 reports as 1. */
+		2 * !!(has_flick);
+
+	return 0;
+}
+
+/*
+ * This reads in a sample and reports the function $11 source data to the
+ * input subsystem. It is used for both polling and interrupt driven
+ * operation. This is called a lot so don't put in any informational
+ * printks since they will slow things way down!
+ */
+void FN_11_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs)
+{
+	/* number of touch points - fingers down in this case */
+	int finger_down_count;
+	int finger;
+	struct rmi_function_device *function_device;
+	struct f11_instance_data *instance_data = rmifninfo->fndata;
+	int retval;
+
+	finger_down_count = 0;
+	function_device = rmifninfo->function_device;
+
+	/* get 2D sensor finger data */
+	retval =
+	    rmi_read_multiple(rmifninfo->sensor,
+			      rmifninfo->function_descriptor.data_base_addr,
+			      instance_data->finger_data_buffer,
+			      instance_data->finger_data_buffer_size);
+	if (retval) {
+		pr_err("%s: Failed to read finger data registers, code=%d.\n",
+		       __func__, retval);
+		return;
+	}
+
+	/* First we need to count the fingers and generate some events
+	 * related to that. */
+	for (finger = 0; finger < instance_data->sensor_info->number_of_fingers;
+	     finger++) {
+		int reg = finger / 4;	/* Which data byte has finger status */
+		int finger_shift = (finger % 4) * 2;	/* Where in the byte? */
+		int finger_status =
+		    (instance_data->
+		     finger_data_buffer[reg] >> finger_shift) & 0x03;
+
+		if (finger_status == F11_PRESENT
+		    || finger_status == F11_INACCURATE) {
+			finger_down_count++;
+			instance_data->wasdown = true;
+		}
+	}
+	input_report_key(function_device->input, BTN_TOUCH, finger_down_count);
+	for (finger = 0;
+	     finger < (instance_data->sensor_info->number_of_fingers - 1);
+	     finger++)
+		input_report_key(function_device->input, BTN_2 + finger,
+				 finger_down_count >= (finger + 2));
+
+	for (finger = 0; finger < instance_data->sensor_info->number_of_fingers;
+	     finger++) {
+		int reg;
+		int finger_shift;
+		int finger_status;
+		int X = 0, Y = 0, Z = 0, Wy = 0, Wx = 0;
+
+		/* determine which data byte the finger status is in */
+		reg = finger / 4;
+		/* bit shift to get finger's status */
+		finger_shift = (finger % 4) * 2;
+		finger_status =
+		    (instance_data->finger_data_buffer[reg] >> finger_shift)
+		    & 0x03;
+
+		/* if finger status indicates a finger is present then
+		   extract the finger data and report it */
+		if (finger_status == F11_PRESENT
+		    || finger_status == F11_INACCURATE) {
+
+			if (instance_data->sensor_info->has_absolute) {
+				int maxX =
+				    instance_data->control_registers->
+				    sensor_max_X_pos;
+				int maxY =
+				    instance_data->control_registers->
+				    sensor_max_Y_pos;
+				reg =
+				    instance_data->abs_data_offset +
+				    (finger * instance_data->abs_data_size);
+				X = (instance_data->
+				     finger_data_buffer[reg] << 4) & 0x0ff0;
+				X |= (instance_data->
+				      finger_data_buffer[reg + 2] & 0x0f);
+				Y = (instance_data->
+				     finger_data_buffer[reg + 1] << 4) & 0x0ff0;
+				Y |= ((instance_data->
+				       finger_data_buffer[reg +
+							2] & 0xf0) >> 4) & 0x0f;
+				/* First thing to do is swap axes if needed.
+				 */
+				if (instance_data->swap_axes) {
+					int temp = X;
+					X = Y;
+					Y = temp;
+					maxX =
+					    instance_data->control_registers->
+					    sensor_max_Y_pos;
+					maxY =
+					    instance_data->control_registers->
+					    sensor_max_X_pos;
+				}
+				if (instance_data->flip_X)
+					X = max(maxX - X, 0);
+				X = X - instance_data->offset_X;
+				X = min(max(X, instance_data->clip_X_low),
+					instance_data->clip_X_high);
+				if (instance_data->flip_Y)
+					Y = max(maxY - Y, 0);
+				Y = Y - instance_data->offset_Y;
+				Y = min(max(Y, instance_data->clip_Y_low),
+					instance_data->clip_Y_high);
+
+				/* upper 4 bits of W are Wy,
+				   lower 4 of W are Wx */
+				Wy = (instance_data->
+				      finger_data_buffer[reg + 3] >> 4) & 0x0f;
+				Wx = instance_data->finger_data_buffer[reg +
+								     3] & 0x0f;
+				if (instance_data->swap_axes) {
+					int temp = Wx;
+					Wx = Wy;
+					Wy = temp;
+				}
+
+				Z = instance_data->finger_data_buffer[reg + 4];
+
+				/* if this is the first finger report normal
+				 * ABS_X, ABS_Y, PRESSURE, TOOL_WIDTH events for
+				 * non-MT apps. Apps that support Multi-touch
+				 * will ignore these events and use the MT
+				 * events. Apps that don't support Multi-touch
+				 * will still function.
+				 */
+				if (finger_down_count == 1) {
+					instance_data->old_X = X;
+					instance_data->old_Y = Y;
+					input_report_abs(function_device->input,
+							 ABS_X, X);
+					input_report_abs(function_device->input,
+							 ABS_Y, Y);
+					input_report_abs(function_device->input,
+							 ABS_PRESSURE, Z);
+					input_report_abs(function_device->input,
+							 ABS_TOOL_WIDTH,
+							 max(Wx, Wy));
+				} else {
+					/* TODO generate non MT events for
+					 * multifinger situation. */
+				}
+#ifdef CONFIG_SYNA_MULTI_TOUCH
+				/* Report Multi-Touch events for each finger */
+				/* major axis of touch area ellipse */
+				input_report_abs(function_device->input,
+						 ABS_MT_TOUCH_MAJOR, Z);
+				/* minor axis of touch area ellipse */
+				input_report_abs(function_device->input,
+						 ABS_MT_WIDTH_MAJOR, max(Wx,
+									 Wy));
+				/* Currently only 2 supported - 1 or 0 */
+				input_report_abs(function_device->input,
+						 ABS_MT_ORIENTATION,
+						 (Wx > Wy ? 1 : 0));
+				input_report_abs(function_device->input,
+						 ABS_MT_POSITION_X, X);
+				input_report_abs(function_device->input,
+						 ABS_MT_POSITION_Y, Y);
+
+				/* TODO: Tracking ID needs to be reported but
+				 * not used yet. Could be formed by keeping
+				 * an id per position and assiging a new id
+				 * when finger_status changes for that position.
+				 */
+				input_report_abs(function_device->input,
+						 ABS_MT_TRACKING_ID,
+						 finger + 1);
+
+				/* MT sync between fingers */
+				input_mt_sync(function_device->input);
+#endif
+			}
+		}
+	}
+
+	/* if we had a finger down before and now we don't have
+	 * any send a button up. */
+	if ((finger_down_count == 0) && instance_data->wasdown) {
+		instance_data->wasdown = false;
+
+#ifdef CONFIG_SYNA_MULTI_TOUCH
+		input_report_abs(function_device->input, ABS_MT_TOUCH_MAJOR, 0);
+		input_report_abs(function_device->input, ABS_MT_WIDTH_MAJOR, 0);
+		input_report_abs(function_device->input, ABS_MT_POSITION_X,
+				 instance_data->old_X);
+		input_report_abs(function_device->input, ABS_MT_POSITION_Y,
+				 instance_data->old_Y);
+		input_report_abs(function_device->input, ABS_MT_TRACKING_ID, 1);
+		input_mt_sync(function_device->input);
+#endif
+
+		input_report_abs(function_device->input, ABS_X,
+				 instance_data->old_X);
+		input_report_abs(function_device->input, ABS_Y,
+				 instance_data->old_Y);
+		instance_data->old_X = instance_data->old_Y = 0;
+		pr_debug("%s: Finger up.", __func__);
+	}
+
+	FN_11_relreport(rmifninfo);
+	input_sync(function_device->input); /* sync after groups of events */
+
+}
+EXPORT_SYMBOL(FN_11_inthandler);
+
+#define F11_MIN_RELATIVE -128
+#define F11_MAX_RELATIVE 127
+
+/* This function reads in relative data for first finger and
+ * sends it to input system */
+static void FN_11_relreport(struct rmi_function_info *rmifninfo)
+{
+	struct f11_instance_data *instance_data = rmifninfo->fndata;
+	struct rmi_function_device *function_device;
+	signed char X, Y;
+	unsigned short fn11DataBaseAddr;
+
+	if (instance_data->sensor_info->has_relative &&
+			instance_data->rel_report_enabled) {
+		int reg = instance_data->rel_data_offset;
+
+		function_device = rmifninfo->function_device;
+
+		fn11DataBaseAddr =
+		    rmifninfo->function_descriptor.data_base_addr;
+		/* Read and report Rel data for primary finger
+		 * one register for X and one for Y */
+		X = instance_data->finger_data_buffer[reg];
+		Y = instance_data->finger_data_buffer[reg + 1];
+		if (instance_data->swap_axes) {
+			signed char temp = X;
+			X = Y;
+			Y = temp;
+		}
+		if (instance_data->flip_X)
+			X = -X;
+		if (instance_data->flip_Y)
+			Y = -Y;
+		X = (signed char)min(F11_MAX_RELATIVE,
+				     max(F11_MIN_RELATIVE, (int)X));
+		Y = (signed char)min(F11_MAX_RELATIVE,
+				     max(F11_MIN_RELATIVE, (int)Y));
+
+		input_report_rel(function_device->input, REL_X, X);
+		input_report_rel(function_device->input, REL_Y, Y);
+	}
+}
+
+/* This is a stub for now, and will be expanded as this implementation
+ * evolves.
+ */
+int FN_11_config(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+
+	pr_debug("%s: RMI4 function $11 config\n", __func__);
+
+	return retval;
+}
+EXPORT_SYMBOL(FN_11_config);
+
+/* This operation is done in a number of places, so we have a handy routine
+ * for it.
+ */
+static void f11_set_abs_params(struct rmi_function_device *function_device)
+{
+	struct f11_instance_data *instance_data = function_device->rfi->fndata;
+	/* Use the max X and max Y read from the device, or the clip values,
+	 * whichever is stricter.
+	 */
+	int xMin = instance_data->clip_X_low;
+	int xMax =
+	    min((int)instance_data->control_registers->sensor_max_X_pos,
+		instance_data->clip_X_high);
+	int yMin = instance_data->clip_Y_low;
+	int yMax =
+	    min((int)instance_data->control_registers->sensor_max_Y_pos,
+		instance_data->clip_Y_high);
+	if (instance_data->swap_axes) {
+		int temp = xMin;
+		xMin = yMin;
+		yMin = temp;
+		temp = xMax;
+		xMax = yMax;
+		yMax = temp;
+	}
+	pr_debug("%s: Set ranges X=[%d..%d] Y=[%d..%d].", __func__, xMin, xMax,
+		 yMin, yMax);
+	input_set_abs_params(function_device->input, ABS_X, xMin, xMax, 0, 0);
+	input_set_abs_params(function_device->input, ABS_Y, yMin, yMax, 0, 0);
+	input_set_abs_params(function_device->input, ABS_PRESSURE, 0, 255, 0,
+			     0);
+	input_set_abs_params(function_device->input, ABS_TOOL_WIDTH, 0, 15, 0,
+			     0);
+
+#ifdef CONFIG_SYNA_MULTI_TOUCH
+	input_set_abs_params(function_device->input, ABS_MT_TOUCH_MAJOR, 0, 15,
+			     0, 0);
+	input_set_abs_params(function_device->input, ABS_MT_TOUCH_MINOR, 0, 15,
+			     0, 0);
+	input_set_abs_params(function_device->input, ABS_MT_ORIENTATION, 0, 1,
+			     0, 0);
+	input_set_abs_params(function_device->input, ABS_MT_TRACKING_ID, 1, 10,
+			     0, 0);
+	input_set_abs_params(function_device->input, ABS_MT_POSITION_X, xMin,
+			     xMax, 0, 0);
+	input_set_abs_params(function_device->input, ABS_MT_POSITION_Y, yMin,
+			     yMax, 0, 0);
+#endif
+}
+
+/* Initialize any function $11 specific params and settings - input
+ * settings, device settings, etc.
+ */
+int FN_11_init(struct rmi_function_device *function_device)
+{
+	struct f11_instance_data *instance_data = function_device->rfi->fndata;
+	int retval = 0;
+	int attr_count = 0;
+	struct rmi_f11_functiondata *functiondata =
+		rmi_sensor_get_functiondata(function_device->sensor,
+			RMI_F11_INDEX);
+	pr_debug("%s: RMI4 F11 init", __func__);
+
+	/* TODO: Initialize these through some normal kernel mechanism.
+	 */
+	instance_data->flip_X = false;
+	instance_data->flip_Y = false;
+	instance_data->swap_axes = false;
+	instance_data->rel_report_enabled = true;
+	instance_data->offset_X = instance_data->offset_Y = 0;
+	instance_data->clip_X_low = instance_data->clip_Y_low = 0;
+	/* TODO: 65536 should actually be the largest valid RMI4
+	 * position coordinate */
+	instance_data->clip_X_high = instance_data->clip_Y_high = 65536;
+
+	/* Load any overrides that were specified via platform data.
+	 */
+	if (functiondata) {
+		pr_debug("%s: found F11 per function platformdata.", __func__);
+		instance_data->flip_X = functiondata->flip_X;
+		instance_data->flip_Y = functiondata->flip_Y;
+		instance_data->swap_axes = functiondata->swap_axes;
+		if (functiondata->offset) {
+			instance_data->offset_X = functiondata->offset->x;
+			instance_data->offset_Y = functiondata->offset->y;
+		}
+		if (functiondata->clip_X) {
+			if (functiondata->clip_X->min >=
+			    functiondata->clip_X->max) {
+				pr_warning
+				    ("%s: Clip X min (%d) >= X clip max (%d) "
+				     "- ignored.",
+				     __func__, functiondata->clip_X->min,
+				     functiondata->clip_X->max);
+			} else {
+				instance_data->clip_X_low =
+				    functiondata->clip_X->min;
+				instance_data->clip_X_high =
+				    functiondata->clip_X->max;
+			}
+		}
+		if (functiondata->clip_Y) {
+			if (functiondata->clip_Y->min >=
+			    functiondata->clip_Y->max) {
+				pr_warning
+				    ("%s: Clip Y min (%d) >= Y clip max (%d) "
+				     "- ignored.",
+				     __func__, functiondata->clip_Y->min,
+				     functiondata->clip_Y->max);
+			} else {
+				instance_data->clip_Y_low =
+				    functiondata->clip_Y->min;
+				instance_data->clip_Y_high =
+				    functiondata->clip_Y->max;
+			}
+		}
+	}
+
+	/* need to init the input abs params for the 2D */
+	set_bit(EV_ABS, function_device->input->evbit);
+	set_bit(EV_SYN, function_device->input->evbit);
+	set_bit(EV_KEY, function_device->input->evbit);
+
+	f11_set_abs_params(function_device);
+
+	pr_debug("%s: Creating sysfs files.", __func__);
+	/* Set up sysfs device attributes. */
+	for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+		if (sysfs_create_file
+		    (&function_device->dev.kobj, &attrs[attr_count].attr) < 0) {
+			pr_err
+			    ("%s: Failed to create sysfs file for %s.",
+			     __func__, attrs[attr_count].attr.name);
+			retval = -ENODEV;
+			goto error_exit;
+		}
+	}
+
+	return 0;
+
+error_exit:
+	for (attr_count--; attr_count >= 0; attr_count--)
+		sysfs_remove_file(&function_device->dev.kobj,
+				  &attrs[attr_count].attr);
+	/* If you alloc anything, free it here. */
+	return retval;
+}
+EXPORT_SYMBOL(FN_11_init);
+
+int FN_11_detect(struct rmi_function_info *rmifninfo)
+{
+	unsigned char control_buffer[12]; /* TODO: Compute size correctly. */
+	int retval = 0;
+	struct f11_instance_data *instance_data;
+
+	pr_debug("%s: RMI4 F11 detect\n", __func__);
+
+	if (rmifninfo->fndata) {
+		/* detect routine should only ever be called once
+		 * per rmifninfo. */
+		pr_err("%s: WTF?!? F11 instance data is already present!",
+		       __func__);
+		return -EINVAL;
+	}
+	instance_data = kzalloc(sizeof(struct f11_instance_data), GFP_KERNEL);
+	if (!instance_data) {
+		pr_err("%s: Error allocating F11 instance data.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	rmifninfo->fndata = instance_data;
+
+	instance_data->device_info =
+	    kzalloc(sizeof(struct rmi_F11_device_query), GFP_KERNEL);
+	if (!instance_data->device_info) {
+		pr_err("%s: Error allocating F11 device query.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	instance_data->sensor_info =
+	    kzalloc(sizeof(struct rmi_F11_sensor_query), GFP_KERNEL);
+	if (!instance_data->sensor_info) {
+		pr_err("%s: Error allocating F11 sensor query.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	retval = read_query_registers(rmifninfo);
+	if (retval) {
+		pr_err("%s: Failed to read sensor query registers.", __func__);
+		goto error_exit;
+	}
+
+	instance_data->finger_data_buffer =
+	    kcalloc(instance_data->finger_data_buffer_size,
+		    sizeof(unsigned char), GFP_KERNEL);
+	if (!instance_data->finger_data_buffer) {
+		pr_err("%s: Failed to allocate finger data buffer.", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+
+	/* Grab a copy of the control registers. */
+	instance_data->control_registers =
+	    kzalloc(sizeof(struct rmi_F11_control), GFP_KERNEL);
+	if (!instance_data->control_registers) {
+		pr_err("%s: Error allocating F11 control registers.\n",
+		       __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	retval = rmi_read_multiple(rmifninfo->sensor,
+			      rmifninfo->function_descriptor.control_base_addr,
+			      control_buffer, sizeof(control_buffer));
+	if (retval) {
+		pr_err("%s: Failed to read F11 control registers.", __func__);
+		goto error_exit;
+	}
+	instance_data->control_registers->sensor_max_X_pos =
+	    (((int)control_buffer[7] & 0x0F) << 8) + control_buffer[6];
+	instance_data->control_registers->sensor_max_Y_pos =
+	    (((int)control_buffer[9] & 0x0F) << 8) + control_buffer[8];
+	pr_debug("%s: Max X %d Max Y %d", __func__,
+		 instance_data->control_registers->sensor_max_X_pos,
+		 instance_data->control_registers->sensor_max_Y_pos);
+	return 0;
+
+error_exit:
+	if (instance_data) {
+		kfree(instance_data->sensor_info);
+		kfree(instance_data->device_info);
+		kfree(instance_data->control_registers);
+		kfree(instance_data->finger_data_buffer);
+	}
+	kfree(instance_data);
+	rmifninfo->fndata = NULL;
+	return retval;
+}
+EXPORT_SYMBOL(FN_11_detect);
+
+static ssize_t rmi_fn_11_maxPos_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u %u\n",
+		instance_data->control_registers->sensor_max_X_pos,
+		instance_data->control_registers->sensor_max_Y_pos);
+}
+
+static ssize_t rmi_fn_11_flip_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u %u\n", instance_data->flip_X,
+			instance_data->flip_Y);
+}
+
+static ssize_t rmi_fn_11_flip_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+	unsigned int new_X, new_Y;
+
+	if (sscanf(buf, "%u %u", &new_X, &new_Y) != 2)
+		return -EINVAL;
+	if (new_X < 0 || new_X > 1 || new_Y < 0 || new_Y > 1)
+		return -EINVAL;
+	instance_data->flip_X = new_X;
+	instance_data->flip_Y = new_Y;
+
+	return count;
+}
+
+static ssize_t rmi_fn_11_swap_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->swap_axes);
+}
+
+static ssize_t rmi_fn_11_swap_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+	unsigned int newSwap;
+
+	if (sscanf(buf, "%u", &newSwap) != 1)
+		return -EINVAL;
+	if (newSwap < 0 || newSwap > 1)
+		return -EINVAL;
+	instance_data->swap_axes = newSwap;
+
+	f11_set_abs_params(fn);
+
+	return count;
+}
+
+static ssize_t rmi_fn_11_relreport_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE,
+			"%u\n", instance_data->rel_report_enabled);
+}
+
+static ssize_t rmi_fn_11_relreport_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf,
+					 size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+	unsigned int new_value;
+
+	if (sscanf(buf, "%u", &new_value) != 1)
+		return -EINVAL;
+	if (new_value < 0 || new_value > 1)
+		return -EINVAL;
+	instance_data->rel_report_enabled = new_value;
+
+	return count;
+}
+
+static ssize_t rmi_fn_11_offset_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%d %d\n", instance_data->offset_X,
+		instance_data->offset_Y);
+}
+
+static ssize_t rmi_fn_11_offset_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+	int new_X, new_Y;
+
+	if (sscanf(buf, "%d %d", &new_X, &new_Y) != 2)
+		return -EINVAL;
+	instance_data->offset_X = new_X;
+	instance_data->offset_Y = new_Y;
+
+	return count;
+}
+
+static ssize_t rmi_fn_11_clip_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u %u %u %u\n",
+		       instance_data->clip_X_low, instance_data->clip_X_high,
+		       instance_data->clip_Y_low, instance_data->clip_Y_high);
+}
+
+static ssize_t rmi_fn_11_clip_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f11_instance_data *instance_data = fn->rfi->fndata;
+	unsigned int new_X_low, new_X_high, new_Y_low, new_Y_high;
+
+	if (sscanf(buf, "%u %u %u %u",
+			&new_X_low, &new_X_high, &new_Y_low, &new_Y_high) != 4)
+		return -EINVAL;
+	if (new_X_low < 0 || new_X_low >= new_X_high || new_Y_low < 0
+			|| new_Y_low >= new_Y_high)
+		return -EINVAL;
+	instance_data->clip_X_low = new_X_low;
+	instance_data->clip_X_high = new_X_high;
+	instance_data->clip_Y_low = new_Y_low;
+	instance_data->clip_Y_high = new_Y_high;
+
+	f11_set_abs_params(fn);
+
+	return count;
+}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
                   ` (6 preceding siblings ...)
  2011-07-01  5:19 ` [PATCH 7/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  2011-07-01  5:19 ` [PATCH 9/9] " Christopher Heiny
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_f19.h b/drivers/input/touchscreen/rmi_f19.h
new file mode 100644
index 0000000..b5964fe
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f19.h
@@ -0,0 +1,63 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $11 header.
+ * Copyright (c) 2007 - 2010, Synaptics Incorporated
+ *
+ * For every RMI4 function that has a data source - like 2D sensors,
+ * buttons, LEDs, GPIOs, etc. - the user will create a new rmi_function_xx.c
+ * file and add these functions to perform the config(), init(), report()
+ * and detect() functionality. The function pointers are then srored under
+ * the RMI function info and these functions will automatically be called by
+ * the global config(), init(), report() and detect() functions that will
+ * loop through all data sources and call the data sources functions using
+ * these functions pointed to by the function ptrs.
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_F19_H)
+#define _RMI_F19_H
+
+/* This is the data read from the F19 query registers.
+ */
+struct rmi_F19_query {
+	bool has_hysteresis_threshold;
+	bool has_sensitivity_adjust;
+	bool configurable;
+	unsigned char button_count;
+};
+
+struct rmi_F19_control {
+	unsigned char button_usage;
+	unsigned char filter_mode;
+	unsigned char *interrupt_enable_registers;
+	unsigned char *single_button_control;
+	unsigned char *sensor_map;
+	unsigned char *single_button_sensitivity;
+	unsigned char global_sensitivity_adjustment;
+	unsigned char global_hysteresis_threshold;
+};
+
+
+void FN_19_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs);
+int FN_19_config(struct rmi_function_info *rmifninfo);
+int FN_19_init(struct rmi_function_device *function_device);
+int FN_19_detect(struct rmi_function_info *rmifninfo);
+/* No attention function for Fn $19 */
+#endif
diff --git a/drivers/input/touchscreen/rmi_f19.c b/drivers/input/touchscreen/rmi_f19.c
new file mode 100644
index 0000000..c8646aa
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f19.c
@@ -0,0 +1,629 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $11 support for 2D.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f19.h"
+#include "rmi_platformdata.h"
+
+struct f19_instance_data {
+	struct rmi_F19_query *device_info;
+	struct rmi_F19_control *control_registers;
+	bool *button_down;
+	unsigned char button_data_buffer_size;
+	unsigned char *button_data_buffer;
+	unsigned char *button_map;
+	int control_register_size;
+	int register_count_for_bit_per_button;
+	int usage_and_filter_mode_offset;
+	int interrupt_enable_offset;
+	int interrupt_enable_length;
+	int single_button_control_length;
+	int single_button_control_offset;
+	int sensor_map_control_offset;
+	int sensor_map_control_length;
+	int single_button_sensor_offset;
+	int single_button_sensor_length;
+	int global_sensor_offset;
+	int global_hysteresis_threshold_offset;
+};
+
+static ssize_t rmi_f19_button_count_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf);
+
+static ssize_t rmi_f19_buttonMap_show(struct device *dev,
+				      struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_f19_buttonMap_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count);
+
+static struct device_attribute attrs[] = {
+	__ATTR(button_count, 0444,
+	       rmi_f19_button_count_show, rmi_store_error),	/* RO attr */
+	__ATTR(buttonMap, 0664,
+	       rmi_f19_buttonMap_show, rmi_f19_buttonMap_store)	/* RW attr */
+};
+
+/*
+ * There is no attention function for F19 - it is left NULL
+ * in the function table so it is not called.
+ *
+ */
+
+/*
+ * This reads in a sample and reports the F19 source data to the
+ * input subsystem. It is used for both polling and interrupt driven
+ * operation. This is called a lot so don't put in any informational
+ * printks since they will slow things way down!
+ */
+void FN_19_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs)
+{
+	struct f19_instance_data *instance_data = rmifninfo->fndata;
+	struct rmi_function_device *function_device =
+	    rmifninfo->function_device;
+	int button;
+
+	/* Read the button data. */
+
+	if (rmi_read_multiple(rmifninfo->sensor,
+			rmifninfo->function_descriptor.data_base_addr,
+			instance_data->button_data_buffer,
+			instance_data->button_data_buffer_size)) {
+		pr_err("%s: Failed to read button data registers.\n", __func__);
+		return;
+	}
+
+	/* Generate events for buttons that change state. */
+	for (button = 0; button < instance_data->device_info->button_count;
+	     button++) {
+		int button_reg;
+		int button_shift;
+		bool button_status;
+
+		/* determine which data byte the button status is in */
+		button_reg = button / 4;
+		/* bit shift to get button's status */
+		button_shift = button % 8;
+		button_status =
+		    ((instance_data->
+		      button_data_buffer[button_reg] >> button_shift) & 0x01) !=
+		    0;
+
+		/* if the button state changed from the last time report it
+		 * and store the new state */
+		if (button_status != instance_data->button_down[button]) {
+			pr_debug("%s: Button %d (code %d) -> %d.", __func__,
+				 button, instance_data->button_map[button],
+				 button_status);
+			/* Generate an event here. */
+			input_report_key(function_device->input,
+					 instance_data->button_map[button],
+					 button_status);
+			instance_data->button_down[button] = button_status;
+		}
+	}
+
+	input_sync(function_device->input); /* sync after groups of events */
+}
+EXPORT_SYMBOL(FN_19_inthandler);
+
+/* This is a stub for now.  It will be filled in as the driver implementation
+ * evolves.
+ */
+int FN_19_config(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+
+	pr_debug("%s: RMI4 F19 config\n", __func__);
+
+	/* TODO: Perform configuration.  In particular, write any cached control
+	 * register values to the device. */
+
+	return retval;
+}
+EXPORT_SYMBOL(FN_19_config);
+
+/* Initialize any F19 specific params and settings - input
+ * settings, device settings, etc.
+ */
+int FN_19_init(struct rmi_function_device *function_device)
+{
+	int i, retval = 0;
+	int attr_count = 0;
+	struct f19_instance_data *instance_data = function_device->rfi->fndata;
+	struct rmi_f19_functiondata *functiondata =
+	    rmi_sensor_get_functiondata(function_device->sensor, RMI_F19_INDEX);
+
+	pr_debug("%s: RMI4 F19 init\n", __func__);
+
+	if (functiondata && functiondata->button_map) {
+		if (functiondata->button_map->nbuttons !=
+		    instance_data->device_info->button_count) {
+			pr_warning
+			    ("%s: Platformdata button map size (%d) != number "
+			     "of buttons on device (%d) - ignored.",
+			     __func__, functiondata->button_map->nbuttons,
+			     instance_data->device_info->button_count);
+		} else if (!functiondata->button_map->map) {
+			pr_warning("%s: Platformdata button map is missing!",
+				   __func__);
+		} else {
+			for (i = 0; i < functiondata->button_map->nbuttons; i++)
+				instance_data->button_map[i] =
+				    functiondata->button_map->map[i];
+		}
+	}
+
+	/* Set up any input events. */
+	set_bit(EV_SYN, function_device->input->evbit);
+	set_bit(EV_KEY, function_device->input->evbit);
+	/* set bits for each button... */
+	for (i = 0; i < instance_data->device_info->button_count; i++)
+		set_bit(instance_data->button_map[i],
+			function_device->input->keybit);
+
+	pr_debug("%s: Creating sysfs files.", __func__);
+	/* Set up sysfs device attributes. */
+	for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+		if (sysfs_create_file
+		    (&function_device->dev.kobj, &attrs[attr_count].attr) < 0) {
+			pr_err
+			    ("%s: Failed to create sysfs file for %s.",
+			     __func__, attrs[attr_count].attr.name);
+			retval = -ENODEV;
+			goto error_exit;
+		}
+	}
+
+	return 0;
+
+error_exit:
+	for (attr_count--; attr_count >= 0; attr_count--)
+		sysfs_remove_file(&function_device->dev.kobj,
+				  &attrs[attr_count].attr);
+	/* If you alloc anything, free it here. */
+	return retval;
+}
+EXPORT_SYMBOL(FN_19_init);
+
+static int init_control_registers(struct rmi_function_info *rmifninfo)
+{
+	struct f19_instance_data *instance_data = rmifninfo->fndata;
+	unsigned char *control_registers = NULL;
+	int retval = 0;
+
+	if (instance_data->control_registers) {
+		pr_err
+		    ("%s: WTF? F19 control regsiters are already initialized.",
+		     __func__);
+		return -EINVAL;
+	}
+
+	/* Allocate memory for the control registers. */
+	instance_data->control_registers =
+	    kzalloc(sizeof(struct rmi_F19_control), GFP_KERNEL);
+	if (!instance_data->control_registers) {
+		pr_err("%s: Error allocating F19 control registers.\n",
+		       __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+
+	instance_data->register_count_for_bit_per_button =
+	    (instance_data->device_info->button_count + 7) / 8;
+
+	/* Need to compute the amount of data to read since it varies with the
+	 * number of buttons */
+		/* 1 for filter mode and button usage bits */
+	instance_data->control_register_size = 1
+		/* interrupt enable bits and single button participation bits */
+	    + 2 * instance_data->register_count_for_bit_per_button
+		/* sensormap registers + single button sensitivity registers */
+	    + 2 * instance_data->device_info->button_count
+		/* 1 for global sensitivity adjust and
+		 * 1 for global hysteresis threshold */
+	    + 2;
+
+	/* Allocate a temp memory buffer to read the control registers into */
+	control_registers =
+	    kzalloc(instance_data->control_register_size, GFP_KERNEL);
+	if (!control_registers) {
+		pr_err
+		    ("%s: Error allocating temp storage to read "
+		     "fn19 control info.\n",
+		     __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+
+	/* Grab a copy of the control registers. */
+	retval = rmi_read_multiple(rmifninfo->sensor,
+			      rmifninfo->function_descriptor.control_base_addr,
+			      control_registers,
+			      instance_data->control_register_size);
+	if (retval) {
+		pr_err("%s: Failed to read F19 control registers.", __func__);
+		goto error_exit;
+	}
+
+	/* Copy over control registers data to the instance data */
+	instance_data->usage_and_filter_mode_offset = 0;
+	instance_data->control_registers->button_usage =
+	    control_registers[instance_data->
+			      usage_and_filter_mode_offset] & 0x3;
+	instance_data->control_registers->filter_mode =
+	    control_registers[instance_data->
+			      usage_and_filter_mode_offset] & 0xc;
+
+	/* Fill in interrupt enable registers */
+	instance_data->interrupt_enable_offset = 1;
+	instance_data->interrupt_enable_length =
+	    instance_data->register_count_for_bit_per_button;
+	instance_data->control_registers->interrupt_enable_registers =
+	    kzalloc(instance_data->interrupt_enable_length, GFP_KERNEL);
+	if (!instance_data->control_registers->interrupt_enable_registers) {
+		pr_err("%s: Error allocating storage for interrupt "
+		     "enable control info.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	memcpy(instance_data->control_registers->interrupt_enable_registers,
+	       &control_registers[instance_data->interrupt_enable_offset],
+	       instance_data->interrupt_enable_length);
+
+	/* Fill in single button control registers */
+	instance_data->single_button_control_offset =
+	    instance_data->interrupt_enable_offset +
+	    instance_data->interrupt_enable_length;
+	instance_data->single_button_control_length =
+	    instance_data->register_count_for_bit_per_button;
+	instance_data->control_registers->single_button_control =
+	    kzalloc(instance_data->single_button_control_length, GFP_KERNEL);
+	if (!instance_data->control_registers->single_button_control) {
+		pr_err("%s: Error allocating storage for single button "
+		     "participation control info.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	memcpy(instance_data->control_registers->single_button_control,
+	       &control_registers[instance_data->single_button_control_offset],
+	       instance_data->single_button_control_length);
+
+	/* Fill in sensor map registers */
+	instance_data->sensor_map_control_offset =
+	    instance_data->single_button_control_offset +
+	    instance_data->single_button_control_length;
+	instance_data->sensor_map_control_length =
+	    instance_data->device_info->button_count;
+	instance_data->control_registers->sensor_map =
+	    kzalloc(instance_data->sensor_map_control_length, GFP_KERNEL);
+	if (!instance_data->control_registers->sensor_map) {
+		pr_err("%s: Error allocating storage for sensor map "
+		     "control info.", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	memcpy(instance_data->control_registers->sensor_map,
+	       &control_registers[instance_data->sensor_map_control_offset],
+	       instance_data->sensor_map_control_length);
+
+	/* Fill in single button sensitivity registers */
+	instance_data->single_button_sensor_offset =
+	    instance_data->sensor_map_control_offset +
+	    instance_data->sensor_map_control_length;
+	instance_data->single_button_sensor_length =
+	    instance_data->device_info->button_count;
+	instance_data->control_registers->single_button_sensitivity =
+	    kzalloc(instance_data->single_button_sensor_length, GFP_KERNEL);
+	if (!instance_data->control_registers->single_button_sensitivity) {
+		pr_err
+		    ("%s: Error allocating storage for single button "
+		     "sensitivity control info.",
+		     __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	memcpy(instance_data->control_registers->single_button_sensitivity,
+	       &control_registers[instance_data->single_button_sensor_offset],
+	       instance_data->single_button_sensor_length);
+
+	/* Fill in global sensitivity adjustment and global
+	 * hysteresis threshold values */
+	instance_data->global_sensor_offset =
+	    instance_data->single_button_sensor_offset +
+	    instance_data->single_button_sensor_length;
+	instance_data->global_hysteresis_threshold_offset =
+	    instance_data->global_sensor_offset + 1;
+	instance_data->control_registers->global_sensitivity_adjustment =
+	    control_registers[instance_data->global_sensor_offset] & 0x1f;
+	instance_data->control_registers->global_hysteresis_threshold =
+	    control_registers[instance_data->
+			      global_hysteresis_threshold_offset] & 0x0f;
+
+	/* Free up temp storage that held copy of control registers */
+	kfree(control_registers);
+
+	return 0;
+
+error_exit:
+	if (instance_data->control_registers) {
+		kfree(
+		  instance_data->control_registers->single_button_sensitivity);
+		kfree(
+		  instance_data->control_registers->interrupt_enable_registers);
+		kfree(instance_data->control_registers->sensor_map);
+		kfree(instance_data->control_registers->single_button_control);
+	}
+	kfree(instance_data->control_registers);
+	kfree(control_registers);
+	return retval;
+}
+
+int FN_19_detect(struct rmi_function_info *rmifninfo)
+{
+	unsigned char query_buffer[2];
+	int retval = 0;
+	int i;
+	struct f19_instance_data *instance_data;
+
+	pr_debug("%s: RMI4 F19 detect\n", __func__);
+
+	if (rmifninfo->fndata) {
+		/* detect routine should only ever be called once
+		 * per rmifninfo. */
+		pr_err("%s: WTF?!? F19 instance data is already present!",
+		       __func__);
+		return -EINVAL;
+	}
+	instance_data = kzalloc(sizeof(struct f19_instance_data), GFP_KERNEL);
+	if (!instance_data) {
+		pr_err("%s: Error allocating F19 instance data.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	instance_data->device_info =
+	    kzalloc(sizeof(struct rmi_F19_query), GFP_KERNEL);
+	if (!instance_data->device_info) {
+		pr_err("%s: Error allocating F19 device query.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	rmifninfo->fndata = instance_data;
+
+	/* need to get number of fingers supported, data size, etc. -
+	   to be used when getting data since the number of registers to
+	   read depends on the number of fingers supported and data size. */
+	retval =
+	    rmi_read_multiple(rmifninfo->sensor,
+			      rmifninfo->function_descriptor.query_base_addr,
+			      query_buffer, sizeof(query_buffer));
+	if (retval) {
+		pr_err("%s: RMI4 F19 detect: "
+		       "Could not read function query registers 0x%x\n",
+		       __func__,
+		       rmifninfo->function_descriptor.query_base_addr);
+		goto error_exit;
+	}
+
+	/* Extract device data. */
+	instance_data->device_info->configurable = query_buffer[0] & 0x01;
+	instance_data->device_info->has_sensitivity_adjust =
+	    query_buffer[0] & 0x02;
+	instance_data->device_info->has_hysteresis_threshold =
+	    query_buffer[0] & 0x04;
+	instance_data->device_info->button_count = query_buffer[1] & 0x01F;
+	pr_debug("%s: F19 device - %d buttons...", __func__,
+		 instance_data->device_info->button_count);
+
+	/* Figure out just how much data we'll need to read. */
+	instance_data->button_down =
+	    kcalloc(instance_data->device_info->button_count, sizeof(bool),
+		    GFP_KERNEL);
+	if (!instance_data->button_down) {
+		pr_err("%s: Error allocating F19 button state buffer.\n",
+		       __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+
+	instance_data->button_data_buffer_size =
+	    (instance_data->device_info->button_count + 7) / 8;
+	instance_data->button_data_buffer =
+	    kcalloc(instance_data->button_data_buffer_size,
+		    sizeof(unsigned char), GFP_KERNEL);
+	if (!instance_data->button_data_buffer) {
+		pr_err("%s: Failed to allocate button data buffer.", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+
+	instance_data->button_map =
+	    kcalloc(instance_data->device_info->button_count,
+		    sizeof(unsigned char), GFP_KERNEL);
+	if (!instance_data->button_map) {
+		pr_err("%s: Error allocating F19 button map.\n", __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+
+	for (i = 0; i < instance_data->device_info->button_count; i++)
+		instance_data->button_map[i] = BTN_0 + i; /* default values */
+
+	/* Grab the control register info. */
+	retval = init_control_registers(rmifninfo);
+	if (retval) {
+		pr_err("%s: Error %d getting fn19 control register info.\n",
+		       __func__, retval);
+		goto error_exit;
+	}
+
+	return 0;
+
+error_exit:
+	if (instance_data) {
+		kfree(instance_data->button_map);
+		kfree(instance_data->button_data_buffer);
+		kfree(instance_data->button_down);
+		kfree(instance_data->device_info);
+	}
+	kfree(instance_data);
+	return retval;
+}
+EXPORT_SYMBOL(FN_19_detect);
+
+static ssize_t rmi_f19_button_count_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f19_instance_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			instance_data->device_info->button_count);
+}
+
+static ssize_t rmi_f19_buttonMap_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f19_instance_data *instance_data = fn->rfi->fndata;
+	int i, len, total_len = 0;
+	char *current_buf = buf;
+
+	/* loop through each button map value and copy its
+	 * string representation into buf */
+	for (i = 0; i < instance_data->device_info->button_count; i++) {
+		/* get next button mapping value and write it to buf */
+		len = snprintf(current_buf, PAGE_SIZE - total_len,
+			"%u ", instance_data->button_map[i]);
+		/* bump up ptr to next location in buf if the
+		 * snprintf was valid.  Otherwise issue an error
+		 * and return. */
+		if (len > 0) {
+			current_buf += len;
+			total_len += len;
+		} else {
+			dev_err(dev, "%s: Failed to build button map buffer, "
+				"code = %d.\n", __func__, len);
+			return snprintf(buf, PAGE_SIZE, "unknown\n");
+		}
+	}
+	snprintf(current_buf, PAGE_SIZE - total_len, "\n");
+
+	return total_len;
+}
+
+static ssize_t rmi_f19_buttonMap_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct f19_instance_data *instance_data = fn->rfi->fndata;
+	unsigned int button;
+	int i;
+	int retval = count;
+	int button_count = 0;
+	unsigned char *temp_button_map;
+
+	/* Do validation on the button map data passed in.  Store button
+	 * mappings into a temp buffer and then verify button count and
+	 * data prior to clearing out old button mappings and storing the
+	 * new ones. */
+	temp_button_map =
+	    kzalloc(instance_data->device_info->button_count, GFP_KERNEL);
+	if (!temp_button_map) {
+		dev_err(dev, "%s: Error allocating temp button map.\n",
+			__func__);
+		retval = -ENOMEM;
+		goto err_ret;
+	}
+
+	for (i = 0; i < instance_data->device_info->button_count && *buf != 0;
+	     i++) {
+		/* get next button mapping value and store and bump up to
+		 * point to next item in buf */
+		sscanf(buf, "%u", &button);
+
+		/* Make sure the key is a valid key */
+		if (button > KEY_MAX) {
+			dev_err(dev,
+				"%s: Error - button map for button %d is not a "
+				"valid value 0x%x.\n",
+				__func__, i, button);
+			retval = -EINVAL;
+			goto err_ret;
+		}
+
+		temp_button_map[i] = button;
+		button_count++;
+
+		/* bump up buf to point to next item to read */
+		while (*buf != 0) {
+			buf++;
+			if (*(buf - 1) == ' ')
+				break;
+		}
+	}
+
+	/* Make sure the button count matches */
+	if (button_count != instance_data->device_info->button_count) {
+		dev_err(dev,
+		    "%s: Error - button map count of %d doesn't match device "
+		     "button count of %d.\n", __func__, button_count,
+		     instance_data->device_info->button_count);
+		retval = -EINVAL;
+		goto err_ret;
+	}
+
+	/* Switch to the new map. */
+	kfree(instance_data->button_map);
+	instance_data->button_map = temp_button_map;
+	temp_button_map = NULL;
+
+	/* Loop through the temp buffer and copy the button event and
+	 * set the key bit for the new mapping. */
+	for (i = 0; i < button_count; i++)
+		set_bit(instance_data->button_map[i], fn->input->keybit);
+
+err_ret:
+	kfree(temp_button_map);
+
+	return retval;
+}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 9/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver
  2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
                   ` (7 preceding siblings ...)
  2011-07-01  5:19 ` [PATCH 8/9] " Christopher Heiny
@ 2011-07-01  5:19 ` Christopher Heiny
  8 siblings, 0 replies; 10+ messages in thread
From: Christopher Heiny @ 2011-07-01  5:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jean Delvare, Linux Kernel, Linux Input, Christopher Heiny,
	Allie Xiong, William Manson, Peichen Chang, Joerie de Gram,
	Wolfram Sang, Mathieu Poirier, Linus Walleij,
	Naveen Kumar Gaddipati

Driver for Synaptics touchscreens using RMI4 protocol.

Please see the email 0/9 for a description of this patch.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Signed-off-by: William Manson <wmanson@synaptics.com>
Signed-off-by: Allie Xiong <axiong@synaptics.com>
Signed-off-by: Peichen Chang <peichen.chang@synaptics.com>

Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>

Acked-by: Jean Delvare <khali@linux-fr.org>

---

diff --git a/drivers/input/touchscreen/rmi_f34.h b/drivers/input/touchscreen/rmi_f34.h
new file mode 100644
index 0000000..c9e8b52
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f34.h
@@ -0,0 +1,48 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $34 header.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ * There is only one function $34 for each RMI4 sensor. This will be
+ * the function that is used to reflash the firmware and get the
+ * boot loader address and the boot image block size.
+ *
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#if !defined(_RMI_F34_H)
+#define _RMI_F34_H
+
+/* define fn $34 commands */
+#define WRITE_FW_BLOCK            2
+#define ERASE_ALL                 3
+#define READ_CONFIG_BLOCK         5
+#define WRITE_CONFIG_BLOCK        6
+#define ERASE_CONFIG              7
+#define ENABLE_FLASH_PROG         15
+
+void FN_34_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs);
+int FN_34_config(struct rmi_function_info *rmifninfo);
+int FN_34_init(struct rmi_function_device *function_device);
+int FN_34_detect(struct rmi_function_info *rmifninfo);
+void FN_34_attention(struct rmi_function_info *rmifninfo);
+
+#endif
diff --git a/drivers/input/touchscreen/rmi_f34.c b/drivers/input/touchscreen/rmi_f34.c
new file mode 100644
index 0000000..b41d591
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_f34.c
@@ -0,0 +1,556 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $34 support for sensor
+ * firmware reflashing.
+ *
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/input.h>
+#include <linux/sysfs.h>
+#include <linux/math64.h>
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f34.h"
+
+/* data specific to fn $34 that needs to be kept around */
+struct rmi_fn_34_data {
+	unsigned char status;
+	unsigned char cmd;
+	unsigned short bootloaderid;
+	unsigned short blocksize;
+	unsigned short imageblockcount;
+	unsigned short configblockcount;
+};
+
+static ssize_t rmi_fn_34_status_show(struct device *dev,
+				     struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_34_cmd_show(struct device *dev,
+				  struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_34_cmd_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count);
+
+static ssize_t rmi_fn_34_data_read(struct file *data_file, struct kobject *kobj,
+				   struct bin_attribute *attributes,
+				   char *buf, loff_t pos, size_t count);
+
+static ssize_t rmi_fn_34_data_write(struct file *data_file,
+				    struct kobject *kobj,
+				    struct bin_attribute *attributes, char *buf,
+				    loff_t pos, size_t count);
+
+static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf);
+
+static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf, size_t count);
+
+static ssize_t rmi_fn_34_blocksize_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+
+static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf);
+
+static ssize_t rmi_fn_34_configblockcount_show(struct device *dev,
+					       struct device_attribute *attr,
+					       char *buf);
+
+static struct device_attribute attrs[] = {
+	__ATTR(status, 0444,
+	       rmi_fn_34_status_show, rmi_store_error),	/* RO attr */
+	/* Also, sysfs will need to have a file set up to distinguish
+	 * between commands - like Config write/read, Image write/verify. */
+	__ATTR(cmd, 0666,
+	       rmi_fn_34_cmd_show, rmi_fn_34_cmd_store),	/* RW attr */
+	__ATTR(bootloaderid, 0666,
+	       rmi_fn_34_bootloaderid_show, rmi_fn_34_bootloaderid_store),
+	       /* RW attr */
+	__ATTR(blocksize, 0444,
+	       rmi_fn_34_blocksize_show, rmi_store_error),	/* RO attr */
+	__ATTR(imageblockcount, 0444,
+	       rmi_fn_34_imageblockcount_show, rmi_store_error), /* RO attr */
+	__ATTR(configblockcount, 0444,
+	       rmi_fn_34_configblockcount_show, rmi_store_error) /* RO attr */
+};
+
+struct bin_attribute dev_attr_data = {
+	.attr = {
+		 .name = "data",
+		 .mode = 0666},
+	.size = 0,
+	.read = rmi_fn_34_data_read,
+	.write = rmi_fn_34_data_write,
+};
+
+/* 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.
+ */
+static void batohs(unsigned short *dest, unsigned char *src)
+{
+	*src = dest[1] * 0x100 + dest[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.
+ */
+static void hstoba(unsigned char *dest, unsigned short src)
+{
+	dest[0] = src % 0x100;
+	dest[1] = src / 0x100;
+}
+
+/*.
+ * The interrupt handler for Fn $34.
+ */
+void FN_34_inthandler(struct rmi_function_info *rmifninfo,
+		      unsigned int asserted_IRQs)
+{
+	unsigned int status;
+	struct rmi_fn_34_data *instance_data = rmifninfo->fndata;
+
+	/* Read the Fn $34 status register to see whether the previous
+	 * command executed OK. inform user space - through a sysfs param. */
+	if (rmi_read_multiple(rmifninfo->sensor,
+			rmifninfo->function_descriptor.data_base_addr + 3,
+			(unsigned char *)&status, 1)) {
+		pr_err("%s : Could not read status from 0x%x\n", __func__,
+		       rmifninfo->function_descriptor.data_base_addr + 3);
+		status = 0xff;	/* failure */
+	}
+
+	/* set a sysfs value that the user mode can read - only
+	 * upper 4 bits are the status. successful is $80, anything
+	 * else is failure */
+	instance_data->status = status & 0xf0;
+}
+EXPORT_SYMBOL(FN_34_inthandler);
+
+/* This is a stub for now, and will be fleshed out or removed as the
+ * implementation matures.
+ */
+void FN_34_attention(struct rmi_function_info *rmifninfo)
+{
+
+}
+EXPORT_SYMBOL(FN_34_attention);
+
+/* This is a stub for now, and will be fleshed out or removed as the
+ * implementation matures.
+ */
+int FN_34_config(struct rmi_function_info *rmifninfo)
+{
+	pr_debug("%s: RMI4 function $34 config\n", __func__);
+	return 0;
+}
+EXPORT_SYMBOL(FN_34_config);
+
+int FN_34_init(struct rmi_function_device *function_device)
+{
+	int retval = 0;
+	int attr_count = 0;
+	unsigned char buf[2];
+	struct rmi_function_info *rmifninfo = function_device->rfi;
+	struct rmi_fn_34_data *instance_data;
+
+	pr_debug("%s: RMI4 function $34 init\n", __func__);
+
+	if (rmifninfo->fndata) {
+		/* detect routine should only ever be called once
+		 * per rmifninfo. */
+		pr_err("%s: WTF?!? F34 instance data is already present!",
+		       __func__);
+		return -EINVAL;
+	}
+
+	instance_data = kzalloc(sizeof(struct rmi_fn_34_data), GFP_KERNEL);
+	if (!instance_data) {
+		pr_err("%s: Error allocating memory for rmi_fn_34_data.\n",
+		       __func__);
+		retval = -ENOMEM;
+		goto error_exit;
+	}
+	rmifninfo->fndata = instance_data;
+
+	/* get the Bootloader ID and Block Size. */
+	retval = rmi_read_multiple(rmifninfo->sensor,
+		rmifninfo->function_descriptor.query_base_addr,
+		buf, ARRAY_SIZE(buf));
+	if (retval) {
+		pr_err("%s : Could not read bootloaderid from 0x%04x\n",
+		       __func__,
+		       function_device->function->query_base_address);
+		goto error_exit;
+	}
+	batohs(&instance_data->bootloaderid, buf);
+
+	retval = rmi_read_multiple(rmifninfo->sensor,
+			rmifninfo->function_descriptor.query_base_addr + 3,
+			buf, ARRAY_SIZE(buf));
+	if (retval) {
+		pr_err("%s: Could not read block size from 0x%04x\n",
+		       __func__,
+		       rmifninfo->function_descriptor.query_base_addr + 3);
+		goto error_exit;
+	}
+	batohs(&instance_data->blocksize, buf);
+
+	/* Get firmware image block count and store it in the instance data */
+	retval = rmi_read_multiple(rmifninfo->sensor,
+			rmifninfo->function_descriptor.query_base_addr + 5,
+			buf, ARRAY_SIZE(buf));
+	if (retval) {
+		pr_err("%s: Could not read image block count from 0x%x\n",
+		       __func__,
+		       rmifninfo->function_descriptor.query_base_addr + 5);
+		goto error_exit;
+	}
+	batohs(&instance_data->imageblockcount, buf);
+
+	/* Get config block count and store it in the instance data */
+	retval = rmi_read_multiple(rmifninfo->sensor,
+			rmifninfo->function_descriptor.query_base_addr + 7,
+			buf, ARRAY_SIZE(buf));
+	if (retval) {
+		pr_err("%s: Could not read config block count from 0x%x, "
+			"error=%d.\n", __func__,
+			rmifninfo->function_descriptor.query_base_addr + 7,
+			retval);
+		goto error_exit;
+	}
+	batohs(&instance_data->configblockcount, buf);
+
+	/* We need a sysfs file for the image/config block to write or read.
+	 * Set up sysfs bin file for binary data block. Since the image is
+	 * already in our format there is no need to convert the data for
+	 * endianess. */
+	retval = sysfs_create_bin_file(&function_device->dev.kobj,
+				&dev_attr_data);
+	if (retval < 0) {
+		pr_err
+		    ("%s: Failed to create sysfs file for fn 34 data "
+		     "(error = %d).\n", __func__, retval);
+		retval = -ENODEV;
+		goto error_exit;
+	}
+
+	pr_debug("%s: Creating sysfs files.", __func__);
+	/* Set up sysfs device attributes. */
+	for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+		if (sysfs_create_file
+		    (&function_device->dev.kobj, &attrs[attr_count].attr) < 0) {
+			pr_err
+			    ("%s: Failed to create sysfs file for  %s.",
+			     __func__, attrs[attr_count].attr.name);
+			retval = -ENODEV;
+			goto error_exit;
+		}
+	}
+
+	return retval;
+
+error_exit:
+	for (attr_count--; attr_count >= 0; attr_count--)
+		sysfs_remove_file(&function_device->dev.kobj,
+				  &attrs[attr_count].attr);
+	kfree(instance_data);
+	return retval;
+}
+EXPORT_SYMBOL(FN_34_init);
+
+int FN_34_detect(struct rmi_function_info *rmifninfo)
+{
+	int retval = 0;
+
+	pr_debug("%s: RMI4 function $34 detect\n", __func__);
+	if (rmifninfo->sensor == NULL) {
+		pr_err("%s: NULL sensor passed in!", __func__);
+		return -EINVAL;
+	}
+
+	return retval;
+}
+EXPORT_SYMBOL(FN_34_detect);
+
+static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->bootloaderid);
+}
+
+static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,
+					size_t count)
+{
+	int error;
+	unsigned long val;
+	unsigned char data[2];
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+
+	/* need to convert the string data to an actual value */
+	error = strict_strtoul(buf, 10, &val);
+
+	if (error)
+		return error;
+
+	instance_data->bootloaderid = val;
+
+	/* Write the Bootloader ID key data back to the first two Block
+	 * Data registers (F34_Flash_Data2.0 and F34_Flash_Data2.1). */
+	hstoba(data, (unsigned short)val);
+	error =
+	    rmi_write_multiple(fn->sensor, fn->function->data_base_address,
+			       data, ARRAY_SIZE(data));
+	if (error) {
+		dev_err(dev, "%s : Could not write bootloader id to 0x%x\n",
+		       __func__, fn->function->data_base_address);
+		return error;
+	}
+
+	return count;
+}
+
+static ssize_t rmi_fn_34_blocksize_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->blocksize);
+}
+
+static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->imageblockcount);
+}
+
+static ssize_t rmi_fn_34_configblockcount_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			instance_data->configblockcount);
+}
+
+static ssize_t rmi_fn_34_status_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->status);
+}
+
+static ssize_t rmi_fn_34_cmd_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->cmd);
+}
+
+static ssize_t rmi_fn_34_cmd_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t count)
+{
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+	unsigned long val;
+	int error;
+
+	/* need to convert the string data to an actual value */
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
+
+	instance_data->cmd = val;
+
+	/* Validate command value and (if necessary) write it to the command
+	 * register.
+	 */
+	switch (instance_data->cmd) {
+	case ENABLE_FLASH_PROG:
+	case ERASE_ALL:
+	case ERASE_CONFIG:
+	case WRITE_FW_BLOCK:
+	case READ_CONFIG_BLOCK:
+	case WRITE_CONFIG_BLOCK:
+		/* Issue a Write Firmware Block ($02) command to the Flash
+		 * Command (F34_Flash_Data3, bits 3:0) field. */
+		error = rmi_write_multiple(fn->sensor,
+				fn->function->data_base_address + 3,
+			     &instance_data->cmd, 1);
+		if (error) {
+			dev_err(dev, "%s: Could not write command 0x%02x "
+				"to 0x%04x\n", __func__, instance_data->cmd,
+				fn->function->data_base_address + 3);
+			return error;
+		}
+		break;
+	default:
+		dev_dbg(dev, "%s: RMI4 function $34 - "
+				"unknown command 0x%02lx.\n", __func__, val);
+		count = -EINVAL;
+		break;
+	}
+
+	return count;
+}
+
+static ssize_t rmi_fn_34_data_read(struct file *data_file,
+				struct kobject *kobj,
+				struct bin_attribute *attributes,
+				char *buf,
+				loff_t pos,
+				size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+	int error;
+
+	if (count != instance_data->blocksize) {
+		dev_err(dev,
+			"%s: Incorrect F34 block size %d. Expected size %d.\n",
+			__func__, count, instance_data->blocksize);
+		return -EINVAL;
+	}
+
+	/* Read the data from flash into buf.  The app layer will be blocked
+	 * at reading from the sysfs file.  When we return the count (or
+	 * error if we fail) the app will resume. */
+	error = rmi_read_multiple(fn->sensor,
+			fn->function->data_base_address + pos,
+			(unsigned char *)buf, count);
+	if (error) {
+		dev_err(dev, "%s : Could not read data from 0x%llx\n",
+		       __func__, fn->function->data_base_address + pos);
+		return error;
+	}
+
+	return count;
+}
+
+static ssize_t rmi_fn_34_data_write(struct file *data_file,
+				struct kobject *kobj,
+				struct bin_attribute *attributes,
+				char *buf,
+				loff_t pos,
+				size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct rmi_function_device *fn = dev_get_drvdata(dev);
+	struct rmi_fn_34_data *instance_data = fn->rfi->fndata;
+	unsigned int blocknum;
+	int error;
+	unsigned int remainder;
+
+	/* Write the data from buf to flash. The app layer will be
+	 * blocked at writing to the sysfs file.  When we return the
+	 * count (or error if we fail) the app will resume. */
+
+	if (count != instance_data->blocksize) {
+		dev_err(dev,
+			"%s: Incorrect F34 block size %d. Expected size %d.\n",
+			__func__, count, instance_data->blocksize);
+		return -EINVAL;
+	}
+
+	/* Verify that the byte offset is always aligned on a block boundary
+	 * and if not return an error.  We can't just use the mod operator %
+	 * and do a (pos % instance_data->blocksize) because of a gcc
+	 * bug that results in undefined symbols.  So we have to compute
+	 * it the hard way.  Grumble. */
+	div_u64_rem(pos, instance_data->blocksize, &remainder);
+	if (remainder) {
+		dev_err(dev,
+			"%s: Invalid byte offset of %llx leads to invalid "
+			"block number.\n", __func__, pos);
+		return -EINVAL;
+	}
+
+	/* Compute the block number using the byte offset (pos) and the
+	 * block size.  Once again, we can't just do a divide due to a
+	 * gcc bug. */
+	blocknum = div_u64(pos, instance_data->blocksize);
+
+	/* Write the block number first */
+	error = rmi_write_multiple(fn->sensor,
+				fn->function->data_base_address,
+				(unsigned char *)&blocknum, 2);
+	if (error) {
+		dev_err(dev, "%s: Could not write block number to 0x%x\n",
+		       __func__, fn->function->data_base_address);
+		return error;
+	}
+
+	/* Write the data block - only if the count is non-zero  */
+	if (count) {
+		error = rmi_write_multiple(fn->sensor,
+				fn->function->data_base_address + 2,
+				(unsigned char *)buf, count);
+		if (error) {
+			dev_err(dev, "%s: Could not write block data "
+				"to 0x%x\n", __func__,
+				fn->function->data_base_address + 2);
+			return error;
+		}
+	}
+
+	return count;
+}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-07-01  5:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-01  5:19 [PATCH 0/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver Christopher Heiny
2011-07-01  5:19 ` [PATCH 1/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 2/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 3/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 4/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 5/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 6/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 7/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 8/9] " Christopher Heiny
2011-07-01  5:19 ` [PATCH 9/9] " Christopher Heiny

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox