From 392334b78238456237a394504aca0a9d1cbd8703 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Thu, 22 Dec 2011 11:48:19 -0800 Subject: [PATCH] rmi4: new driver for synaptics touch controller s3202 BZ: 19819 Added RMI4 framework and driver from Synaptics that supports s3202 touch controller on CloverTrail Phone platform. Changes made to the original driver: 1. Fixed all checkpatch & compiling errors and warnings 2. add F1a function support for key reporting, s3202 doesn't have F19 for key reporting. Change-Id: I1fb608a7d7d9668f1779af5f27332b42a5ecc3f9 Signed-off-by: Andriy Naborskyy Signed-off-by: Leo Yan Signed-off-by: Hong Liu Reviewed-on: http://android.intel.com:8080/31120 Reviewed-by: Mai, Leonard Reviewed-by: Du, Alek Tested-by: Wang, Zhifeng Reviewed-by: buildbot Tested-by: buildbot --- arch/x86/platform/mrst/mrst.c | 59 +- drivers/input/touchscreen/Kconfig | 2 + drivers/input/touchscreen/Makefile | 4 +- drivers/input/touchscreen/rmi/Kconfig | 33 + drivers/input/touchscreen/rmi/Makefile | 7 + drivers/input/touchscreen/rmi/README | 6 + drivers/input/touchscreen/rmi/rmi.h | 72 ++ drivers/input/touchscreen/rmi/rmi_bus.c | 384 ++++++++ drivers/input/touchscreen/rmi/rmi_bus.h | 34 + drivers/input/touchscreen/rmi/rmi_dev.c | 463 +++++++++ drivers/input/touchscreen/rmi/rmi_dev.h | 65 ++ drivers/input/touchscreen/rmi/rmi_drvr.h | 109 +++ drivers/input/touchscreen/rmi/rmi_f01.c | 879 ++++++++++++++++++ drivers/input/touchscreen/rmi/rmi_f01.h | 124 +++ drivers/input/touchscreen/rmi/rmi_f05.c | 127 +++ drivers/input/touchscreen/rmi/rmi_f05.h | 42 + drivers/input/touchscreen/rmi/rmi_f11.c | 1256 +++++++++++++++++++++++++ drivers/input/touchscreen/rmi/rmi_f11.h | 110 +++ drivers/input/touchscreen/rmi/rmi_f19.c | 620 +++++++++++++ drivers/input/touchscreen/rmi/rmi_f19.h | 63 ++ drivers/input/touchscreen/rmi/rmi_f34.c | 558 +++++++++++ drivers/input/touchscreen/rmi/rmi_f34.h | 48 + drivers/input/touchscreen/rmi/rmi_f54.c | 666 +++++++++++++ drivers/input/touchscreen/rmi/rmi_f54.h | 76 ++ drivers/input/touchscreen/rmi/rmi_function.c | 312 +++++++ drivers/input/touchscreen/rmi/rmi_function.h | 190 ++++ drivers/input/touchscreen/rmi/rmi_i2c.c | 713 ++++++++++++++ drivers/input/touchscreen/rmi/rmi_sensor.c | 1289 ++++++++++++++++++++++++++ drivers/input/touchscreen/rmi/rmi_sensor.h | 135 +++ drivers/input/touchscreen/rmi/rmi_spi.c | 770 +++++++++++++++ drivers/input/touchscreen/rmi/rmi_spi.h | 104 +++ include/linux/rmi_i2c.h | 59 ++ include/linux/rmi_platformdata.h | 144 +++ 33 files changed, 9520 insertions(+), 3 deletions(-) create mode 100644 drivers/input/touchscreen/rmi/Kconfig create mode 100644 drivers/input/touchscreen/rmi/Makefile create mode 100644 drivers/input/touchscreen/rmi/README create mode 100644 drivers/input/touchscreen/rmi/rmi.h create mode 100644 drivers/input/touchscreen/rmi/rmi_bus.c create mode 100644 drivers/input/touchscreen/rmi/rmi_bus.h create mode 100644 drivers/input/touchscreen/rmi/rmi_dev.c create mode 100644 drivers/input/touchscreen/rmi/rmi_dev.h create mode 100644 drivers/input/touchscreen/rmi/rmi_drvr.h create mode 100644 drivers/input/touchscreen/rmi/rmi_f01.c create mode 100644 drivers/input/touchscreen/rmi/rmi_f01.h create mode 100644 drivers/input/touchscreen/rmi/rmi_f05.c create mode 100644 drivers/input/touchscreen/rmi/rmi_f05.h create mode 100644 drivers/input/touchscreen/rmi/rmi_f11.c create mode 100644 drivers/input/touchscreen/rmi/rmi_f11.h create mode 100644 drivers/input/touchscreen/rmi/rmi_f19.c create mode 100644 drivers/input/touchscreen/rmi/rmi_f19.h create mode 100644 drivers/input/touchscreen/rmi/rmi_f34.c create mode 100644 drivers/input/touchscreen/rmi/rmi_f34.h create mode 100644 drivers/input/touchscreen/rmi/rmi_f54.c create mode 100644 drivers/input/touchscreen/rmi/rmi_f54.h create mode 100644 drivers/input/touchscreen/rmi/rmi_function.c create mode 100644 drivers/input/touchscreen/rmi/rmi_function.h create mode 100644 drivers/input/touchscreen/rmi/rmi_i2c.c create mode 100644 drivers/input/touchscreen/rmi/rmi_sensor.c create mode 100644 drivers/input/touchscreen/rmi/rmi_sensor.h create mode 100644 drivers/input/touchscreen/rmi/rmi_spi.c create mode 100644 drivers/input/touchscreen/rmi/rmi_spi.h create mode 100644 include/linux/rmi_i2c.h create mode 100644 include/linux/rmi_platformdata.h diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 53eaaf9..2894c6c3 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -1000,7 +1001,7 @@ void max17042_i2c_reset_workaround(void) 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); @@ -1572,6 +1573,60 @@ void *atmel_mxt224_platform_data_init(void *info) 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}, @@ -1605,7 +1660,7 @@ static const struct devs_id __initconst device_ids[] = { {"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}, {}, }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 23ef376..98cff54 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -759,5 +759,7 @@ config TOUCHSCREEN_ATMEL_MXT224 help Say Y here if you have a mXT224 touchscreen If unsure, say N. + +source "drivers/input/touchscreen/rmi/Kconfig" endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 3933daa..980576b 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -63,4 +63,6 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o 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/ diff --git a/drivers/input/touchscreen/rmi/Kconfig b/drivers/input/touchscreen/rmi/Kconfig new file mode 100644 index 0000000..326389e --- /dev/null +++ b/drivers/input/touchscreen/rmi/Kconfig @@ -0,0 +1,33 @@ +# +# 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 diff --git a/drivers/input/touchscreen/rmi/Makefile b/drivers/input/touchscreen/rmi/Makefile new file mode 100644 index 0000000..221c9ee --- /dev/null +++ b/drivers/input/touchscreen/rmi/Makefile @@ -0,0 +1,7 @@ +# +# 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 diff --git a/drivers/input/touchscreen/rmi/README b/drivers/input/touchscreen/rmi/README new file mode 100644 index 0000000..b31ef6a --- /dev/null +++ b/drivers/input/touchscreen/rmi/README @@ -0,0 +1,6 @@ +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. diff --git a/drivers/input/touchscreen/rmi/rmi.h b/drivers/input/touchscreen/rmi/rmi.h new file mode 100644 index 0000000..7357819 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi.h @@ -0,0 +1,72 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) Header File. + * Copyright (c) 2007 - 2011, Synaptics Incorporated + * + * + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + *############################################################################# + */ + +#if !defined(_RMI_H) +#define _RMI_H + +/* RMI4 Protocol Support + */ + + +/* Every function on an RMI device is identified by a one byte function number. + * The hexadecimal representation of this byte is used in the function name. + * For example, the function identified by the byte 0x11 is referred to as + * F11 (or sometimes FN11). In the extremely improbable event that F11 is no + * longer identified by 0x11, though, we provide these handy #defines. + */ +#define RMI_F01_INDEX 0x01 +#define RMI_F05_INDEX 0x05 +#define RMI_F11_INDEX 0x11 +#define RMI_F19_INDEX 0x19 +#define RMI_F34_INDEX 0x34 +#define RMI_F54_INDEX 0x54 + +/* This byte has information about the communications protocol. See the RMI4 + * specification for details of what exactly is there. + */ +#define RMI_PROTOCOL_VERSION_ADDRESS 0xA0FD + +/* For each function present on the RMI device, we need to get the RMI4 Function + * Descriptor info from the Page Descriptor Table. This will give us the + * addresses for Query, Command, Control, Data and the Source Count (number + * of sources for this function) and the function id. + */ +struct rmi_function_descriptor { + unsigned char query_base_addr; + unsigned char command_base_addr; + unsigned char control_base_addr; + unsigned char data_base_addr; + unsigned char interrupt_source_count; + unsigned char function_number; +}; + +/* The product descriptor table starts here, and continues till we get + * a function ID of 0x00 or 0xFF. + */ +#define RMI_PDT_START_ADDRESS 0x00E9 + +#define RMI_IS_VALID_FUNCTION_ID(id) (id != 0x00 && id != 0xFF) + +#endif diff --git a/drivers/input/touchscreen/rmi/rmi_bus.c b/drivers/input/touchscreen/rmi/rmi_bus.c new file mode 100644 index 0000000..d74a0c7 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_bus.c @@ -0,0 +1,384 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); diff --git a/drivers/input/touchscreen/rmi/rmi_bus.h b/drivers/input/touchscreen/rmi/rmi_bus.h new file mode 100644 index 0000000..780a2f5 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_bus.h @@ -0,0 +1,34 @@ +/* + * + * Synaptics Register Mapped Interface (RMI4) - RMI Bus Module Header. + * Copyright (C) 2007 - 2010, Synaptics Incorporated + * + */ +/* + * + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + *############################################################################# + */ + +#if !defined(_RMI_BUS_H) +#define _RMI_BUS_H + +#include "rmi_sensor.h" + +int rmi_bus_register_sensor_driver(struct rmi_sensor_driver *sensor_driver); +void rmi_bus_unregister_sensor_driver(struct rmi_sensor_driver *sensor_driver); + +#endif diff --git a/drivers/input/touchscreen/rmi/rmi_dev.c b/drivers/input/touchscreen/rmi/rmi_dev.c new file mode 100644 index 0000000..47a4f86 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_dev.c @@ -0,0 +1,463 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#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"); diff --git a/drivers/input/touchscreen/rmi/rmi_dev.h b/drivers/input/touchscreen/rmi/rmi_dev.h new file mode 100644 index 0000000..9a28034 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_dev.h @@ -0,0 +1,65 @@ +/* + * + * 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 +#include +#include +#include + + +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*/ diff --git a/drivers/input/touchscreen/rmi/rmi_drvr.h b/drivers/input/touchscreen/rmi/rmi_drvr.h new file mode 100644 index 0000000..20783c9 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_drvr.h @@ -0,0 +1,109 @@ +/** + * + * 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 +#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 diff --git a/drivers/input/touchscreen/rmi/rmi_f01.c b/drivers/input/touchscreen/rmi/rmi_f01.c new file mode 100644 index 0000000..56e9e73 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f01.c @@ -0,0 +1,879 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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< 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)) + ); + } +} diff --git a/drivers/input/touchscreen/rmi/rmi_f01.h b/drivers/input/touchscreen/rmi/rmi_f01.h new file mode 100644 index 0000000..8db462a --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f01.h @@ -0,0 +1,124 @@ +/** + * + * 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 diff --git a/drivers/input/touchscreen/rmi/rmi_f05.c b/drivers/input/touchscreen/rmi/rmi_f05.c new file mode 100644 index 0000000..8f2808a --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f05.c @@ -0,0 +1,127 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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); diff --git a/drivers/input/touchscreen/rmi/rmi_f05.h b/drivers/input/touchscreen/rmi/rmi_f05.h new file mode 100644 index 0000000..10e4df4 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f05.h @@ -0,0 +1,42 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) Function $11 header. + * Copyright (c) 2007 - 2010, Synaptics Incorporated + * + * For every RMI4 function that has a data source - like 2D sensors, + * buttons, LEDs, GPIOs, etc. - the user will create a new rmi_function_xx.c + * file and add these functions to perform the config(), init(), report() + * and detect() functionality. The function pointers are then srored under + * the RMI function info and these functions will automatically be called by + * the global config(), init(), report() and detect() functions that will + * loop through all data sources and call the data sources functions using + * these functions pointed to by the function ptrs. + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + *############################################################################# + */ + +#if !defined(_RMI_F05_H) +#define _RMI_F05_H + +void FN_05_inthandler(struct rmi_function_info *rmifninfo, + unsigned int asserted_IRQs); +int FN_05_config(struct rmi_function_info *rmifninfo); +int FN_05_init(struct rmi_function_device *function_device); +int FN_05_detect(struct rmi_function_info *rmifninfo); +/* No attention function for F05 */ +#endif diff --git a/drivers/input/touchscreen/rmi/rmi_f11.c b/drivers/input/touchscreen/rmi/rmi_f11.c new file mode 100644 index 0000000..5bdee0b --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f11.c @@ -0,0 +1,1256 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/input/touchscreen/rmi/rmi_f11.h b/drivers/input/touchscreen/rmi/rmi_f11.h new file mode 100644 index 0000000..6616084 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f11.h @@ -0,0 +1,110 @@ +/** + * + * 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 diff --git a/drivers/input/touchscreen/rmi/rmi_f19.c b/drivers/input/touchscreen/rmi/rmi_f19.c new file mode 100644 index 0000000..ccd4a05 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f19.c @@ -0,0 +1,620 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/input/touchscreen/rmi/rmi_f19.h b/drivers/input/touchscreen/rmi/rmi_f19.h new file mode 100644 index 0000000..b5964fe --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f19.h @@ -0,0 +1,63 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) Function $11 header. + * Copyright (c) 2007 - 2010, Synaptics Incorporated + * + * For every RMI4 function that has a data source - like 2D sensors, + * buttons, LEDs, GPIOs, etc. - the user will create a new rmi_function_xx.c + * file and add these functions to perform the config(), init(), report() + * and detect() functionality. The function pointers are then srored under + * the RMI function info and these functions will automatically be called by + * the global config(), init(), report() and detect() functions that will + * loop through all data sources and call the data sources functions using + * these functions pointed to by the function ptrs. + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + *############################################################################# + */ + +#if !defined(_RMI_F19_H) +#define _RMI_F19_H + +/* This is the data read from the F19 query registers. + */ +struct rmi_F19_query { + bool has_hysteresis_threshold; + bool has_sensitivity_adjust; + bool configurable; + unsigned char button_count; +}; + +struct rmi_F19_control { + unsigned char button_usage; + unsigned char filter_mode; + unsigned char *interrupt_enable_registers; + unsigned char *single_button_control; + unsigned char *sensor_map; + unsigned char *single_button_sensitivity; + unsigned char global_sensitivity_adjustment; + unsigned char global_hysteresis_threshold; +}; + + +void FN_19_inthandler(struct rmi_function_info *rmifninfo, + unsigned int asserted_IRQs); +int FN_19_config(struct rmi_function_info *rmifninfo); +int FN_19_init(struct rmi_function_device *function_device); +int FN_19_detect(struct rmi_function_info *rmifninfo); +/* No attention function for Fn $19 */ +#endif diff --git a/drivers/input/touchscreen/rmi/rmi_f34.c b/drivers/input/touchscreen/rmi/rmi_f34.c new file mode 100644 index 0000000..55c317e1 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f34.c @@ -0,0 +1,558 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/drivers/input/touchscreen/rmi/rmi_f34.h b/drivers/input/touchscreen/rmi/rmi_f34.h new file mode 100644 index 0000000..c9e8b52 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f34.h @@ -0,0 +1,48 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) Function $34 header. + * Copyright (c) 2007 - 2011, Synaptics Incorporated + * + * There is only one function $34 for each RMI4 sensor. This will be + * the function that is used to reflash the firmware and get the + * boot loader address and the boot image block size. + * + * + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + *############################################################################# + */ + +#if !defined(_RMI_F34_H) +#define _RMI_F34_H + +/* define fn $34 commands */ +#define WRITE_FW_BLOCK 2 +#define ERASE_ALL 3 +#define READ_CONFIG_BLOCK 5 +#define WRITE_CONFIG_BLOCK 6 +#define ERASE_CONFIG 7 +#define ENABLE_FLASH_PROG 15 + +void FN_34_inthandler(struct rmi_function_info *rmifninfo, + unsigned int asserted_IRQs); +int FN_34_config(struct rmi_function_info *rmifninfo); +int FN_34_init(struct rmi_function_device *function_device); +int FN_34_detect(struct rmi_function_info *rmifninfo); +void FN_34_attention(struct rmi_function_info *rmifninfo); + +#endif diff --git a/drivers/input/touchscreen/rmi/rmi_f54.c b/drivers/input/touchscreen/rmi/rmi_f54.c new file mode 100644 index 0000000..246683d --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f54.c @@ -0,0 +1,666 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/input/touchscreen/rmi/rmi_f54.h b/drivers/input/touchscreen/rmi/rmi_f54.h new file mode 100644 index 0000000..8ad43c9 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_f54.h @@ -0,0 +1,76 @@ +/** + * + * 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 diff --git a/drivers/input/touchscreen/rmi/rmi_function.c b/drivers/input/touchscreen/rmi/rmi_function.c new file mode 100644 index 0000000..a9737f3 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_function.c @@ -0,0 +1,312 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); diff --git a/drivers/input/touchscreen/rmi/rmi_function.h b/drivers/input/touchscreen/rmi/rmi_function.h new file mode 100644 index 0000000..18e4277 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_function.h @@ -0,0 +1,190 @@ +/** + * + * 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 +#include +/* 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 diff --git a/drivers/input/touchscreen/rmi/rmi_i2c.c b/drivers/input/touchscreen/rmi/rmi_i2c.c new file mode 100644 index 0000000..ec25b18 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_i2c.c @@ -0,0 +1,713 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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"); diff --git a/drivers/input/touchscreen/rmi/rmi_sensor.c b/drivers/input/touchscreen/rmi/rmi_sensor.c new file mode 100644 index 0000000..09917e6 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_sensor.c @@ -0,0 +1,1289 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); diff --git a/drivers/input/touchscreen/rmi/rmi_sensor.h b/drivers/input/touchscreen/rmi/rmi_sensor.h new file mode 100644 index 0000000..0aca071 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_sensor.h @@ -0,0 +1,135 @@ +/** + * + * 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 +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include +#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 diff --git a/drivers/input/touchscreen/rmi/rmi_spi.c b/drivers/input/touchscreen/rmi/rmi_spi.c new file mode 100644 index 0000000..148842b --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_spi.c @@ -0,0 +1,770 @@ +/** + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); diff --git a/drivers/input/touchscreen/rmi/rmi_spi.h b/drivers/input/touchscreen/rmi/rmi_spi.h new file mode 100644 index 0000000..54775d2 --- /dev/null +++ b/drivers/input/touchscreen/rmi/rmi_spi.h @@ -0,0 +1,104 @@ +/** + * + * 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 + +#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 diff --git a/include/linux/rmi_i2c.h b/include/linux/rmi_i2c.h new file mode 100644 index 0000000..061c757 --- /dev/null +++ b/include/linux/rmi_i2c.h @@ -0,0 +1,59 @@ +/** + * + * 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 + +/* 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 diff --git a/include/linux/rmi_platformdata.h b/include/linux/rmi_platformdata.h new file mode 100644 index 0000000..c3eb7d3 --- /dev/null +++ b/include/linux/rmi_platformdata.h @@ -0,0 +1,144 @@ +/** + * + * 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 -- 2.7.4