#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
#include <linux/atmel_mxt224.h>
+#include <linux/rmi_i2c.h>
#include <linux/atomisp_platform.h>
#include <media/v4l2-subdev.h>
gpio_set_value(I2C_1_GPIO_PIN, 0);
udelay(10);
lnw_gpio_set_alt(I2C_1_GPIO_PIN, LNW_ALT_1);
-#undef I2C_1_GPIO_PIN 27
+#undef I2C_1_GPIO_PIN
}
EXPORT_SYMBOL(max17042_i2c_reset_workaround);
return &mxt_pdata;
}
+static struct rmi_f11_functiondata synaptics_f11_data = {
+ .swap_axes = true,
+};
+
+static unsigned char synaptic_keys[31] = {1, 2, 3, 4,};
+ /* {KEY_BACK,KEY_MENU,KEY_HOME,KEY_SEARCH,} */
+
+static struct rmi_button_map synaptics_button_map = {
+ .nbuttons = 31,
+ .map = synaptic_keys,
+};
+static struct rmi_f19_functiondata synaptics_f19_data = {
+ .button_map = &synaptics_button_map,
+};
+
+#define RMI_F11_INDEX 0x11
+#define RMI_F19_INDEX 0x19
+
+static struct rmi_functiondata synaptics_functiondata[] = {
+ {
+ .function_index = RMI_F11_INDEX,
+ .data = &synaptics_f11_data,
+ },
+ {
+ .function_index = RMI_F19_INDEX,
+ .data = &synaptics_f19_data,
+ },
+};
+
+static struct rmi_functiondata_list synaptics_perfunctiondata = {
+ .count = ARRAY_SIZE(synaptics_functiondata),
+ .functiondata = synaptics_functiondata,
+};
+
+
+static struct rmi_sensordata s3202_sensordata = {
+ .perfunctiondata = &synaptics_perfunctiondata,
+};
+
+void *s3202_platform_data_init(void *info)
+{
+ struct i2c_board_info *i2c_info = info;
+ static struct rmi_i2c_platformdata s3202_platform_data = {
+ .delay_ms = 50,
+ .sensordata = &s3202_sensordata,
+ };
+
+ s3202_platform_data.i2c_address = i2c_info->addr;
+ s3202_sensordata.attn_gpio_number = get_gpio_by_name("ts_int");
+ s3202_sensordata.rst_gpio_number = get_gpio_by_name("ts_rst");
+
+ return &s3202_platform_data;
+}
+
static const struct devs_id __initconst device_ids[] = {
{"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
{"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data},
{"mt9e013", SFI_DEV_TYPE_I2C, 0, &mt9e013_platform_data_init},
{"mt9m114", SFI_DEV_TYPE_I2C, 0, &mt9m114_platform_data_init},
{"mxt224", SFI_DEV_TYPE_I2C, 0, &atmel_mxt224_platform_data_init},
-
+ {"synaptics_3202", SFI_DEV_TYPE_I2C, 0, &s3202_platform_data_init},
{},
};
help
Say Y here if you have a mXT224 touchscreen
If unsure, say N.
+
+source "drivers/input/touchscreen/rmi/Kconfig"
endif
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
-obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT224) += atmel_mxt224.o
\ No newline at end of file
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT224) += atmel_mxt224.o
+
+obj-y += rmi/
--- /dev/null
+#
+# Touchscreen driver configuration
+#
+
+config TOUCHSCREEN_SYNAPTICS_RMI4_I2C
+ tristate "Synaptics RMI4 I2C touchscreens"
+ depends on I2C
+ default n
+ 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 SYNA_MULTI_TOUCH
+ bool "add multi touch support to RMI4 driver"
+ default y
+ depends on TOUCHSCREEN_SYNAPTICS_RMI4_I2C
+ help
+ This option enables multi-touch capabilities in the input device.
+ Driver will report ABS_MT_* event sequence required by kernel
+ multi-touch protocol.
+
+ If only need single-touch capability, say N.
+
+
+config SYNA_RMI_DEV
+ bool "rmi_dev"
+ depends on TOUCHSCREEN_SYNAPTICS_RMI4_I2C
+ help
+ Enable mutli-touch capabilities in the input device
--- /dev/null
+#
+# Makefile for the touchscreen drivers.
+#
+
+# Each configuration option enables a list of files.
+#ccflags-y += -DDEBUG
+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_f54.o rmi_i2c.o
--- /dev/null
+This is the Synaptics S3200 Touch Controller driver for Intel Clovertrail platform.
+Here are two tips to use the driver:
+1. Since touch screen is on different i2c bus for EV and VV platform, please change
+the I2C_BUS_NUM macro in rmi_i2c.c accordingly when using this driver on these two
+platforms.
+2. Set the COMM_DEBUG macro in rmi_i2c.c to dump more debug information.
--- /dev/null
+/**
+ *
+ * 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
--- /dev/null
+/*
+ * 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_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;
+ dev_set_drvdata(&rmi_sensor_dev->dev, rmi_sensor_dev);
+
+ 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->set_attn_handler(rpd,
+ 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");
--- /dev/null
+/*
+ *
+ * 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
--- /dev/null
+/*
+ * Synaptics Register Mapped Interface (RMI4) - RMI device 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/fs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/syscalls.h>
+
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_function.h"
+#include "rmi_sensor.h"
+#include "rmi_dev.h"
+
+#if defined(CONFIG_SYNA_RMI_DEV)
+
+#define CHAR_DEVICE_NAME "rmi"
+#define CHAR_DEVICE_NAME_SZ 3
+
+#define REG_ADDR_LIMIT 0xFFFF
+
+/*store dynamically allocated major number of char device*/
+static int rmi_char_dev_major_num;
+
+
+/* file operations for RMI char device */
+
+/*
+ * rmi_char_dev_llseek: - use to setup register address
+ *
+ * @filp: file structure for seek
+ * @off: offset
+ * if whence == SEEK_SET,
+ * high 16 bits: page address
+ * low 16 bits: register address
+ *
+ * if whence == SEEK_CUR,
+ * offset from current position
+ *
+ * if whence == SEEK_END,
+ * offset from END(0xFFFF)
+ *
+ * @whence: SEEK_SET , SEEK_CUR or SEEK_END
+ */
+static loff_t rmi_char_dev_llseek(struct file *filp, loff_t off, int whence)
+{
+ loff_t newpos;
+ struct rmi_char_dev *my_char_dev = filp->private_data;
+
+ if (IS_ERR(my_char_dev)) {
+ pr_debug("%s: pointer of char device is invalid", __func__);
+ return -EBADF;
+ }
+
+ mutex_lock(&(my_char_dev->mutex_file_op));
+
+ switch (whence) {
+ case SEEK_SET:
+ newpos = off;
+ break;
+
+ case SEEK_CUR:
+ newpos = filp->f_pos + off;
+ break;
+
+ case SEEK_END:
+ newpos = REG_ADDR_LIMIT + off;
+ break;
+
+ default: /* can't happen */
+ newpos = -EINVAL;
+ goto clean_up;
+ }
+
+ if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
+ pr_debug("%s: newpos 0x%04x is invalid.",
+ __func__, (unsigned int)newpos);
+ newpos = -EINVAL;
+ goto clean_up;
+ }
+
+ filp->f_pos = newpos;
+
+clean_up:
+
+ mutex_unlock(&(my_char_dev->mutex_file_op));
+
+ return newpos;
+}
+
+/*
+ * rmi_char_dev_read: - use to read data from RMI stream
+ *
+ * @filp: file structure for read
+ * @buf: user-level buffer pointer
+ *
+ * @count: number of byte read
+ * @f_pos: offset (starting register address)
+ *
+ * @return number of bytes read into user buffer (buf) if succeeds
+ * negative number if error occurs.
+ */
+static ssize_t rmi_char_dev_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct rmi_char_dev *my_char_dev = filp->private_data;
+ ssize_t ret_value = 0;
+ unsigned char tmpbuf[count+1];
+ struct rmi_phys_driver *rpd;
+
+ /* limit offset to REG_ADDR_LIMIT-1 */
+ if (count > (REG_ADDR_LIMIT - *f_pos))
+ count = REG_ADDR_LIMIT - *f_pos;
+
+ if (count == 0)
+ return 0;
+
+ if (IS_ERR(my_char_dev)) {
+ pr_err("%s: pointer of char device is invalid", __func__);
+ ret_value = -EBADF;
+ return ret_value;
+ }
+
+ mutex_lock(&(my_char_dev->mutex_file_op));
+
+ rpd = my_char_dev->sensor->rpd;
+ /*
+ * just let it go through , because we do not know the register is FIFO
+ * register or not
+ */
+
+ /* return zero upon success */
+ ret_value = rpd->read_multiple(rpd, *f_pos, tmpbuf, count);
+ if (ret_value == 0) {
+ /* we prepare the amount of data requested */
+ ret_value = count;
+ *f_pos += count;
+ } else {
+ ret_value = -EIO;
+ goto clean_up;
+ }
+
+ if (copy_to_user(buf, tmpbuf, count))
+ ret_value = -EFAULT;
+
+clean_up:
+
+ mutex_unlock(&(my_char_dev->mutex_file_op));
+
+ return ret_value;
+}
+
+/*
+ * rmi_char_dev_write: - use to write data into RMI stream
+ *
+ * @filep : file structure for write
+ * @buf: user-level buffer pointer contains data to be written
+ * @count: number of byte be be written
+ * @f_pos: offset (starting register address)
+ *
+ * @return number of bytes written from user buffer (buf) if succeeds
+ * negative number if error occurs.
+ */
+static ssize_t rmi_char_dev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct rmi_char_dev *my_char_dev = filp->private_data;
+ ssize_t ret_value = 0;
+ unsigned char tmpbuf[count+1];
+ struct rmi_phys_driver *rpd;
+
+ /* limit offset to REG_ADDR_LIMIT-1 */
+ if (count > (REG_ADDR_LIMIT - *f_pos))
+ count = REG_ADDR_LIMIT - *f_pos;
+
+ if (count == 0)
+ return 0;
+
+ if (IS_ERR(my_char_dev)) {
+ pr_err("%s: pointer of char device is invalid", __func__);
+ ret_value = -EBADF;
+ return ret_value;
+ }
+
+ if (copy_from_user(tmpbuf, buf, count)) {
+ ret_value = -EFAULT;
+ return ret_value;
+ }
+
+ mutex_lock(&(my_char_dev->mutex_file_op));
+
+ rpd = my_char_dev->sensor->rpd;
+ /*
+ * just let it go through , because we do not know the register is FIFO
+ * register or not
+ */
+
+ /* return one upon success */
+
+ ret_value = rpd->write_multiple(rpd, *f_pos, tmpbuf, count);
+
+ if (ret_value == 1) {
+ /* we had written the amount of data requested */
+ ret_value = count;
+ *f_pos += count;
+ } else {
+ ret_value = -EIO;
+ }
+
+ mutex_unlock(&(my_char_dev->mutex_file_op));
+
+ return ret_value;
+}
+
+/*
+ * rmi_char_dev_open: - get a new handle for from RMI stream
+ * @inp : inode struture
+ * @filp: file structure for read/write
+ *
+ * @return 0 if succeeds
+ */
+static int rmi_char_dev_open(struct inode *inp, struct file *filp)
+{
+ /* store the device pointer to file structure */
+ struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
+ struct rmi_char_dev, main_dev);
+ struct rmi_sensor_driver *sensor = my_dev->sensor;
+ int ret_value = 0;
+
+ filp->private_data = my_dev;
+
+ if (!sensor)
+ return -EACCES;
+
+ mutex_lock(&(my_dev->mutex_file_op));
+ if (my_dev->ref_count < 1)
+ my_dev->ref_count++;
+ else
+ ret_value = -EACCES;
+
+ mutex_unlock(&(my_dev->mutex_file_op));
+
+ return ret_value; /*succeeds*/
+}
+
+/*
+ * rmi_char_dev_release: - release an existing handle
+ * @inp: inode structure
+ * @filp: file structure for read/write
+ *
+ * @return 0 if succeeds
+ */
+static int rmi_char_dev_release(struct inode *inp, struct file *filp)
+{
+ struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
+ struct rmi_char_dev, main_dev);
+ struct rmi_sensor_driver *sensor = my_dev->sensor;
+
+ if (!sensor)
+ return -EACCES;
+
+ mutex_lock(&(my_dev->mutex_file_op));
+
+ my_dev->ref_count--;
+ if (my_dev->ref_count < 0)
+ my_dev->ref_count = 0;
+
+ mutex_unlock(&(my_dev->mutex_file_op));
+
+ return 0; /*succeeds*/
+}
+
+static const struct file_operations rmi_char_dev_fops = {
+ .owner = THIS_MODULE,
+ .llseek = rmi_char_dev_llseek,
+ .read = rmi_char_dev_read,
+ .write = rmi_char_dev_write,
+ .open = rmi_char_dev_open,
+ .release = rmi_char_dev_release,
+};
+
+/*
+ * rmi_char_dev_clean_up - release memory or unregister driver
+ * @char_dev: char device structure
+ * @char_device_class: class of the device use to generate one under /dev
+ *
+ */
+static void rmi_char_dev_clean_up(struct rmi_char_dev *char_dev,
+ struct class *char_device_class)
+{
+ dev_t devno = char_dev->main_dev.dev;
+
+ /* Get rid of our char dev entries */
+ if (char_dev) {
+ cdev_del(&char_dev->main_dev);
+ kfree(char_dev);
+ }
+
+ if (char_device_class) {
+ device_destroy(char_device_class, devno);
+ class_unregister(char_device_class);
+ class_destroy(char_device_class);
+ }
+ /* cleanup_module is never called if registering failed */
+ unregister_chrdev_region(devno, 1);
+ pr_debug("%s: rmi_char_dev is removed\n", __func__);
+}
+
+/*
+ * rmi_char_devnode - return device permission
+ *
+ * @dev: char device structure
+ * @mode: file permission
+ *
+ */
+static char *rmi_char_devnode(struct device *dev, mode_t *mode)
+{
+ if (!mode)
+ return NULL;
+ /* rmi** */
+ /**mode = 0666*/
+ *mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+
+ return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
+}
+
+/*
+ * rmi_char_dev_register - register char device (called from up-level)
+ *
+ * @physical_driver: pointer to physical_driver of the lower-level stack
+ * (I2C or SPI)
+ * @sensor_dev: sensor device containing this device
+ *
+ * @return: zero if suceeds
+ */
+int rmi_char_dev_register(struct rmi_phys_driver *physical_driver,
+ struct rmi_sensor_device *sensor_dev)
+{
+ struct rmi_char_dev *char_dev;
+ dev_t dev_no;
+ int err;
+ int result;
+ struct device *device_ptr;
+
+ if (rmi_char_dev_major_num) {
+ dev_no = MKDEV(rmi_char_dev_major_num, 0);
+ result = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
+ } else {
+ result = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
+ /* let kernel allocate a major for us */
+ rmi_char_dev_major_num = MAJOR(dev_no);
+ pr_debug("%s Major number of rmi_char_dev: %d\n", __func__,
+ rmi_char_dev_major_num);
+
+ }
+ if (result < 0)
+ return result;
+
+ /* allocate memory for rmi_char_dev */
+ char_dev = kzalloc(sizeof(struct rmi_char_dev), GFP_KERNEL);
+ if (!char_dev) {
+ pr_err("%s: Error allocating memory. ", __func__);
+ /* unregister the char device region */
+ __unregister_chrdev(rmi_char_dev_major_num, MINOR(dev_no), 1,
+ CHAR_DEVICE_NAME);
+ return -ENOMEM;
+ }
+ /* initialize mutex */
+ mutex_init(&char_dev->mutex_file_op);
+
+ /* assign device pointer to sensor_device */
+ sensor_dev->char_dev = char_dev;
+
+ /* register char device */
+
+ /* store driver pointer of rmi driver */
+ char_dev->sensor = sensor_dev->driver;
+
+ /* initialize char device */
+ cdev_init(&char_dev->main_dev, &rmi_char_dev_fops);
+
+ err = cdev_add(&char_dev->main_dev, dev_no, 1);
+ /* check if adding device fails */
+ if (err) {
+ pr_err("%s: Error %d adding rmi_char_dev", __func__, err);
+ rmi_char_dev_clean_up(sensor_dev->char_dev,
+ sensor_dev->rmi_char_device_class);
+ return err;
+ }
+
+ /* create device node */
+ sensor_dev->rmi_char_device_class = class_create(THIS_MODULE,
+ CHAR_DEVICE_NAME);
+
+ if (IS_ERR(sensor_dev->rmi_char_device_class)) {
+ pr_err("%s: create /dev/rmi failed", __func__);
+ rmi_char_dev_clean_up(sensor_dev->char_dev,
+ sensor_dev->rmi_char_device_class);
+ return -ENODEV;
+ }
+ /* setup permission */
+ sensor_dev->rmi_char_device_class->devnode = rmi_char_devnode;
+ /* class creation */
+ device_ptr = device_create(
+ sensor_dev->rmi_char_device_class,
+ NULL, dev_no, NULL,
+ CHAR_DEVICE_NAME"%d",
+ MINOR(dev_no));
+
+ if (IS_ERR(device_ptr)) {
+ pr_err("%s: create rmi device", __func__);
+ rmi_char_dev_clean_up(sensor_dev->char_dev,
+ sensor_dev->rmi_char_device_class);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(rmi_char_dev_register);
+
+/*
+ * rmi_char_dev_unregister - unregister char device (called from up-level)
+ *
+ * @physical_driver: pointer to physical_driver of the lower-level stack
+ * (I2C or SPI)
+ * @sensor_dev: sensor device containing this device
+ *
+ */
+void rmi_char_dev_unregister(struct rmi_char_dev *char_dev,
+ struct class *char_device_class)
+{
+ /* clean up */
+ rmi_char_dev_clean_up(char_dev, char_device_class);
+}
+EXPORT_SYMBOL(rmi_char_dev_unregister);
+
+#endif /*CONFIG_SYNA_RMI_DEV*/
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Char Device");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ *
+ * Synaptics Register Mapped Interface (RMI4) - RMI device 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_DEV_H)
+#define _RMI_DEV_H
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+
+
+struct rmi_sensor_device;
+
+/*
+ * rmi_char_dev: a char device to directly control RMI interface
+ */
+
+#define RMI_CHAR_DEV_TMPBUF_SZ 128
+#define RMI_REG_ADDR_PAGE_SELECT 0xFF
+
+struct rmi_char_dev {
+ /* mutex for file operation*/
+ struct mutex mutex_file_op;
+ /* main char dev structure */
+ struct cdev main_dev;
+
+ /* register address for RMI protocol */
+ /* filp->f_pos */
+
+ /* pointer to the corresponding phys driver info for this sensor */
+ /* The senor driver has the pointers to read, write, etc. */
+ struct rmi_sensor_driver *sensor;
+ /* reference count */
+ int ref_count;
+};
+
+int rmi_char_dev_register(struct rmi_phys_driver *physical_driver,
+ struct rmi_sensor_device *sensor_dev);
+void rmi_char_dev_unregister(struct rmi_char_dev *char_dev,
+ struct class *char_device_class);
+
+
+#endif /*_RMI_DEV_H*/
--- /dev/null
+/**
+ *
+ * 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 <linux/rmi_platformdata.h>
+#include "rmi.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);
+ bool polling_required;
+ int irq;
+
+ void (*set_attn_handler) (
+ struct rmi_phys_driver *physdrvr,
+ void (*attention) (struct rmi_phys_driver *physdrvr));
+ int (*enable_device) (struct rmi_phys_driver *physdrvr);
+ void (*disable_device) (struct rmi_phys_driver *physdrvr);
+
+ /* Some quick data relating to the operation of the device. */
+ char *proto_name;
+ unsigned long tx_count;
+ unsigned long tx_bytes;
+ unsigned long tx_errors;
+ unsigned long rx_count;
+ unsigned long rx_bytes;
+ unsigned long rx_errors;
+ unsigned long attn_count;
+
+ 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
--- /dev/null
+/**
+ *
+ * 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 <linux/rmi_platformdata.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.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)
+#define F01_INITREFLASH (1 << 7)
+
+/* 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 ssize_t rmi_fn_01_initreflash_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+static ssize_t rmi_fn_01_initreflash_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, 0666,
+ rmi_fn_01_reportrate_show, rmi_fn_01_reportrate_store), /* RW */
+ __ATTR(reset, 0222,
+ 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*/
+ __ATTR(initreflash, (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH),
+ rmi_fn_01_initreflash_show, rmi_fn_01_initreflash_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;
+}
+
+static ssize_t rmi_fn_01_initreflash_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;
+ unsigned char initreflash = 0;
+
+ if (!instance_data || !instance_data->query_registers)
+ return snprintf(buf, PAGE_SIZE, "unknown\n");
+
+ initreflash = (instance_data->query_registers->properties &
+ RMI_F01_INIT_REFLASH_MASK) >> RMI_F01_INIT_REFLASH_OFFSET;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", initreflash);
+}
+
+static ssize_t rmi_fn_01_initreflash_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 initreflash;
+ int retval;
+
+ if (sscanf(buf, "%u", &initreflash) != 1)
+ return -EINVAL;
+ if (initreflash < 0 || initreflash > 1)
+ return -EINVAL;
+
+ /* Per spec, 0 has no effect, so we skip it entirely. */
+ if (initreflash) {
+ retval = rmi_set_bits(fn->sensor,
+ fn->rfi->function_descriptor.command_base_addr,
+ F01_INITREFLASH);
+ if (retval < 0) {
+ dev_err(dev, "%s: failed to issue initreflash command, "
+ "error = %d.", __func__, retval);
+ return retval;
+ }
+ }
+
+ return count;
+}
+
+/* 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))
+ );
+ }
+}
--- /dev/null
+/**
+ *
+ * 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)
+
+#define RMI_F01_INIT_REFLASH_MASK 0x04
+/* Position of bits in query 1 register (product properties). */
+#define RMI_F01_INIT_REFLASH_OFFSET 2
+#endif
--- /dev/null
+/**
+ *
+ * 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/rmi_platformdata.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f05.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);
+
+
+/*
+ * This is stubbed for now, will be filled out in the future.
+ */
+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);
--- /dev/null
+/**
+ *
+ * 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
--- /dev/null
+/**
+ *
+ * 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 <linux/rmi_platformdata.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f11.h"
+
+
+/*
+ * This will dump a ton of stuff to the console. Don't turn it on.
+ */
+#define POS_DEBUG 0
+
+/* 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
+
+/*
+ * Bitmasks and offsets for various things. All of these are fixed in the
+ * spec, and most are used exactly once in the code below.
+ */
+/* Per device queries. */
+#define HAS_QUERY_9_MASK 0x08
+#define HAS_QUERY_11_MASK 0x10
+#define NR_SENSORS_MASK 0x07
+
+#define DEVICE_QUERY_SIZE 1
+
+
+/* Per sensor queries. */
+#define CONFIGURABLE_OFFSET 0
+#define CONFIGURABLE_MASK 0x80
+#define HAS_SENSITIVITY_ADJUST_OFFSET 0
+#define HAS_SENSITIVITY_ADJUST_MASK 0x40
+#define HAS_GESTURES_OFFSET 0
+#define HAS_GESTURES_MASK 0x20
+#define HAS_ABS_OFFSET 0
+#define HAS_ABS_MASK 0x10
+#define HAS_REL_OFFSET 0
+#define HAS_REL_MASK 0x08
+#define NR_FINGERS_OFFSET 0
+#define NR_FINGERS_MASK 0x07
+#define NR_X_ELECTRODES_OFFSET 1
+#define NR_Y_ELECTRODES_OFFSET 2
+#define MAX_ELECTRODES_OFFSET 3
+#define NR_ELECTRODES_MASK 0x7F
+#define ABS_DATA_SIZE_OFFSET 4
+#define ABS_DATA_SIZE_MASK 0x03
+#define HAS_ANCHORED_FINGER_OFFSET 4
+#define HAS_ANCHORED_FINGER_MASK 0x04
+#define HAS_ADJ_HYST_OFFSET 4
+#define HAS_ADJ_HYST_MASK 0x08
+#define HAS_DRIBBLE_OFFSET 4
+#define HAS_DRIBBLE_MASK 0x10
+
+#define HAS_SINGLE_TAP_MASK 0x01
+#define HAS_TAP_AND_HOLD_MASK 0x02
+#define HAS_DOUBLE_TAP_MASK 0x04
+#define HAS_EARLY_TAP_MASK 0x08
+#define HAS_FLICK_MASK 0x10
+#define HAS_PRESS_MASK 0x20
+#define HAS_PINCH_MASK 0x40
+#define ROTATE_FLICK_DATA_BYTES 2
+
+#define HAS_PALM_DETECT_MASK 0x01
+#define HAS_ROTATE_MASK 0x02
+#define HAS_TOUCH_SHAPES_MASK 0x04
+#define TOUCH_SHAPE_BITS_PER_BYTE 8
+#define HAS_SCROLL_ZONES_MASK 0x08
+#define HAS_INDIVIDUAL_SCROLL_ZONES_MASK 0x10
+#define SCROLL_ZONE_DATA_BYTES 2
+#define HAS_MULTIFINGER_SCROLL_MASK 0x20
+#define HAS_MULTIFINGER_SCROLL_EDGE_MOTION_MASK 0x40
+#define HAS_MULTIFINGER_SCROLL_INERTIA_MASK 0x80
+
+#define HAS_PEN_MASK 0x01
+#define HAS_PROXIMITY_MASK 0x02
+#define HAS_PALM_DETECT_SENSITIVITY_MASK 0x04
+#define HAS_SUPPRESS_ON_PALM_DETECT_MASK 0x08
+
+#define NUMBER_OF_TOUCH_SHAPES_MASK 0x1F
+
+#define HAS_Z_TUNING_MASK 0x01
+#define HAS_ALGORITHM_SECTION_MASK 0x02
+
+/* Data registers. */
+#define X_HIGH_BITS_OFFSET 0
+#define Y_HIGH_BITS_OFFSET 1
+#define XY_LOW_BITS_OFFSET 2
+#define XY_HIGH_BITS_SHIFT 4
+#define XY_HIGH_BITS_MASK 0x0FF0
+#define XY_LOW_BITS_MASK 0x0F
+#define X_LOW_BITS_SHIFT 0
+#define Y_LOW_BITS_SHIFT 4
+#define W_XY_OFFSET 3
+#define W_X_SHIFT 0
+#define W_Y_SHIFT 4
+#define W_XY_MASK 0x0F
+#define Z_OFFSET 4
+#define REL_X_OFFSET 0
+#define REL_Y_OFFSET 1
+
+
+/* The per-sensor query registers will never be larger than this. */
+#define MAX_PER_SENSOR_QUERY_SIZE 11
+
+/* If we can't figure out how many bytes of abs data there are per finger,
+ * we'll use this and hope we get lucky.
+ */
+#define DEFAULT_ABS_BYTES_PER_FINGER 5
+
+/* How many finger status values are packed into a byte?
+ */
+#define FINGER_STATES_PER_BYTE 4
+#define BITS_PER_FINGER_STATE 2
+
+#define REL_BYTES_PER_FINGER 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;
+
+ unsigned int data8_offset;
+ unsigned int data9_offset;
+ unsigned int data10_offset;
+ unsigned int data11_offset;
+ unsigned int data13_offset;
+ unsigned int data14_offset;
+ unsigned int data16_offset;
+};
+
+enum finger_state {
+ F11_NO_FINGER = 0,
+ F11_PRESENT = 1,
+ F11_INACCURATE = 2,
+ F11_RESERVED = 3
+};
+
+#define FINGER_STATE_MASK 0x03
+
+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, 0666,
+ rmi_fn_11_flip_show, rmi_fn_11_flip_store), /* RW attr */
+ __ATTR(clip, 0666,
+ rmi_fn_11_clip_show, rmi_fn_11_clip_store), /* RW attr */
+ __ATTR(offset, 0666,
+ rmi_fn_11_offset_show, rmi_fn_11_offset_store), /* RW attr */
+ __ATTR(swap, 0666,
+ rmi_fn_11_swap_show, rmi_fn_11_swap_store), /* RW attr */
+ __ATTR(relreport, 0666,
+ 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 handle_absolute_reports(struct rmi_function_info *rmifninfo);
+static void handle_relative_report(struct rmi_function_info *rmifninfo);
+
+/*
+ * Read the device query register and extract interesting data.
+ */
+static int read_device_query(struct rmi_function_info *rmifninfo)
+{
+ int retval = 0;
+ struct f11_instance_data *instance_data = rmifninfo->fndata;
+ unsigned char device_query;
+
+ retval = rmi_read(rmifninfo->sensor,
+ rmifninfo->function_descriptor.query_base_addr,
+ &device_query);
+ if (retval) {
+ pr_err("%s: Could not read F11 device query at 0x%04x\n",
+ __func__,
+ rmifninfo->function_descriptor.query_base_addr);
+ return retval;
+ }
+
+ /* Extract device data. */
+ instance_data->device_info->has_query_9 =
+ (device_query & HAS_QUERY_9_MASK) != 0;
+ instance_data->device_info->has_query_11 =
+ (device_query & HAS_QUERY_11_MASK) != 0;
+ instance_data->device_info->number_of_sensors =
+ (device_query & NR_SENSORS_MASK) + 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);
+ if (instance_data->device_info->number_of_sensors > 1)
+ pr_warning("%s: WARNING device has %d sensors, but RMI4 "
+ "driver does not support multiple sensors yet.",
+ __func__,
+ instance_data->device_info->number_of_sensors);
+
+ return retval;
+}
+
+/*
+ * Read and parse the per sensor query information from the specified
+ * address into the specified sensor_info.
+ */
+static int read_per_sensor_query(struct rmi_function_info *rmifninfo,
+ struct rmi_F11_sensor_query *sensor_info,
+ unsigned char address)
+{
+ int retval = 0;
+ struct f11_instance_data *instance_data = rmifninfo->fndata;
+ unsigned char query_buffer[MAX_PER_SENSOR_QUERY_SIZE];
+ unsigned int nr_fingers;
+ unsigned int query_offset;
+
+ retval = rmi_read_multiple(rmifninfo->sensor, address,
+ query_buffer, sizeof(query_buffer));
+ if (retval) {
+ pr_err("%s: Could not read F11 device query at 0x%04x\n",
+ __func__, address);
+ return retval;
+ }
+
+ /* 2D data sources have only 3 bits for the number of fingers
+ * supported - so the encoding is a bit wierd. */
+ sensor_info->number_of_fingers = DEFAULT_NR_OF_FINGERS;
+ nr_fingers = query_buffer[NR_FINGERS_OFFSET] & NR_FINGERS_MASK;
+ switch (nr_fingers) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ sensor_info->number_of_fingers = nr_fingers + 1;
+ break;
+ case 5:
+ sensor_info->number_of_fingers = 10;
+ break;
+ default:
+ pr_warning("%s: Invalid F11 nr fingers %d. Assuming %d.",
+ __func__, nr_fingers, DEFAULT_NR_OF_FINGERS);
+ }
+ pr_debug("%s: Number of fingers: %d.", __func__,
+ sensor_info->number_of_fingers);
+
+ sensor_info->configurable =
+ (query_buffer[CONFIGURABLE_OFFSET] & CONFIGURABLE_MASK) != 0;
+ sensor_info->has_sensitivity_adjust =
+ (query_buffer[HAS_SENSITIVITY_ADJUST_OFFSET] &
+ HAS_SENSITIVITY_ADJUST_MASK) != 0;
+ sensor_info->has_gestures =
+ (query_buffer[HAS_GESTURES_OFFSET] & HAS_GESTURES_MASK) != 0;
+ sensor_info->has_absolute =
+ (query_buffer[HAS_ABS_OFFSET] & HAS_ABS_MASK) != 0;
+ sensor_info->has_relative =
+ (query_buffer[HAS_REL_OFFSET] & HAS_REL_MASK) != 0;
+
+ sensor_info->abs_data_size =
+ query_buffer[ABS_DATA_SIZE_OFFSET] & ABS_DATA_SIZE_MASK;
+ sensor_info->has_anchored_finger =
+ query_buffer[HAS_ANCHORED_FINGER_OFFSET] &
+ HAS_ANCHORED_FINGER_MASK;
+ sensor_info->has_adj_hyst =
+ query_buffer[HAS_ADJ_HYST_OFFSET] & HAS_ADJ_HYST_MASK;
+ sensor_info->has_dribble =
+ query_buffer[HAS_DRIBBLE_OFFSET] & HAS_DRIBBLE_MASK;
+
+ /* From here on, query offsets are determined by the presence or
+ * absence of various features.
+ */
+ query_offset = ABS_DATA_SIZE_OFFSET + 1;
+
+ /* This byte is here if we have relative reporting, but it
+ * doesn't contain anything.
+ */
+ if (sensor_info->has_relative)
+ query_offset++;
+
+ /* The next two bytes are present if we have gestures. */
+ if (sensor_info->has_gestures) {
+ sensor_info->has_pinch =
+ query_buffer[query_offset] & HAS_PINCH_MASK;
+ sensor_info->has_flick =
+ query_buffer[query_offset] & HAS_FLICK_MASK;
+ sensor_info->has_tap =
+ query_buffer[query_offset] & HAS_SINGLE_TAP_MASK;
+ sensor_info->has_tap_and_hold =
+ query_buffer[query_offset] & HAS_TAP_AND_HOLD_MASK;
+ sensor_info->has_double_tap =
+ query_buffer[query_offset] & HAS_DOUBLE_TAP_MASK;
+ sensor_info->has_early_tap =
+ query_buffer[query_offset] & HAS_EARLY_TAP_MASK;
+ sensor_info->has_press =
+ query_buffer[query_offset] & HAS_PRESS_MASK;
+ query_offset++;
+
+ sensor_info->has_palm_detect =
+ query_buffer[query_offset] & HAS_PALM_DETECT_MASK;
+ sensor_info->has_rotate =
+ query_buffer[query_offset] & HAS_ROTATE_MASK;
+ sensor_info->has_touch_shapes =
+ query_buffer[query_offset] & HAS_TOUCH_SHAPES_MASK;
+ sensor_info->has_scroll_zones =
+ query_buffer[query_offset] & HAS_SCROLL_ZONES_MASK;
+ sensor_info->has_individual_scroll_zones =
+ query_buffer[query_offset] &
+ HAS_INDIVIDUAL_SCROLL_ZONES_MASK;
+ sensor_info->has_multifinger_scroll =
+ query_buffer[query_offset] &
+ HAS_MULTIFINGER_SCROLL_MASK;
+ sensor_info->has_multifinger_scroll_edge_motion =
+ query_buffer[query_offset] &
+ HAS_MULTIFINGER_SCROLL_EDGE_MOTION_MASK;
+ sensor_info->has_multifinger_scroll_inertia =
+ query_buffer[query_offset] &
+ HAS_MULTIFINGER_SCROLL_INERTIA_MASK;
+ query_offset++;
+ }
+
+ if (instance_data->device_info->has_query_9) {
+ sensor_info->has_pen =
+ query_buffer[query_offset] & HAS_PEN_MASK;
+ sensor_info->has_proximity =
+ query_buffer[query_offset] & HAS_PROXIMITY_MASK;
+ sensor_info->has_palm_detect_sensitivity =
+ query_buffer[query_offset] &
+ HAS_PALM_DETECT_SENSITIVITY_MASK;
+ sensor_info->has_suppress_on_palm_detect =
+ query_buffer[query_offset] &
+ HAS_SUPPRESS_ON_PALM_DETECT_MASK;
+ query_offset++;
+ }
+
+ if (sensor_info->has_touch_shapes) {
+ sensor_info->number_of_touch_shapes =
+ (query_buffer[query_offset] &
+ NUMBER_OF_TOUCH_SHAPES_MASK) + 1;
+ query_offset++;
+ }
+
+ if (instance_data->device_info->has_query_11) {
+ sensor_info->has_Z_tuning =
+ query_buffer[query_offset] & HAS_Z_TUNING_MASK;
+ sensor_info->has_algorithm_selection =
+ query_buffer[query_offset] & HAS_ALGORITHM_SECTION_MASK;
+ query_offset++;
+ }
+
+ return 0;
+}
+
+/* Figure out just how much data we'll need to read. */
+static void compute_finger_data_size(struct rmi_function_info *rmifninfo,
+ struct rmi_F11_sensor_query *sensor_info)
+{
+ struct f11_instance_data *instance_data = rmifninfo->fndata;
+ unsigned int data_buffer_size = 0;
+
+ /* Finger state comes first in the data registers.
+ */
+ data_buffer_size = (sensor_info->number_of_fingers +
+ FINGER_STATES_PER_BYTE - 1) / FINGER_STATES_PER_BYTE;
+
+ /* Next comes absolute data.
+ */
+ if (sensor_info->has_absolute) {
+ instance_data->abs_data_offset = data_buffer_size;
+ switch (sensor_info->abs_data_size) {
+ case 0:
+ instance_data->abs_data_size = 5;
+ break;
+ default:
+ instance_data->abs_data_size =
+ DEFAULT_ABS_BYTES_PER_FINGER;
+ pr_warning("%s: Unrecognized abs data size %d ignored.",
+ __func__, sensor_info->abs_data_size);
+ }
+ data_buffer_size += sensor_info->number_of_fingers *
+ instance_data->abs_data_size;
+ }
+
+ /* Then comes the relative data. Once again, it's optional.
+ */
+ if (sensor_info->has_relative) {
+ instance_data->rel_data_offset = data_buffer_size;
+ data_buffer_size +=
+ sensor_info->number_of_fingers * REL_BYTES_PER_FINGER;
+ }
+
+ /* Gesture data is next, and it's very optional and very complicated.
+ */
+ if (sensor_info->has_gestures) {
+ instance_data->gesture_data_offset = data_buffer_size;
+ if (sensor_info->has_pinch ||
+ sensor_info->has_press ||
+ sensor_info->has_flick ||
+ sensor_info->has_early_tap ||
+ sensor_info->has_double_tap ||
+ sensor_info->has_tap ||
+ sensor_info->has_tap_and_hold) {
+ instance_data->data8_offset = data_buffer_size;
+ data_buffer_size++;
+ instance_data->data9_offset = data_buffer_size;
+ data_buffer_size++;
+ } else if (sensor_info->has_palm_detect ||
+ sensor_info->has_rotate ||
+ sensor_info->has_touch_shapes ||
+ sensor_info->has_scroll_zones ||
+ sensor_info->has_individual_scroll_zones ||
+ sensor_info->has_multifinger_scroll ||
+ sensor_info->has_multifinger_scroll_edge_motion
+ ||
+ sensor_info->has_multifinger_scroll_inertia) {
+ instance_data->data9_offset = data_buffer_size;
+ data_buffer_size++;
+ }
+ if (sensor_info->has_pinch || sensor_info->has_flick) {
+ instance_data->data10_offset = data_buffer_size;
+ data_buffer_size++;
+ }
+ if (sensor_info->has_rotate || sensor_info->has_flick) {
+ instance_data->data11_offset = data_buffer_size;
+ data_buffer_size += ROTATE_FLICK_DATA_BYTES;
+ }
+ if (sensor_info->has_touch_shapes) {
+ instance_data->data13_offset = data_buffer_size;
+ data_buffer_size +=
+ (sensor_info->number_of_touch_shapes +
+ TOUCH_SHAPE_BITS_PER_BYTE - 1) /
+ TOUCH_SHAPE_BITS_PER_BYTE;
+ }
+ if (sensor_info->has_scroll_zones) {
+ instance_data->data14_offset = data_buffer_size;
+ data_buffer_size += SCROLL_ZONE_DATA_BYTES;
+ }
+ if (sensor_info->has_individual_scroll_zones) {
+ instance_data->data16_offset = data_buffer_size;
+ data_buffer_size += SCROLL_ZONE_DATA_BYTES;
+ }
+ }
+
+ instance_data->finger_data_buffer_size = data_buffer_size;
+}
+
+/* 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. We can break it down into
+ * a few function calls, but some things (like computing finger data size)
+ * are just not amenable to further break down.
+ */
+static int read_query_registers(struct rmi_function_info *rmifninfo)
+{
+ int retval = 0;
+ struct f11_instance_data *instance_data = rmifninfo->fndata;
+ unsigned char query_address =
+ rmifninfo->function_descriptor.query_base_addr;
+
+ retval = read_device_query(rmifninfo);
+
+ if (retval)
+ return retval;
+
+ query_address = query_address + DEVICE_QUERY_SIZE;
+
+ retval = read_per_sensor_query(rmifninfo, instance_data->sensor_info,
+ query_address);
+
+ if (retval)
+ return retval;
+
+ compute_finger_data_size(rmifninfo, instance_data->sensor_info);
+
+ return 0;
+}
+
+static enum finger_state get_finger_state(unsigned char finger,
+ unsigned char *buffer)
+{
+ int finger_byte = finger / FINGER_STATES_PER_BYTE;
+ int finger_shift =
+ (finger % FINGER_STATES_PER_BYTE) * BITS_PER_FINGER_STATE;
+ return (buffer[finger_byte] >> finger_shift) & FINGER_STATE_MASK;
+}
+
+/*
+ * 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 = 0;
+ int finger;
+ struct rmi_function_device *function_device =
+ rmifninfo->function_device;
+ struct f11_instance_data *instance_data = rmifninfo->fndata;
+ int retval;
+
+ /* 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++) {
+ enum finger_state finger_status = get_finger_state(finger,
+ instance_data->finger_data_buffer);
+ 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));
+
+ if (instance_data->sensor_info->has_absolute)
+ handle_absolute_reports(rmifninfo);
+
+ if (instance_data->sensor_info->has_relative &&
+ instance_data->rel_report_enabled)
+ handle_relative_report(rmifninfo);
+
+ input_sync(function_device->input); /* sync after groups of events */
+
+}
+EXPORT_SYMBOL(FN_11_inthandler);
+
+static void handle_absolute_reports(struct rmi_function_info *rmifninfo)
+{
+ int finger;
+ int finger_down_count = 0;
+ struct rmi_function_device *function_device =
+ rmifninfo->function_device;
+ struct f11_instance_data *instance_data = rmifninfo->fndata;
+
+ for (finger = 0; finger < instance_data->sensor_info->number_of_fingers;
+ finger++) {
+ enum finger_state finger_status = get_finger_state(finger,
+ instance_data->finger_data_buffer);
+ int X = 0, Y = 0, Z = 0, Wy = 0, Wx = 0;
+
+ /* 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) {
+ int max_X = instance_data->control_registers->
+ sensor_max_X_pos;
+ int max_Y = instance_data->control_registers->
+ sensor_max_Y_pos;
+ int reg = instance_data->abs_data_offset +
+ (finger * instance_data->abs_data_size);
+
+ finger_down_count++;
+
+ X = ((instance_data->finger_data_buffer[reg +
+ X_HIGH_BITS_OFFSET] <<
+ XY_HIGH_BITS_SHIFT) & XY_HIGH_BITS_MASK)
+ | ((instance_data->finger_data_buffer[reg +
+ XY_LOW_BITS_OFFSET] >> X_LOW_BITS_SHIFT)
+ & XY_LOW_BITS_MASK);
+ Y = ((instance_data->finger_data_buffer[reg +
+ Y_HIGH_BITS_OFFSET] <<
+ XY_HIGH_BITS_SHIFT) & XY_HIGH_BITS_MASK)
+ | ((instance_data->finger_data_buffer[reg +
+ XY_LOW_BITS_OFFSET] >> Y_LOW_BITS_SHIFT)
+ & XY_LOW_BITS_MASK);
+ /* First thing to do is swap axes if needed. */
+ if (instance_data->swap_axes) {
+ int temp = X;
+ X = Y;
+ Y = temp;
+ max_X = instance_data->control_registers->
+ sensor_max_Y_pos;
+ max_Y = instance_data->control_registers->
+ sensor_max_X_pos;
+ }
+ if (instance_data->flip_X)
+ X = max(max_X - 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(max_Y - Y, 0);
+ Y = Y - instance_data->offset_Y;
+ Y = min(max(Y, instance_data->clip_Y_low),
+ instance_data->clip_Y_high);
+
+ Wx = (instance_data->finger_data_buffer[reg +
+ W_XY_OFFSET] >> W_Y_SHIFT) & W_XY_MASK;
+ Wy = (instance_data->finger_data_buffer[reg +
+ W_XY_OFFSET] >> W_Y_SHIFT) & W_XY_MASK;
+ if (instance_data->swap_axes) {
+ int temp = Wx;
+ Wx = Wy;
+ Wy = temp;
+ }
+
+ Z = instance_data->finger_data_buffer[reg + Z_OFFSET];
+#if POS_DEBUG
+ pr_info("Finger %d - X:%d, Y:%d, Z:%d, Wx:%d, Wy:%d\n",
+ finger, X, Y, Z, Wx, Wy);
+#endif
+
+ /* 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. */
+ }
+#if defined(CONFIG_SYNA_MULTI_TOUCH)
+ /* Report Multi-Touch events for each finger */
+#if defined(ABS_MT_PRESSURE)
+ /* Finger pressure; not supported in all kernel
+ * versions. */
+ input_report_abs(function_device->input,
+ ABS_MT_PRESSURE, Z);
+#endif
+ /* major axis of touch area ellipse */
+ input_report_abs(function_device->input,
+ ABS_MT_TOUCH_MAJOR, max(Wx, Wy));
+ /* minor axis of touch area ellipse */
+ input_report_abs(function_device->input,
+ ABS_MT_TOUCH_MINOR, min(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;
+
+#if defined(CONFIG_SYNA_MULTI_TOUCH)
+#if defined(ABS_MT_PRESSURE)
+ input_report_abs(function_device->input, ABS_MT_PRESSURE, 0);
+#endif
+ input_report_abs(function_device->input, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_abs(function_device->input, ABS_MT_TOUCH_MINOR, 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__);
+ }
+}
+
+#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 handle_relative_report(struct rmi_function_info *rmifninfo)
+{
+ struct f11_instance_data *instance_data = rmifninfo->fndata;
+ struct rmi_function_device *function_device =
+ rmifninfo->function_device;
+ signed char X, Y;
+ int reg = instance_data->rel_data_offset;
+
+
+ X = instance_data->finger_data_buffer[reg + REL_X_OFFSET];
+ Y = instance_data->finger_data_buffer[reg + REL_Y_OFFSET];
+ 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);
+
+#if defined(CONFIG_SYNA_MULTI_TOUCH)
+#if defined(ABS_MT_PRESSURE)
+ input_set_abs_params(function_device->input, ABS_MT_PRESSURE, 0, 255,
+ 0, 0);
+#endif
+ 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);
+ set_bit(BTN_TOUCH, function_device->input->keybit);
+
+
+ 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;
+}
--- /dev/null
+/**
+ *
+ * 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;
+ bool has_query_11;
+ 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;
+ bool has_adj_hyst;
+ bool has_dribble;
+ bool has_pinch;
+ bool has_flick;
+ bool has_tap;
+ bool has_tap_and_hold;
+ bool has_double_tap;
+ bool has_early_tap;
+ bool has_press;
+
+ bool has_palm_detect;
+ bool has_rotate;
+ bool has_touch_shapes;
+ bool has_scroll_zones;
+ bool has_individual_scroll_zones;
+ bool has_multifinger_scroll;
+ bool has_multifinger_scroll_edge_motion;
+ bool has_multifinger_scroll_inertia;
+
+ bool has_pen;
+ bool has_proximity;
+ bool has_palm_detect_sensitivity;
+ bool has_suppress_on_palm_detect;
+
+ bool has_Z_tuning;
+ bool has_algorithm_selection;
+
+ unsigned char number_of_touch_shapes;
+
+ 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
--- /dev/null
+/**
+ *
+ * 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/rmi_platformdata.h>
+
+#include "rmi.h"
+#include "rmi_drvr.h"
+#include "rmi_bus.h"
+#include "rmi_sensor.h"
+#include "rmi_function.h"
+#include "rmi_f19.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, 0666,
+ 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[instance_data->device_info->button_count];
+
+ /* Do validation on the button map data passed in. Store button
+ * mappings into a temp buffer and then verify button count and
+ * data prior to clearing out old button mappings and storing the
+ * new ones. */
+ for (i = 0; i < 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;
+ }
+
+ /* Clear the key bits for the old button map. */
+ for (i = 0; i < button_count; i++)
+ clear_bit(instance_data->button_map[i], fn->input->keybit);
+
+ /* Switch to the new map. */
+ memcpy(instance_data->button_map, temp_button_map,
+ instance_data->device_info->button_count);
+
+ /* Loop through the key map and set the key bit for the new mapping. */
+ for (i = 0; i < button_count; i++)
+ set_bit(instance_data->button_map[i], fn->input->keybit);
+
+err_ret:
+ return retval;
+}
--- /dev/null
+/**
+ *
+ * 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
--- /dev/null
+/**
+ *
+ * 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__,
+ rmifninfo->function_descriptor.query_base_addr);
+ 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->rfi->function_descriptor.data_base_addr,
+ data, ARRAY_SIZE(data));
+ if (error) {
+ dev_err(dev, "%s : Could not write bootloader id to 0x%x\n",
+ __func__, fn->rfi->function_descriptor.data_base_addr);
+ 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;
+ unsigned short baseaddr = fn->rfi->function_descriptor.data_base_addr;
+ 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, baseaddr + 3,
+ &instance_data->cmd, 1);
+ /* return one if succeeds */
+ if (error != 1) {
+ dev_err(dev, "%s: Could not write command 0x%02x "
+ "to 0x%04x\n", __func__, instance_data->cmd,
+ baseaddr + 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->rfi->function_descriptor.data_base_addr + pos,
+ (unsigned char *)buf, count);
+ if (error) {
+ dev_err(dev, "%s : Could not read data from 0x%llx\n",
+ __func__,
+ fn->rfi->function_descriptor.data_base_addr + 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;
+ unsigned short baseaddr = fn->rfi->function_descriptor.data_base_addr;
+
+ /* Write the data from buf to flash. The app layer will be
+ * blocked at writing to the sysfs file. When we return the
+ * count (or error if we fail) the app will resume. */
+
+ if (count != instance_data->blocksize) {
+ dev_err(dev,
+ "%s: Incorrect F34 block size %d. Expected size %d.\n",
+ __func__, count, instance_data->blocksize);
+ return -EINVAL;
+ }
+
+ /* 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, baseaddr,
+ (unsigned char *)&blocknum, 2);
+ /* return one if succeeds */
+ if (error != 1) {
+ dev_err(dev, "%s: Could not write block number to 0x%x\n",
+ __func__, baseaddr);
+ return error;
+ }
+
+ /* Write the data block - only if the count is non-zero */
+ if (count) {
+ error = rmi_write_multiple(fn->sensor, baseaddr + 2,
+ (unsigned char *)buf, count);
+ /* return one if succeeds */
+ if (error != 1) {
+ dev_err(dev, "%s: Could not write block data "
+ "to 0x%x\n", __func__, baseaddr + 2);
+ return error;
+ }
+ }
+
+ return count;
+}
--- /dev/null
+/**
+ *
+ * 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
--- /dev/null
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $54 support for direct
+ * access to low-level capacitance data.
+ *
+ * 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_f54.h"
+
+/* modified from F 34, must check for copy-paste nonsense */
+
+
+static ssize_t rmi_fn_54_reporttype_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_reporttype_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_cmd_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_cmd_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_data_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attributes,
+ char *buf, loff_t pos, size_t count);
+
+static ssize_t rmi_fn_54_numrxelectrodes_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_numtxelectrodes_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_control_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_control_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_fifoindexlo_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_fifoindexlo_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+static ssize_t rmi_fn_54_fifoindexhi_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_fn_54_fifoindexhi_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+/* Should probably change name here to something more appropriate */
+static struct device_attribute attrs[] = {
+ __ATTR(reporttype, 0666,
+ rmi_fn_54_reporttype_show, rmi_fn_54_reporttype_store),
+ __ATTR(cmd, 0666,
+ rmi_fn_54_cmd_show, rmi_fn_54_cmd_store),
+ __ATTR(status, 0444,
+ rmi_fn_54_status_show, rmi_store_error),
+ __ATTR(numrxelectrodes, 0444,
+ rmi_fn_54_numrxelectrodes_show, rmi_store_error),
+ __ATTR(numtxelectrodes, 0444,
+ rmi_fn_54_numtxelectrodes_show, rmi_store_error),
+ __ATTR(control, 0666,
+ rmi_fn_54_control_show, rmi_fn_54_control_store),
+ __ATTR(fifoindexlo, 0666,
+ rmi_fn_54_fifoindexlo_show, rmi_fn_54_fifoindexlo_store),
+ __ATTR(fifoindexhi, 0666,
+ rmi_fn_54_fifoindexhi_show, rmi_fn_54_fifoindexhi_store)
+};
+/* Same as above */
+struct bin_attribute dev_rep_data = {
+ .attr = {
+ .name = "repdata",
+ .mode = 0444},
+ .size = 0,
+ .read = rmi_fn_54_data_read,
+};
+
+
+int FN_54_init(struct rmi_function_device *function_device)
+{
+ int retval = 0;
+ int attr_count = 0;
+ unsigned char buf;
+ struct rmi_function_info *rmifninfo = function_device->rfi;
+ struct rmi_fn_54_data *instance_data;
+
+ pr_debug("%s: RMI4 function $54 init\n", __func__);
+
+ if (rmifninfo->fndata) {
+ /* detect routine should only ever be called once
+ * per rmifninfo. */
+ pr_err("%s: WTF?!? F54 instance data is already present!",
+ __func__);
+ return -EINVAL;
+ }
+
+ instance_data = kzalloc(sizeof(struct rmi_fn_54_data), GFP_KERNEL);
+ if (!instance_data) {
+ pr_err("%s: Error allocating memory for rmi_fn_54_data.\n",
+ __func__);
+ retval = -ENOMEM;
+ goto error_exit;
+ }
+ rmifninfo->fndata = instance_data;
+
+ /* get the Number of Receiver and Transmitter Electrodes. */
+ retval = rmi_read_multiple(rmifninfo->sensor,
+ rmifninfo->function_descriptor.query_base_addr,
+ &buf, 1);
+ if (retval) {
+ pr_err("%s : Could not read NumberOfReceiverElectrodes from 0x%04x\n",
+ __func__,
+ rmifninfo->function_descriptor.query_base_addr);
+ goto error_exit;
+ }
+ instance_data->numrxelectrodes = buf;
+
+ retval = rmi_read_multiple(rmifninfo->sensor,
+ rmifninfo->function_descriptor.query_base_addr + 1,
+ &buf, 1);
+ if (retval) {
+ pr_err("%s: Could not read NumberOfTransmitterElectrodes from 0x%04x\n",
+ __func__,
+ rmifninfo->function_descriptor.query_base_addr + 1);
+ goto error_exit;
+ }
+ instance_data->numtxelectrodes = buf;
+
+ __mutex_init(&instance_data->data_mutex, "data_mutex",
+ &instance_data->data_key);
+
+ /* 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_rep_data);
+ if (retval < 0) {
+ pr_err
+ ("%s: Failed to create sysfs file for fn 54 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_54_init);
+
+
+void FN_54_inthandler(struct rmi_function_info *rmifninfo,
+ unsigned int asserted_IRQs)
+{
+
+ struct rmi_fn_54_data *instance_data = rmifninfo->fndata;
+ int error = 0;
+ char *to_write;
+
+ /* TODO: do something to disable all other interupts : ? */
+ /* TODO: Need to do something for timeout? */
+
+ instance_data->status = 1; /* busy */
+
+ switch (instance_data->reporttype) {
+ case r8bit_image:
+ instance_data->reportsize = instance_data->numrxelectrodes *
+ instance_data->numtxelectrodes;
+ break;
+ case r16bit_image:
+ case autoscan:
+ instance_data->reportsize = 2 * instance_data->numrxelectrodes *
+ instance_data->numtxelectrodes;
+ break;
+ case trans2trans:
+ case trans2trans_short:
+ instance_data->reportsize = instance_data->numtxelectrodes *
+ instance_data->numtxelectrodes;
+ break;
+ case rec2rec:
+ instance_data->reportsize = instance_data->numrxelectrodes *
+ instance_data->numrxelectrodes;
+ break;
+ default:
+ instance_data->reportsize = 0;
+ pr_err("%s:Invalid report type. This should never happen.\n",
+ __func__);
+ }
+ /* We need to ensure the buffer is big enough.
+ * A Buffer size of 0 means that the buffer has not been allocated.
+ */
+ if (instance_data->bufsize < instance_data->reportsize) {
+ mutex_lock(&instance_data->data_mutex);
+ if (instance_data->bufsize > 0)
+ kfree(instance_data->report_data);
+
+ instance_data->report_data = kzalloc(instance_data->reportsize,
+ GFP_KERNEL);
+ if (!instance_data->report_data) {
+ pr_err("%s: Error allocating memory for report data.\n",
+ __func__);
+ instance_data->status = ENOMEM;
+ instance_data->bufsize = 0;
+ mutex_unlock(&instance_data->data_mutex);
+ return;
+ }
+ instance_data->bufsize = instance_data->reportsize;
+ mutex_unlock(&instance_data->data_mutex);
+ }
+ if (!instance_data->report_data) {
+ pr_err("%s: Error allocating memory for f54 report_data.\n",
+ __func__);
+ instance_data->status = ENOMEM;
+ return;
+ }
+ pr_err("%s: Stuff is actually running.\n\n Size : %d\n",
+ __func__, instance_data->reportsize);
+ /* Loop requesting data until we reach the end. */
+
+ to_write = instance_data->report_data;
+
+
+ error = rmi_read_multiple(rmifninfo->sensor,
+ rmifninfo->function_descriptor.data_base_addr + 3,
+ instance_data->report_data,
+ instance_data->reportsize);
+ if (error)
+ pr_err("%s: ERROR F54 data read failed. "
+ "Code: %d.\n", __func__, error);
+
+ /*for (i = 0; i < instance_data->reportsize; i++) {
+ // attempt to write FIFOData to the next space in the data file.
+ error = rmi_read_multiple(rmifninfo->sensor,
+ rmifninfo->function_descriptor.data_base_addr + 3,
+ to_write, 1);
+ *to_write = 'a';
+ pr_info("%d: %c",i, *to_write);
+ if ( error ) {
+ pr_err("%s: Error while reading data: Error %d\n",
+ __func__, error);
+ instance_data->status = error;
+ // Do some sort of error handling?
+ }
+ to_write++;
+ }*/
+ if (!error)
+ instance_data->status = 0; /* Success */
+ else
+ instance_data->status = error;
+}
+EXPORT_SYMBOL(FN_54_inthandler);
+
+/* This is a stub for now, and will be fleshed out or removed as the
+ * implementation matures.
+ */
+int FN_54_config(struct rmi_function_info *rmifninfo)
+{
+ pr_debug("%s: RMI4 function $54 config\n", __func__);
+ return 0;
+}
+EXPORT_SYMBOL(FN_54_config);
+
+int FN_54_detect(struct rmi_function_info *rmifninfo)
+{
+ int retval = 0;
+
+ pr_debug("%s: RMI4 function $54 detect\n", __func__);
+ if (rmifninfo->sensor == NULL) {
+ pr_err("%s: NULL sensor passed in!", __func__);
+ return -EINVAL;
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL(FN_54_detect);
+
+/* SYSFS file show/store functions */
+static ssize_t rmi_fn_54_reporttype_show(struct device *dev,
+ struct device_attribute *attr, char *buf) {
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->reporttype);
+}
+
+static ssize_t rmi_fn_54_reporttype_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count) {
+ int error, result;
+ unsigned long val;
+ unsigned char data;
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_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->reporttype = (enum Report)val;
+ data = (char)val;
+ /* Write the Report Type back to the first Block
+ * Data registers (F54_AD_Data0). */
+ result = rmi_write_multiple(fn->sensor,
+ fn->rfi->function_descriptor.data_base_addr, &data, 1);
+ if (result != count) {
+ if (result < 0) {
+ dev_err(dev, "%s : Could not write report type "
+ "to 0x%x\n", __func__,
+ fn->rfi->function_descriptor.data_base_addr);
+ } else {
+ dev_err(dev, "%s : Unexpected number of lines written "
+ "to 0x%x\n", __func__,
+ fn->rfi->function_descriptor.data_base_addr);
+ dev_err(dev, "Wrote: %d\tExpected:%d\n", result, count);
+ }
+ }
+ return result;
+}
+
+static ssize_t rmi_fn_54_cmd_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->cmd);
+}
+
+static ssize_t rmi_fn_54_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_54_data *instance_data = fn->rfi->fndata;
+ u16 baseaddr = fn->rfi->function_descriptor.command_base_addr;
+ unsigned long val;
+ int error, result;
+
+ /* need to convert the string data to an actual value */
+ error = strict_strtoul(buf, 10, &val);
+ if (error)
+ return error;
+
+ instance_data->cmd = (unsigned char)val;
+
+ /* Validate command value and (if necessary) write it to the command
+ * register.
+ */
+ switch (instance_data->cmd) {
+ case GET_REPORT:
+ /* This starts the report getting process. We calculate the
+ * expcected file size based on the report type, number of
+ * transmitters and receivers, and eventually the fifoindexlo
+ * and fifoindexhi. Currently, the firmware assumes those are
+ * 0 when it gets reports, and I'm not sure exactly how they're
+ * going to eventually effect report sizes, so they're ignored
+ * for now.
+ */
+ switch (instance_data->reporttype) {
+ case r8bit_image:
+ case r16bit_image:
+ case autoscan:
+ case trans2trans:
+ case trans2trans_short:
+ case rec2rec:
+ break;
+ case trans_open:
+ case rec_open:
+ case high_resistance:
+ dev_err(dev, "%s : Report type unimplemented\n",
+ __func__);
+ return -EINVAL;
+ break;
+ default:
+ dev_err(dev, "%s : Report type invalid\n", __func__);
+ return -EINVAL;
+ }
+ case FORCE_CAL:
+ /* Write the command to the command register */
+ result = rmi_write_multiple(fn->sensor, baseaddr,
+ &instance_data->cmd, 1);
+ if (result != count) {
+ if (result < 0) {
+ dev_err(dev, "%s : Could not write command "
+ "to 0x%x\n", __func__, baseaddr);
+ } else {
+ dev_err(dev, "%s : Unexpected number of lines "
+ "written to 0x%x\n",
+ __func__, baseaddr);
+ dev_err(dev, "Wrote: %d\tExpected:%d\n",
+ result, count);
+ }
+ }
+ break;
+ default:
+ dev_dbg(dev, "%s: RMI4 function $54 - "
+ "unknown command 0x%02lx.\n", __func__, val);
+ count = -EINVAL;
+ break;
+ }
+
+ return count;
+}
+
+static ssize_t rmi_fn_54_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->status);
+}
+
+static ssize_t rmi_fn_54_numrxelectrodes_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->numrxelectrodes);
+}
+
+static ssize_t rmi_fn_54_numtxelectrodes_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->numtxelectrodes);
+}
+
+static ssize_t rmi_fn_54_control_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ instance_data->no_auto_cal ? 1 : 0);
+}
+
+static ssize_t rmi_fn_54_control_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int error, result;
+ unsigned long val;
+ unsigned char data;
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+ u16 ctrlbase = fn->rfi->function_descriptor.control_base_addr;
+
+ /* need to convert the string data to an actual value */
+ error = strict_strtoul(buf, 10, &val);
+
+ if (error)
+ return error;
+
+ /* Write the control back to the control register (F54_AD_Ctrl0)
+ * Ignores everything but bit 0 */
+ data = (unsigned char)(val & 0x01); /* bit mask for lowest bit */
+ instance_data->no_auto_cal = (data == (unsigned char)0x01);
+ result = rmi_write_multiple(fn->sensor, ctrlbase, &data, 1);
+ if (result != count) {
+ if (result < 0) {
+ dev_err(dev, "%s : Could not write control to 0x%x\n",
+ __func__, ctrlbase);
+ } else {
+ dev_err(dev, "%s : Unexpected number of lines written "
+ "to 0x%x\n", __func__, ctrlbase);
+ dev_err(dev, "Wrote: %d\tExpected:%d\n", result, count);
+ }
+ }
+ return result;
+}
+
+static ssize_t rmi_fn_54_fifoindexlo_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ /* Might want to read from device */
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->fifoindexlo);
+}
+
+static ssize_t rmi_fn_54_fifoindexlo_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int error, result;
+ unsigned long val;
+ unsigned char data;
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+ u16 database = fn->rfi->function_descriptor.data_base_addr;
+
+ /* need to convert the string data to an actual value */
+ error = strict_strtoul(buf, 10, &val);
+
+ if (error)
+ return error;
+
+ instance_data->fifoindexlo = (unsigned char)val;
+
+ /* Write the FIFOIndexLo back to the
+ * Data register (F54_AD_Data1). */
+ /* hstoba(data, (unsigned short)val); Don't need this */
+ data = (unsigned char)val;
+ result = rmi_write_multiple(fn->sensor, database + 1, &data, 1);
+ if (result != count) {
+ if (result < 0) {
+ dev_err(dev, "%s : Could not write FIFOIndexLo "
+ "to 0x%x\n", __func__, database + 1);
+ } else {
+ dev_err(dev, "%s : Unexpected number of lines written "
+ "to 0x%x\n", __func__, database + 1);
+ dev_err(dev, "Wrote: %d\tExpected:%d\n", result, count);
+ }
+ }
+ return result;
+}
+
+static ssize_t rmi_fn_54_fifoindexhi_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+
+ /* Might want to read from device */
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->fifoindexhi);
+}
+
+static ssize_t rmi_fn_54_fifoindexhi_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int error, result;
+ unsigned long val;
+ unsigned char data;
+ struct rmi_function_device *fn = dev_get_drvdata(dev);
+ struct rmi_fn_54_data *instance_data = fn->rfi->fndata;
+ u16 database = fn->rfi->function_descriptor.data_base_addr;
+
+ /* need to convert the string data to an actual value */
+ error = strict_strtoul(buf, 10, &val);
+
+ if (error)
+ return error; /* Should this be -error? */
+ instance_data->fifoindexhi = (unsigned char)val;
+
+ /* Write the FIFOIndexLo back to the
+ * Data register (F54_AD_Data2). */
+ /* hstoba(data, (unsigned short)val); Don't need this */
+ data = (unsigned char)val;
+ result =
+ rmi_write_multiple(fn->sensor, database + 2, &data, 1);
+ if (result != count) {
+ if (result < 0) {
+ dev_err(dev, "%s : Could not write FIFOIndexHi to "
+ "0x%x\n", __func__, database + 2);
+ } else {
+ dev_err(dev, "%s : Unexpected number of lines written "
+ " to 0x%x\n", __func__, database + 2);
+ dev_err(dev, "Wrote: %d\tExpected:%d\n", result, count);
+ }
+ }
+ return result;
+}
+
+/* Provide access to last report */
+
+static ssize_t rmi_fn_54_data_read(struct file *filp, 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_54_data *instance_data = fn->rfi->fndata;
+
+ dev_dbg(dev, "%s: Trying to read data. count: %d pos: %ld\n",
+ __func__, count, (long)pos);
+ /* May run into issues here is a new report type is set before reading
+ * the old data. MAy need to keep track of 2. */
+ if (count < instance_data->reportsize) {
+ dev_err(dev,
+ "%s: Incorrect F54 report size %d. Expected size %d.\n",
+ __func__, count, instance_data->reportsize);
+ return -EINVAL;
+ }
+
+ /* Copy data from instance_data to buffer */
+ mutex_lock(&instance_data->data_mutex);
+ memcpy(buf, instance_data->report_data, instance_data->reportsize);
+ mutex_unlock(&instance_data->data_mutex);
+ dev_info(dev, "%s: Presumably successful.", __func__);
+
+ return instance_data->reportsize;
+}
--- /dev/null
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) Function $54 header.
+ * Copyright (c) 2007 - 2011, Synaptics Incorporated
+ *
+ * TODO: Description here
+ *
+ *
+ */
+/*
+ * 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_F54_H)
+#define _RMI_F54_H
+
+/* define fn $54 commands */
+#define GET_REPORT 1
+#define FORCE_CAL 2
+
+/* define report types */
+enum Report {
+ /* The numbering should follow automatically, here for clarity */
+ reserved = 0,
+ r8bit_image = 1,
+ r16bit_image = 2,
+ autoscan = 3,
+ trans2trans = 4,
+ trans2trans_short = 5,
+ trans_open = 6,
+ rec2rec = 7,
+ rec_open = 8,
+ high_resistance = 9
+};
+
+/* data specific to fn $54 that needs to be kept around */
+struct rmi_fn_54_data {
+ unsigned char cmd;
+ enum Report reporttype;
+ unsigned char fifoindexlo;
+ unsigned char fifoindexhi;
+ unsigned char numrxelectrodes;
+ unsigned char numtxelectrodes;
+ unsigned char status;
+ bool no_auto_cal;
+ /* May need to do something to make sure this reflects what is
+ * currently in data. */
+ unsigned int reportsize;
+ unsigned char *report_data;
+ unsigned int bufsize;
+ struct mutex data_mutex;
+ struct lock_class_key data_key;
+};
+
+
+
+void FN_54_inthandler(struct rmi_function_info *rmifninfo,
+ unsigned int asserted_IRQs);
+int FN_54_config(struct rmi_function_info *rmifninfo);
+int FN_54_init(struct rmi_function_device *function_device);
+int FN_54_detect(struct rmi_function_info *rmifninfo);
+#endif
--- /dev/null
+/**
+ * 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"
+#include "rmi_f54.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 $1a - buttons */
+ {
+ .function_number = 0x1a,
+ .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},
+ /* Fn $54 - diagnostics. */
+ {
+ .function_number = RMI_F54_INDEX,
+ .inthandler = FN_54_inthandler,
+ .config = FN_54_config,
+ .init = FN_54_init,
+ .detect = FN_54_detect,
+ .attention = NULL,
+ .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");
--- /dev/null
+/**
+ *
+ * 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, 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.
+ * This version contains the full addresses, needed in the case of multiple
+ * pages with PDT's on them.
+ */
+struct rmi_function_descriptor_short {
+ unsigned short query_base_addr;
+ unsigned short command_base_addr;
+ unsigned short control_base_addr;
+ unsigned short data_base_addr;
+ unsigned char interrupt_source_count;
+ unsigned char function_number;
+};
+/* 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. It includes the page in the addresses.
+ */
+ struct rmi_function_descriptor_short 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 {
+ /*TODO: function driver should be removed if/when we don't need it.*/
+ /*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
--- /dev/null
+/**
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+/* #define DEBUG 1 */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/rmi_i2c.h>
+#include "rmi_drvr.h"
+#include "rmi_sensor.h"
+
+#define DRIVER_NAME "rmi4_ts"
+#define DEVICE_NAME "rmi4_ts"
+
+#define COMM_DEBUG 0 /* Set to 1 to dump transfers. */
+#define PAGE_SELECT_REGISTER 0xFF
+
+static const struct i2c_device_id rmi_i2c_id_table[] = {
+ {"synaptics_3202", 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;
+ int attn_polarity;
+ int attn_gpio;
+ int enabled;
+ 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;
+};
+
+static irqreturn_t i2c_attn_isr(int irq, void *info);
+
+/*
+ * 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 *instance_data, unsigned int page)
+{
+ char txbuf[2] = {PAGE_SELECT_REGISTER, page};
+ int retval;
+
+#if COMM_DEBUG
+ dev_info(&instance_data->i2cclient->dev,
+ "%s: Set page to 0x%02X.", __func__, page);
+#endif
+
+ retval = i2c_master_send(instance_data->i2cclient,
+ txbuf, ARRAY_SIZE(txbuf));
+ if (retval != ARRAY_SIZE(txbuf)) {
+ dev_err(&instance_data->i2cclient->dev,
+ "%s: Set page failed: %d.", __func__, retval);
+ } else {
+ retval = 0;
+ instance_data->page = page;
+ }
+ return retval;
+}
+#else
+int rmi_set_page(struct instance_data *instance_data, 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 *instance_data =
+ container_of(physdrvr, struct instance_data, rmiphysdrvr);
+ char txbuf[1] = {address & 0xff};
+ int retval = 0;
+ int retry_count = 0;
+
+#if COMM_DEBUG
+ dev_info(&instance_data->i2cclient->dev, "%s: Read %d bytes at 0x%04x",
+ __func__, size, address);
+#endif
+
+ /* Can't have anyone else changing the page behind our backs */
+ mutex_lock(&instance_data->page_mutex);
+
+ if (((address >> 8) & 0xff) != instance_data->page) {
+ /* Switch pages */
+ retval = rmi_set_page(instance_data, ((address >> 8) & 0xff));
+ if (retval)
+ goto exit;
+ }
+
+retry:
+ physdrvr->tx_count++;
+ physdrvr->tx_bytes += ARRAY_SIZE(txbuf);
+ retval = i2c_master_send(instance_data->i2cclient,
+ txbuf, ARRAY_SIZE(txbuf));
+ if (retval != 1) {
+ dev_err(&instance_data->i2cclient->dev, "%s: Write fail: %d\n",
+ __func__, retval);
+ physdrvr->tx_errors++;
+ goto exit;
+ }
+
+ physdrvr->rx_count++;
+ physdrvr->rx_bytes += size;
+ retval = i2c_master_recv(instance_data->i2cclient, valp, size);
+
+ if (retval != size) {
+ physdrvr->rx_errors++;
+ if (++retry_count == 5) {
+ dev_err(&instance_data->i2cclient->dev,
+ "%s: Read of 0x%04x size %d fail: %d\n",
+ __func__, address, size, retval);
+ } else {
+ mdelay(10);
+ rmi_set_page(instance_data, ((address >> 8) & 0xff));
+ goto retry;
+ }
+ } else {
+ retval = 0;
+ }
+
+exit:
+ mutex_unlock(&instance_data->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 *instance_data =
+ 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(&instance_data->page_mutex);
+
+ if (((address >> 8) & 0xff) != instance_data->page) {
+ /* Switch pages */
+ retval = rmi_set_page(instance_data, ((address >> 8) & 0xff));
+ if (retval) {
+ /* error occurs we change return value to -1 */
+ retval = -1;
+ goto exit;
+ }
+ }
+
+ txbuf[0] = address & 0xff; /* put the address in the first byte */
+ retval = i2c_master_send(instance_data->i2cclient,
+ txbuf, ARRAY_SIZE(txbuf));
+ physdrvr->tx_count++;
+ physdrvr->tx_bytes += ARRAY_SIZE(txbuf);
+
+ /* TODO: Add in retry on writes only in certain error return values */
+ if (retval != ARRAY_SIZE(txbuf)) {
+ dev_err(&instance_data->i2cclient->dev, "%s: Write fail: %d\n",
+ __func__, retval);
+ physdrvr->tx_errors++;
+ /* error occurs we change return value to -2 */
+ retval = -2;
+ goto exit;
+ } else
+ retval = 1; /* return one if succeeds */
+
+exit:
+ mutex_unlock(&instance_data->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 *instance_data = info;
+
+ disable_irq_nosync(instance_data->irq);
+ instance_data->rmiphysdrvr.attn_count++;
+
+ if (instance_data->rmiphysdrvr.attention &&
+ (gpio_get_value(instance_data->attn_gpio) ==
+ instance_data->attn_polarity)) {
+ instance_data->rmiphysdrvr.attention(
+ &instance_data->rmiphysdrvr);
+ } else {
+ enable_irq(instance_data->irq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static int
+acquire_attn_irq(struct instance_data *instance_data)
+{
+ int retval;
+
+ unsigned long irq_type = IRQ_TYPE_EDGE_FALLING;
+ retval = request_irq(instance_data->irq, i2c_attn_isr,
+ irq_type, "rmi_i2c", instance_data);
+ if (retval)
+ return retval;
+
+ dev_dbg(&instance_data->rmiphysdrvr.sensor->sensor_device->dev,
+ "got ATTN irq.\n");
+
+ /*
+ * For some reason if we setup as level trigger, and execute
+ * 'instance_data->rmiphysdrvr.atten',
+ * there will be no more IRQ triggered.
+ * On the contrary, if we setup as edge trigger, we have to execute
+ * 'instance_data->rmiphysdrvr.atten'.
+ * Or, we won't receive any IRQ.
+ *
+ */
+ if ((irq_type & IRQ_TYPE_EDGE_BOTH) != 0)
+ if (instance_data->attn_gpio &&
+ gpio_get_value(instance_data->attn_gpio) ==
+ instance_data->attn_polarity &&
+ instance_data->rmiphysdrvr.attention) {
+
+ disable_irq(instance_data->irq);
+ instance_data->rmiphysdrvr.attention(
+ &instance_data->rmiphysdrvr);
+ }
+
+ return retval;
+}
+
+/* Specify the routine that will be called when attention is asserted.
+ */
+static void set_attn_handler (struct rmi_phys_driver *physdrvr,
+ void (*attention) (struct rmi_phys_driver *physdrvr))
+{
+ struct instance_data *instance_data =
+ container_of(physdrvr, struct instance_data, rmiphysdrvr);
+
+ physdrvr->attention = attention;
+ if (instance_data->attn_gpio &&
+ gpio_get_value(instance_data->attn_gpio) ==
+ instance_data->attn_polarity &&
+ instance_data->rmiphysdrvr.attention) {
+ disable_irq(instance_data->irq);
+ instance_data->rmiphysdrvr.attention(
+ &instance_data->rmiphysdrvr);
+ }
+}
+
+
+static void release_attn_irq(struct rmi_phys_driver *physdrvr)
+{
+ struct instance_data *instance_data =
+ container_of(physdrvr, struct instance_data, rmiphysdrvr);
+
+ dev_info(&physdrvr->sensor->sensor_device->dev,
+ "Releasing ATTN irq.\n");
+ disable_irq(instance_data->irq);
+ free_irq(instance_data->irq, instance_data);
+}
+
+
+static int
+enable_device(struct rmi_phys_driver *physdrvr)
+{
+ int retval = 0;
+ struct instance_data *instance_data =
+ container_of(physdrvr, struct instance_data, rmiphysdrvr);
+
+ if (instance_data->enabled)
+ return 0;
+
+ retval = acquire_attn_irq(instance_data);
+ if (retval)
+ goto error_exit;
+ instance_data->enabled = true;
+ dev_dbg(&physdrvr->sensor->sensor_device->dev,
+ "Physical device enabled.\n");
+ return 0;
+
+error_exit:
+ dev_err(&physdrvr->sensor->sensor_device->dev,
+ "Failed to enable physical device. Code=%d.\n", retval);
+ return retval;
+}
+
+
+static void
+disable_device(struct rmi_phys_driver *physdrvr)
+{
+ struct instance_data *instance_data =
+ container_of(physdrvr, struct instance_data, rmiphysdrvr);
+
+ if (!instance_data->enabled)
+ return;
+
+ release_attn_irq(physdrvr);
+ dev_dbg(&physdrvr->sensor->sensor_device->dev,
+ "Physical device disabled.\n");
+ instance_data->enabled = false;
+}
+
+/* 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 *instance_data;
+ 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 */
+ instance_data = kzalloc(sizeof(*instance_data), GFP_KERNEL);
+ if (!instance_data) {
+ dev_err(&client->dev,
+ "%s: Failed to allocate instance_data.\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ __mutex_init(&instance_data->page_mutex, "page_mutex",
+ &instance_data->page_key);
+ instance_data->rmiphysdrvr.name = RMI4_I2C_DRIVER_NAME;
+ instance_data->rmiphysdrvr.write = rmi_i2c_write;
+ instance_data->rmiphysdrvr.read = rmi_i2c_read;
+ instance_data->rmiphysdrvr.write_multiple = rmi_i2c_write_multiple;
+ instance_data->rmiphysdrvr.read_multiple = rmi_i2c_read_multiple;
+ instance_data->rmiphysdrvr.set_attn_handler = set_attn_handler;
+ instance_data->rmiphysdrvr.enable_device = enable_device;
+ instance_data->rmiphysdrvr.disable_device = disable_device;
+ instance_data->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 */
+ instance_data->rmiphysdrvr.polling_required = true;
+ instance_data->rmiphysdrvr.proto_name = "i2c";
+
+ instance_data->page = 0xffff; /* Force a set page the first time */
+ instance_data->enabled = true; /* We plan to come up enabled. */
+
+ /* 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.
+ */
+ dev_dbg(&client->dev, "%s: sensor addr: 0x%02x irq: %d\n",
+ __func__, platformdata->i2c_address,
+ sensordata->attn_gpio_number ?
+ gpio_to_irq(sensordata->attn_gpio_number) : -1);
+ 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;
+ }
+
+ instance_data->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,
+ instance_data->instance_no);
+
+ retval = gpio_request(sensordata->attn_gpio_number, "rmi");
+ if (retval < 0) {
+ dev_err(&client->dev, "%s: Unable to request GPIO\n", __func__);
+ goto error_exit;
+ }
+ retval = gpio_direction_input(sensordata->attn_gpio_number);
+ if (retval < 0) {
+ dev_err(&client->dev, "%s: Unable to set GPIO direction\n",
+ __func__);
+ goto error_exit;
+ }
+
+ retval = gpio_request(sensordata->rst_gpio_number, "rmi");
+ if (retval < 0) {
+ dev_err(&client->dev, "%s: Unable to request RESET GPIO\n",
+ __func__);
+ goto error_exit;
+ }
+ retval = gpio_direction_output(sensordata->rst_gpio_number, 1);
+ if (retval < 0) {
+ dev_err(&client->dev, "%s: Unable to set RESET GPIO "
+ "direction\n", __func__);
+ goto error_exit;
+ }
+ gpio_set_value(sensordata->rst_gpio_number, 1);
+
+ if (platformdata->delay_ms > 0)
+ mdelay(platformdata->delay_ms);
+
+
+ /* Determine if we need to poll (inefficient) or use interrupts.
+ */
+ if (sensordata->attn_gpio_number) {
+ instance_data->irq = gpio_to_irq(sensordata->attn_gpio_number);
+ instance_data->attn_polarity = sensordata->attn_polarity;
+ instance_data->attn_gpio = sensordata->attn_gpio_number;
+ instance_data->rmiphysdrvr.polling_required = false;
+ instance_data->rmiphysdrvr.irq = instance_data->irq;
+
+ } else {
+ instance_data->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, instance_data);
+
+ /* Copy i2c_client pointer into instance_data's i2c_client pointer for
+ later use in rmi4_read, rmi4_write, etc. */
+ instance_data->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(&instance_data->rmiphysdrvr,
+ platformdata->sensordata);
+ if (retval) {
+ dev_err(&client->dev,
+ "%s: Failed to register %s sensor drivers\n", __func__,
+ instance_data->rmiphysdrvr.name);
+ goto error_exit;
+ }
+
+ if (instance_data->rmiphysdrvr.polling_required == false) {
+ retval = acquire_attn_irq(instance_data);
+ if (retval) {
+ dev_warn(&client->dev,
+ "Failed to obtain IRQ %d. Result: %d.",
+ instance_data->irq, retval);
+ dev_info(&client->dev, "%s: Reverting to polling.\n",
+ __func__);
+ instance_data->rmiphysdrvr.polling_required = true;
+ /* TODO: Need to revert back to polling - create and
+ * start timer. */
+ retval = 0;
+ }
+
+ /* export GPIO for attention handling */
+
+#if defined(CONFIG_SYNA_RMI_DEV)
+ retval = gpio_export(instance_data->attn_gpio, false);
+ if (retval) {
+ dev_warn(&client->dev, "%s: WARNING: Failed to "
+ "export ATTN gpio!.", __func__);
+ retval = 0;
+ } else {
+ retval = gpio_export_link(
+ &instance_data->rmiphysdrvr.sensor->
+ sensor_device->dev, "attn",
+ instance_data->attn_gpio);
+ if (retval) {
+ dev_warn(
+ &instance_data->rmiphysdrvr.sensor->
+ sensor_device->dev, "%s: WARNING: "
+ "Failed to symlink ATTN gpio!.",
+ __func__);
+ retval = 0;
+ } else {
+ dev_info(&instance_data->
+ rmiphysdrvr.sensor->sensor_device->dev,
+ "%s: Exported GPIO %d.",
+ __func__, instance_data->attn_gpio);
+ }
+ }
+#endif /* CONFIG_SYNA_RMI_DEV */
+ }
+
+ dev_dbg(&client->dev, "%s: Successfully registered %s sensor driver.\n",
+ __func__, instance_data->rmiphysdrvr.name);
+
+ return retval;
+
+error_exit:
+ kfree(instance_data);
+ /* return error for clean-up*/
+ return retval;
+}
+
+static int rmi_i2c_remove(struct i2c_client *client)
+{
+ struct instance_data *instance_data = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "%s: Unregistering phys driver %s\n", __func__,
+ instance_data->rmiphysdrvr.name);
+
+ rmi_unregister_sensors(&instance_data->rmiphysdrvr);
+
+ dev_dbg(&client->dev, "%s: Unregistered phys driver %s\n",
+ __func__, instance_data->rmiphysdrvr.name);
+
+ /* only free irq if we have an irq - otherwise the instance_data
+ will be 0 for that field */
+ if (instance_data->irq)
+ free_irq(instance_data->irq, instance_data);
+
+ kfree(instance_data);
+ 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");
--- /dev/null
+/**
+ * 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;
+ bool enabled;
+};
+
+#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_OFFSET 0x00E9
+#define PDT_END_SCAN_OFFSET 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 ssize_t rmi_sensor_enabled_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmi_sensor_enabled_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+static ssize_t rmi_sensor_phy_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+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 */
+ __ATTR(enabled, 0666,
+ rmi_sensor_enabled_show, rmi_sensor_enabled_store), /* RW attr */
+ __ATTR(phy, 0444,
+ rmi_sensor_phy_show, rmi_store_error) /* RO 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;
+ struct rmi_sensor_device *sensor_device = sensor->sensor_device;
+ struct sensor_instance_data *instance_data;
+
+ /* we could read while sensor_device is not ready */
+ if (sensor_device) {
+ instance_data = sensor_device->sensordata;
+ /* we could read while instance_data is not ready */
+ if (instance_data)
+ if (!instance_data->enabled)
+ return -ENODEV;
+ }
+
+ 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;
+ struct rmi_sensor_device *sensor_device = sensor->sensor_device;
+ struct sensor_instance_data *instance_data;
+
+ /* we could write while sensor_device is not ready */
+ if (sensor_device) {
+ instance_data = sensor_device->sensordata;
+ /* we could write while instance_data is not ready */
+ if (instance_data)
+ if (!instance_data->enabled)
+ return -ENODEV;
+ }
+
+ 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;
+ struct rmi_sensor_device *sensor_device = sensor->sensor_device;
+
+ /* we could read while sensor_device is not ready */
+ if (sensor_device) {
+ struct sensor_instance_data *instance_data =
+ sensor_device->sensordata;
+ /* we could read while instance_data is not ready */
+ if (instance_data)
+ if (!instance_data->enabled)
+ return -ENODEV;
+ }
+ 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;
+ struct rmi_sensor_device *sensor_device = sensor->sensor_device;
+ struct sensor_instance_data *instance_data;
+
+ /* we could write while sensor_device is not ready */
+ if (sensor_device) {
+ instance_data = sensor_device->sensordata;
+ /* we could write while instance_data is not ready */
+ if (instance_data)
+ if (!instance_data->enabled)
+ return -ENODEV;
+ }
+ 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, ®_contents);
+ if (retval) {
+ pr_debug("%s: Read at 0x%04x failed, code: %d.\n",
+ __func__, address, retval);
+ return retval;
+ }
+ reg_contents = reg_contents | bits;
+ retval = rmi_write(sensor, address, reg_contents);
+ if (retval == 1)
+ return 0;
+ else if (retval == 0) {
+ pr_debug("%s: Write at 0x%04x failed.\n",
+ __func__, address);
+ 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, ®_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, ®_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
+ && 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)
+{
+ /* All we have to do is schedule work. */
+ schedule_work(&(physdrvr->sensor->work));
+}
+
+static void disable_sensor(struct rmi_sensor_driver *sensor)
+{
+ struct rmi_phys_driver *rpd = sensor->rpd;
+ struct sensor_instance_data *instance_data =
+ sensor->sensor_device->sensordata;
+
+ rpd->disable_device(rpd);
+ instance_data->enabled = false;
+}
+
+static int enable_sensor(struct rmi_sensor_driver *sensor)
+{
+ struct rmi_phys_driver *rpd = sensor->rpd;
+ struct sensor_instance_data *instance_data =
+ sensor->sensor_device->sensordata;
+ int retval = 0;
+
+ retval = rpd->enable_device(rpd);
+ /* non-zero means error occurred */
+ if (retval)
+ return retval;
+ instance_data->enabled = true;
+
+ return 0;
+}
+
+/* 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);
+ }
+
+ instance_data->enabled = true;
+ return;
+
+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
+
+
+#define RMI4_MAX_PAGE 0xFF
+#define RMI4_PAGE_SIZE 0x100
+
+/*
+ * 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 page;
+ bool done; /* Indicates the last page we checked for PDT's had none */
+ int interrupt_offset;
+ unsigned char interrupt_count = 0;
+ struct rmi_function_descriptor rmi_fd;
+ struct rmi_function_ops *fops;
+ 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 (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
+ int page_start = RMI4_PAGE_SIZE * page;
+ int pdt_start = page_start + PDT_START_SCAN_OFFSET;
+ int pdt_end = page_start + PDT_END_SCAN_OFFSET;
+ done = true; /* Assume we are done until we read a
+ valid function */
+
+ for (i = pdt_start; i >= pdt_end; i -= PDT_ENTRY_SIZE) {
+ dev_dbg(dev, "%s: Reading page descriptor at 0x%04x.\n",
+ __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;
+ } else {
+ /* There must be at least one valid function on
+ * a page for this code to run. We must check
+ * the next page.
+ */
+ done = false;
+ }
+
+ 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;
+ /* Here we add in the current page start address to our
+ * addressess. According to current RMI specification,
+ * all PDT entries are located on the same page as
+ * their corresponding function. This is because we
+ * don't have the room to store page info in the table,
+ * but can infer it off of the current page.
+ */
+
+ function_info->function_descriptor.query_base_addr =
+ rmi_fd.query_base_addr + page_start;
+ function_info->function_descriptor.command_base_addr =
+ rmi_fd.command_base_addr + page_start;
+ function_info->function_descriptor.control_base_addr =
+ rmi_fd.control_base_addr + page_start;
+ function_info->function_descriptor.data_base_addr =
+ rmi_fd.data_base_addr + page_start;
+
+ function_info->function_descriptor.function_number =
+ rmi_fd.function_number;
+ 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);
+ fops = rmi_find_function(rmi_fd.function_number);
+ if (!fops) {
+ dev_err(dev,
+ "%s: couldn't find support for F%02X.",
+ __func__, rmi_fd.function_number);
+ } else {
+ retval = fops->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 = fops;
+ 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
+ && fops->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
+ && fops->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 to register function "
+ " 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:
+ if (function_info)
+ kfree(function_info->function_device);
+ 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));
+}
+
+/* Show physical connection information as:
+ * prot tx_count tx_bytes tx_errors rx_count rx_bytes rx_errors attn
+ */
+static ssize_t rmi_sensor_phy_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rmi_sensor_device *sensor = dev_get_drvdata(dev);
+ struct rmi_phys_driver *rpd = sensor->driver->rpd;
+
+ return snprintf(buf, PAGE_SIZE, "%s %ld %ld %ld %ld %ld %ld %ld\n",
+ rpd->proto_name, rpd->tx_count, rpd->tx_bytes,
+ rpd->tx_errors, rpd->rx_count, rpd->rx_bytes,
+ rpd->rx_errors, rpd->attn_count);
+}
+
+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 */
+ retval = strict_strtoul(buf, 10, &val);
+ if (retval < 0)
+ return retval;
+
+
+ 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;
+}
+
+static ssize_t rmi_sensor_enabled_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 = sensor->sensordata;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->enabled);
+}
+
+static ssize_t rmi_sensor_enabled_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);
+ bool new_value;
+
+ if (sysfs_streq(buf, "0"))
+ new_value = false;
+ else if (sysfs_streq(buf, "1"))
+ new_value = true;
+ else
+ return -EINVAL;
+
+ if (new_value) {
+ retval = enable_sensor(sensor->driver);
+ if (retval) {
+ dev_err(dev, "Failed to ensable sensor, code=%d.\n",
+ retval);
+ return -EIO;
+ }
+ } else {
+ disable_sensor(sensor->driver);
+ }
+
+ 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
+ struct sensor_instance_data *instance_data;
+
+ 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;
+ }
+ instance_data = dev->sensordata;
+ /* let initial rmi_read_multiple/rmi_read happy */
+ instance_data->enabled = true;
+
+ 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 */
+
+ return 0;
+
+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);
+#if defined(CONFIG_SYNA_RMI_DEV)
+ if (rmi_char_dev_register(driver->rpd, driver->sensor_device))
+ pr_err("%s: error register char device", __func__);
+#endif /*CONFIG_SYNA_RMI_DEV*/
+ 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)
+{
+#if defined(CONFIG_SYNA_RMI_DEV)
+ struct rmi_sensor_device *rmisensordev = driver->sensor_device;
+#endif /* CONFIG_SYNA_RMI_DEV */
+ pr_debug("%s: Unregistering sensor driver.\n", __func__);
+
+#if defined(CONFIG_SYNA_RMI_DEV)
+ rmi_char_dev_unregister(rmisensordev->char_dev,
+ rmisensordev->rmi_char_device_class);
+#endif /*CONFIG_SYNA_RMI_DEV*/
+
+ /* 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");
--- /dev/null
+/**
+ *
+ * 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/cdev.h>
+#include <linux/mutex.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include <linux/rmi_platformdata.h>
+#include "rmi_dev.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);
+ /* 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 */
+#ifdef CONFIG_SYNA_RMI_DEV
+ /* pointer to attention char device and char device */
+ struct rmi_char_dev *char_dev;
+ struct class *rmi_char_device_class;
+#endif /*CONFIG_SYNA_RMI_DEV*/
+};
+
+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
--- /dev/null
+/**
+ *
+ * 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/irq.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 <linux/gpio.h>
+
+#include "rmi_spi.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;
+ int attn_polarity;
+ int attn_gpio;
+ 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;
+ instance_data->rpd.tx_count++;
+ instance_data->rpd.tx_bytes += n_tx;
+ }
+ if (n_rx) {
+ instance_data->rpd.rx_count++;
+ instance_data->rpd.rx_bytes += 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__);
+ /* nonzero means error */
+ status = -1;
+ goto error_exit;
+ } else
+ status = 0;
+ }
+ 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__);
+ /* nonzero means error */
+ status = -1;
+ goto error_exit;
+ } else
+ status = 0;
+ }
+ 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 {
+ if (n_tx)
+ instance_data->rpd.tx_errors++;
+ if (n_rx)
+ instance_data->rpd.rx_errors++;
+ 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);
+ instance_data->rpd.attn_count++;
+
+ 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);
+ return IRQ_HANDLED;
+}
+
+/* Specify the routine that will be called when attention is asserted.
+ */
+static void set_attn_handler (struct rmi_phys_driver *physdrvr,
+ void (*attention) (struct rmi_phys_driver *physdrvr))
+{
+ physdrvr->attention = attention;
+}
+
+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];
+ unsigned long irq_type = IRQ_TYPE_LEVEL_LOW;
+
+ 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.proto_name = "spi1";
+ 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.set_attn_handler = set_attn_handler;
+ 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);
+ goto error_exit;
+ }
+ }
+
+ 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 (sensordata->attn_gpio_number) {
+ instance_data->attn_polarity = sensordata->attn_polarity;
+ instance_data->attn_gpio = sensordata->attn_gpio_number;
+ instance_data->rpd.polling_required = false;
+ } 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.proto_name = "spi2";
+ 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) {
+ retval = request_irq(instance_data->irq, spi_attn_isr,
+ irq_type, dev_name(&spi->dev),
+ instance_data);
+ if (retval) {
+ dev_err(&spi->dev,
+ "%s: failed to obtain IRQ %d. Result: %d.",
+ __func__, instance_data->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->irq =
+ gpio_to_irq(sensordata->attn_gpio_number);
+
+ 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;
+ }
+ if ((irq_type & IRQ_TYPE_EDGE_BOTH) != 0)
+
+ if (instance_data->attn_gpio &&
+ gpio_get_value(
+ instance_data->attn_gpio
+ ) == instance_data->attn_polarity &&
+ instance_data->rpd.attention) {
+
+ disable_irq(instance_data->irq);
+ instance_data->rpd.attention(
+ &instance_data->rpd);
+ }
+ }
+
+ /* export GPIO for attention handling */
+
+#if defined(CONFIG_SYNA_RMI_DEV)
+ retval = gpio_export(instance_data->attn_gpio, false);
+ if (retval) {
+ dev_warn(&spi->dev, "%s: WARNING: Failed to "
+ "export ATTN gpio!.", __func__);
+ retval = 0;
+ } else {
+ retval = gpio_export_link(
+ &instance_data->rpd.sensor->
+ sensor_device->dev, "attn",
+ instance_data->attn_gpio);
+ if (retval) {
+ dev_warn(
+ &instance_data->rpd.sensor->
+ sensor_device->dev, "%s: WARNING: "
+ "Failed to symlink ATTN gpio!.",
+ __func__);
+ retval = 0;
+ } else {
+ dev_info(&instance_data->
+ rpd.sensor->sensor_device->dev,
+ "%s: Exported GPIO %d.",
+ __func__, instance_data->attn_gpio);
+ }
+ }
+#endif /* CONFIG_SYNA_RMI_DEV */
+ }
+
+ 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");
--- /dev/null
+/**
+ *
+ * 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 <linux/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 {
+ /* 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
--- /dev/null
+/**
+ *
+ * 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 <linux/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;
+
+ /* 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
--- /dev/null
+/**
+ *
+ * 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
+
+/* 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;
+
+};
+
+#define RMI_ATTN_ACTIVE_LOW 0
+#define RMI_ATTN_ACTIVE_HIGH 1
+
+/* 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);
+
+ /* The number of gpio for irq. Set to zero if polling is required. */
+ int attn_gpio_number;
+ int rst_gpio_number;
+ int attn_polarity;
+
+ /* 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;
+};
+
+#define USE_PAGESELECT /* for RMI_I2C */
+
+#endif