[PATCH 2/9] input/touchscreen: Synaptics RMI4 Touchscreen Driver

From: Christopher Heiny
Date: Fri Jul 01 2011 - 01:37:42 EST


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@xxxxxxxxxxxxx>
Signed-off-by: William Manson <wmanson@xxxxxxxxxxxxx>
Signed-off-by: Allie Xiong <axiong@xxxxxxxxxxxxx>
Signed-off-by: Peichen Chang <peichen.chang@xxxxxxxxxxxxx>

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

Acked-by: Jean Delvare <khali@xxxxxxxxxxxx>

---

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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/